| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/parser.h" | 5 #include "vm/parser.h" |
| 6 | 6 |
| 7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
| 8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
| 9 #include "vm/ast_transformer.h" | 9 #include "vm/ast_transformer.h" |
| 10 #include "vm/bootstrap.h" | 10 #include "vm/bootstrap.h" |
| (...skipping 5955 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5966 stack_trace_param.token_pos = Scanner::kNoSourcePos; | 5966 stack_trace_param.token_pos = Scanner::kNoSourcePos; |
| 5967 stack_trace_param.type = &dynamic_type; | 5967 stack_trace_param.type = &dynamic_type; |
| 5968 stack_trace_param.name = &Symbols::StackTraceParameter(); | 5968 stack_trace_param.name = &Symbols::StackTraceParameter(); |
| 5969 | 5969 |
| 5970 AddCatchParamsToScope( | 5970 AddCatchParamsToScope( |
| 5971 &exception_param, &stack_trace_param, current_block_->scope); | 5971 &exception_param, &stack_trace_param, current_block_->scope); |
| 5972 | 5972 |
| 5973 LocalVariable* context_var = current_block_->scope->LookupVariable( | 5973 LocalVariable* context_var = current_block_->scope->LookupVariable( |
| 5974 Symbols::SavedTryContextVar(), false); | 5974 Symbols::SavedTryContextVar(), false); |
| 5975 ASSERT(context_var != NULL); | 5975 ASSERT(context_var != NULL); |
| 5976 |
| 5976 LocalVariable* exception_var = current_block_->scope->LookupVariable( | 5977 LocalVariable* exception_var = current_block_->scope->LookupVariable( |
| 5977 Symbols::ExceptionVar(), false); | 5978 Symbols::ExceptionVar(), false); |
| 5979 ASSERT(exception_var != NULL); |
| 5978 if (exception_param.var != NULL) { | 5980 if (exception_param.var != NULL) { |
| 5979 // Generate code to load the exception object (:exception_var) into | 5981 // Generate code to load the exception object (:exception_var) into |
| 5980 // the exception variable specified in this block. | 5982 // the exception variable specified in this block. |
| 5981 ASSERT(exception_var != NULL); | |
| 5982 current_block_->statements->Add(new(Z) StoreLocalNode( | 5983 current_block_->statements->Add(new(Z) StoreLocalNode( |
| 5983 Scanner::kNoSourcePos, | 5984 Scanner::kNoSourcePos, |
| 5984 exception_param.var, | 5985 exception_param.var, |
| 5985 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var))); | 5986 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var))); |
| 5986 } | 5987 } |
| 5988 |
| 5987 LocalVariable* stack_trace_var = | 5989 LocalVariable* stack_trace_var = |
| 5988 current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false); | 5990 current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false); |
| 5991 ASSERT(stack_trace_var != NULL); |
| 5989 if (stack_trace_param.var != NULL) { | 5992 if (stack_trace_param.var != NULL) { |
| 5990 // A stack trace variable is specified in this block, so generate code | 5993 // A stack trace variable is specified in this block, so generate code |
| 5991 // to load the stack trace object (:stack_trace_var) into the stack | 5994 // to load the stack trace object (:stack_trace_var) into the stack |
| 5992 // trace variable specified in this block. | 5995 // trace variable specified in this block. |
| 5993 ASSERT(stack_trace_var != NULL); | |
| 5994 current_block_->statements->Add(new(Z) StoreLocalNode( | 5996 current_block_->statements->Add(new(Z) StoreLocalNode( |
| 5995 Scanner::kNoSourcePos, | 5997 Scanner::kNoSourcePos, |
| 5996 stack_trace_param.var, | 5998 stack_trace_param.var, |
| 5997 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var))); | 5999 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var))); |
| 5998 } | 6000 } |
| 5999 | 6001 |
| 6002 AddSavedExceptionAndStacktraceToScope( |
| 6003 exception_var, stack_trace_var, current_block_->scope); |
| 6004 |
| 6000 ASSERT(try_blocks_list_ != NULL); | 6005 ASSERT(try_blocks_list_ != NULL); |
| 6001 ASSERT(innermost_function().IsAsyncClosure() || | 6006 ASSERT(innermost_function().IsAsyncClosure() || |
| 6002 innermost_function().IsAsyncFunction()); | 6007 innermost_function().IsAsyncFunction()); |
| 6003 if ((try_blocks_list_->outer_try_block() != NULL) && | 6008 if ((try_blocks_list_->outer_try_block() != NULL) && |
| 6004 (try_blocks_list_->outer_try_block()->try_block() | 6009 (try_blocks_list_->outer_try_block()->try_block() |
| 6005 ->scope->function_level() == | 6010 ->scope->function_level() == |
| 6006 current_block_->scope->function_level())) { | 6011 current_block_->scope->function_level())) { |
| 6007 // We need to unchain three scope levels: catch clause, catch | 6012 // We need to unchain three scope levels: catch clause, catch |
| 6008 // parameters, and the general try block. | 6013 // parameters, and the general try block. |
| 6009 RestoreSavedTryContext( | 6014 RestoreSavedTryContext( |
| (...skipping 2186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8196 exception_param->var = var; | 8201 exception_param->var = var; |
| 8197 } | 8202 } |
| 8198 if (stack_trace_param->name != NULL) { | 8203 if (stack_trace_param->name != NULL) { |
| 8199 LocalVariable* var = new(Z) LocalVariable( | 8204 LocalVariable* var = new(Z) LocalVariable( |
| 8200 stack_trace_param->token_pos, | 8205 stack_trace_param->token_pos, |
| 8201 *stack_trace_param->name, | 8206 *stack_trace_param->name, |
| 8202 *stack_trace_param->type); | 8207 *stack_trace_param->type); |
| 8203 var->set_is_final(); | 8208 var->set_is_final(); |
| 8204 bool added_to_scope = scope->AddVariable(var); | 8209 bool added_to_scope = scope->AddVariable(var); |
| 8205 if (!added_to_scope) { | 8210 if (!added_to_scope) { |
| 8211 // The name of the exception param is reused for the stack trace param. |
| 8206 ReportError(stack_trace_param->token_pos, | 8212 ReportError(stack_trace_param->token_pos, |
| 8207 "name '%s' already exists in scope", | 8213 "name '%s' already exists in scope", |
| 8208 stack_trace_param->name->ToCString()); | 8214 stack_trace_param->name->ToCString()); |
| 8209 } | 8215 } |
| 8210 stack_trace_param->var = var; | 8216 stack_trace_param->var = var; |
| 8211 } | 8217 } |
| 8212 } | 8218 } |
| 8213 | 8219 |
| 8214 | 8220 |
| 8221 // Populate local scope of the catch block with the saved exception and saved |
| 8222 // stack trace. |
| 8223 void Parser::AddSavedExceptionAndStacktraceToScope( |
| 8224 LocalVariable* exception_var, |
| 8225 LocalVariable* stack_trace_var, |
| 8226 LocalScope* scope) { |
| 8227 ASSERT(innermost_function().IsAsyncClosure() || |
| 8228 innermost_function().IsAsyncFunction() || |
| 8229 innermost_function().IsSyncGenClosure() || |
| 8230 innermost_function().IsSyncGenerator()); |
| 8231 // Add :saved_exception_var and :saved_stack_trace_var to scope. |
| 8232 // They will automatically get captured. |
| 8233 LocalVariable* saved_exception_var = new (Z) LocalVariable( |
| 8234 Scanner::kNoSourcePos, |
| 8235 Symbols::SavedExceptionVar(), |
| 8236 Type::ZoneHandle(Z, Type::DynamicType())); |
| 8237 saved_exception_var->set_is_final(); |
| 8238 scope->AddVariable(saved_exception_var); |
| 8239 LocalVariable* saved_stack_trace_var = new (Z) LocalVariable( |
| 8240 Scanner::kNoSourcePos, |
| 8241 Symbols::SavedStackTraceVar(), |
| 8242 Type::ZoneHandle(Z, Type::DynamicType())); |
| 8243 saved_exception_var->set_is_final(); |
| 8244 scope->AddVariable(saved_stack_trace_var); |
| 8245 |
| 8246 // Generate code to load the exception object (:exception_var) into |
| 8247 // the saved exception variable (:saved_exception_var) used to rethrow. |
| 8248 saved_exception_var = current_block_->scope->LookupVariable( |
| 8249 Symbols::SavedExceptionVar(), false); |
| 8250 ASSERT(saved_exception_var != NULL); |
| 8251 ASSERT(exception_var != NULL); |
| 8252 current_block_->statements->Add(new(Z) StoreLocalNode( |
| 8253 Scanner::kNoSourcePos, |
| 8254 saved_exception_var, |
| 8255 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var))); |
| 8256 |
| 8257 // Generate code to load the stack trace object (:stack_trace_var) into |
| 8258 // the saved stacktrace variable (:saved_stack_trace_var) used to rethrow. |
| 8259 saved_stack_trace_var = current_block_->scope->LookupVariable( |
| 8260 Symbols::SavedStackTraceVar(), false); |
| 8261 ASSERT(saved_stack_trace_var != NULL); |
| 8262 ASSERT(stack_trace_var != NULL); |
| 8263 current_block_->statements->Add(new(Z) StoreLocalNode( |
| 8264 Scanner::kNoSourcePos, |
| 8265 saved_stack_trace_var, |
| 8266 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var))); |
| 8267 } |
| 8268 |
| 8269 |
| 8215 SequenceNode* Parser::ParseFinallyBlock() { | 8270 SequenceNode* Parser::ParseFinallyBlock() { |
| 8216 TRACE_PARSER("ParseFinallyBlock"); | 8271 TRACE_PARSER("ParseFinallyBlock"); |
| 8217 OpenBlock(); | 8272 OpenBlock(); |
| 8218 ExpectToken(Token::kLBRACE); | 8273 ExpectToken(Token::kLBRACE); |
| 8219 | 8274 |
| 8220 // In case of async closures we need to restore the saved try index of an | 8275 // In case of async closures we need to restore the saved try index of an |
| 8221 // outer try block (if it exists). The current try block has already been | 8276 // outer try block (if it exists). The current try block has already been |
| 8222 // removed from the stack of try blocks. | 8277 // removed from the stack of try blocks. |
| 8223 if ((innermost_function().IsAsyncClosure() || | 8278 if ((innermost_function().IsAsyncClosure() || |
| 8224 innermost_function().IsAsyncFunction() || | 8279 innermost_function().IsAsyncFunction() || |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8338 stack_trace_param.token_pos = TokenPos(); | 8393 stack_trace_param.token_pos = TokenPos(); |
| 8339 stack_trace_param.name = ExpectIdentifier("identifier expected"); | 8394 stack_trace_param.name = ExpectIdentifier("identifier expected"); |
| 8340 } | 8395 } |
| 8341 ExpectToken(Token::kRPAREN); | 8396 ExpectToken(Token::kRPAREN); |
| 8342 } | 8397 } |
| 8343 | 8398 |
| 8344 // Create a block containing the catch clause parameters and the | 8399 // Create a block containing the catch clause parameters and the |
| 8345 // following code: | 8400 // following code: |
| 8346 // 1) Store exception object and stack trace object into user-defined | 8401 // 1) Store exception object and stack trace object into user-defined |
| 8347 // variables (as needed). | 8402 // variables (as needed). |
| 8348 // 2) Nested block with source code from catch clause block. | 8403 // 2) In async code, save exception object and stack trace object into |
| 8404 // captured :saved_exception_var and :saved_stack_trace_var. |
| 8405 // 3) Nested block with source code from catch clause block. |
| 8349 OpenBlock(); | 8406 OpenBlock(); |
| 8350 AddCatchParamsToScope(&exception_param, &stack_trace_param, | 8407 AddCatchParamsToScope(&exception_param, &stack_trace_param, |
| 8351 current_block_->scope); | 8408 current_block_->scope); |
| 8352 | 8409 |
| 8353 if (exception_param.var != NULL) { | 8410 if (exception_param.var != NULL) { |
| 8354 // Generate code to load the exception object (:exception_var) into | 8411 // Generate code to load the exception object (:exception_var) into |
| 8355 // the exception variable specified in this block. | 8412 // the exception variable specified in this block. |
| 8356 ASSERT(exception_var != NULL); | 8413 ASSERT(exception_var != NULL); |
| 8357 current_block_->statements->Add(new(Z) StoreLocalNode( | 8414 current_block_->statements->Add(new(Z) StoreLocalNode( |
| 8358 catch_pos, exception_param.var, new(Z) LoadLocalNode( | 8415 catch_pos, exception_param.var, new(Z) LoadLocalNode( |
| (...skipping 27 matching lines...) Expand all Loading... |
| 8386 current_block_->scope->function_level())) { | 8443 current_block_->scope->function_level())) { |
| 8387 // We need to unchain three scope levels: catch clause, catch | 8444 // We need to unchain three scope levels: catch clause, catch |
| 8388 // parameters, and the general try block. | 8445 // parameters, and the general try block. |
| 8389 RestoreSavedTryContext( | 8446 RestoreSavedTryContext( |
| 8390 current_block_->scope->parent()->parent()->parent(), | 8447 current_block_->scope->parent()->parent()->parent(), |
| 8391 try_blocks_list_->outer_try_block()->try_index(), | 8448 try_blocks_list_->outer_try_block()->try_index(), |
| 8392 current_block_->statements); | 8449 current_block_->statements); |
| 8393 } else { | 8450 } else { |
| 8394 parsed_function()->reset_saved_try_ctx_vars(); | 8451 parsed_function()->reset_saved_try_ctx_vars(); |
| 8395 } | 8452 } |
| 8453 AddSavedExceptionAndStacktraceToScope( |
| 8454 exception_var, stack_trace_var, current_block_->scope); |
| 8396 } | 8455 } |
| 8397 | 8456 |
| 8398 current_block_->statements->Add(ParseNestedStatement(false, NULL)); | 8457 current_block_->statements->Add(ParseNestedStatement(false, NULL)); |
| 8399 catch_blocks.Add(CloseBlock()); | 8458 catch_blocks.Add(CloseBlock()); |
| 8400 | 8459 |
| 8401 const bool is_bad_type = | 8460 const bool is_bad_type = |
| 8402 exception_param.type->IsMalformed() || | 8461 exception_param.type->IsMalformed() || |
| 8403 exception_param.type->IsMalbounded(); | 8462 exception_param.type->IsMalbounded(); |
| 8404 if (exception_param.type->IsDynamicType() || is_bad_type) { | 8463 if (exception_param.type->IsDynamicType() || is_bad_type) { |
| 8405 // There is no exception type or else it is malformed or malbounded. | 8464 // There is no exception type or else it is malformed or malbounded. |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8530 current_block_->statements->Add(new(Z) StoreLocalNode( | 8589 current_block_->statements->Add(new(Z) StoreLocalNode( |
| 8531 Scanner::kNoSourcePos, | 8590 Scanner::kNoSourcePos, |
| 8532 async_saved_try_ctx, | 8591 async_saved_try_ctx, |
| 8533 new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context))); | 8592 new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context))); |
| 8534 parsed_function()->set_saved_try_ctx(saved_try_context); | 8593 parsed_function()->set_saved_try_ctx(saved_try_context); |
| 8535 parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name); | 8594 parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name); |
| 8536 } | 8595 } |
| 8537 | 8596 |
| 8538 | 8597 |
| 8539 // Restore the currently relevant :saved_try_context_var on the stack | 8598 // Restore the currently relevant :saved_try_context_var on the stack |
| 8540 // from the captured :async_saved_try_cts_var. | 8599 // from the captured :async_saved_try_ctx_var_. |
| 8541 // * Try blocks: Set the context variable for this try block. | 8600 // * Try blocks: Set the context variable for this try block. |
| 8542 // * Catch/finally blocks: Set the context variable for any outer try block (if | 8601 // * Catch/finally blocks: Set the context variable for any outer try block (if |
| 8543 // existent). | 8602 // existent). |
| 8544 // | 8603 // |
| 8545 // Also save the captured variable and the stack variable to be able to set | 8604 // Also save the captured variable and the stack variable to be able to set |
| 8546 // it after a function continues execution (await). | 8605 // it after a function continues execution (await). |
| 8547 void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope, | 8606 void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope, |
| 8548 int16_t try_index, | 8607 int16_t try_index, |
| 8549 SequenceNode* target) { | 8608 SequenceNode* target) { |
| 8550 LocalVariable* saved_try_ctx = saved_try_context_scope->LookupVariable( | 8609 LocalVariable* saved_try_ctx = saved_try_context_scope->LookupVariable( |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8924 // Empty statement, nothing to do. | 8983 // Empty statement, nothing to do. |
| 8925 ConsumeToken(); | 8984 ConsumeToken(); |
| 8926 } else if (token == Token::kRETHROW) { | 8985 } else if (token == Token::kRETHROW) { |
| 8927 // Rethrow of current exception. | 8986 // Rethrow of current exception. |
| 8928 ConsumeToken(); | 8987 ConsumeToken(); |
| 8929 ExpectSemicolon(); | 8988 ExpectSemicolon(); |
| 8930 // Check if it is ok to do a rethrow. | 8989 // Check if it is ok to do a rethrow. |
| 8931 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { | 8990 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { |
| 8932 ReportError(statement_pos, "rethrow of an exception is not valid here"); | 8991 ReportError(statement_pos, "rethrow of an exception is not valid here"); |
| 8933 } | 8992 } |
| 8934 // The exception and stack trace variables are bound in the block | 8993 |
| 8935 // containing the try. | 8994 // If in async code, use :saved_exception_var and :saved_stack_trace_var |
| 8936 LocalScope* scope = try_blocks_list_->try_block()->scope->parent(); | 8995 // instead of :exception_var and :stack_trace_var. |
| 8937 ASSERT(scope != NULL); | 8996 LocalVariable* excp_var; |
| 8938 LocalVariable* excp_var = | 8997 LocalVariable* trace_var; |
| 8939 scope->LocalLookupVariable(Symbols::ExceptionVar()); | 8998 if (innermost_function().IsAsyncClosure() || |
| 8999 innermost_function().IsAsyncFunction() || |
| 9000 innermost_function().IsSyncGenClosure() || |
| 9001 innermost_function().IsSyncGenerator()) { |
| 9002 // The saved exception and stack trace variables are bound in the block |
| 9003 // containing the catch. So start looking in the current scope. |
| 9004 LocalScope* scope = current_block_->scope; |
| 9005 excp_var = scope->LookupVariable(Symbols::SavedExceptionVar(), false); |
| 9006 trace_var = scope->LookupVariable(Symbols::SavedStackTraceVar(), false); |
| 9007 } else { |
| 9008 // The exception and stack trace variables are bound in the block |
| 9009 // containing the try. Look in the try scope directly. |
| 9010 LocalScope* scope = try_blocks_list_->try_block()->scope->parent(); |
| 9011 ASSERT(scope != NULL); |
| 9012 excp_var = scope->LocalLookupVariable(Symbols::ExceptionVar()); |
| 9013 trace_var = scope->LocalLookupVariable(Symbols::StackTraceVar()); |
| 9014 } |
| 8940 ASSERT(excp_var != NULL); | 9015 ASSERT(excp_var != NULL); |
| 8941 LocalVariable* trace_var = | |
| 8942 scope->LocalLookupVariable(Symbols::StackTraceVar()); | |
| 8943 ASSERT(trace_var != NULL); | 9016 ASSERT(trace_var != NULL); |
| 9017 |
| 8944 statement = new(Z) ThrowNode( | 9018 statement = new(Z) ThrowNode( |
| 8945 statement_pos, | 9019 statement_pos, |
| 8946 new(Z) LoadLocalNode(statement_pos, excp_var), | 9020 new(Z) LoadLocalNode(statement_pos, excp_var), |
| 8947 new(Z) LoadLocalNode(statement_pos, trace_var)); | 9021 new(Z) LoadLocalNode(statement_pos, trace_var)); |
| 8948 } else { | 9022 } else { |
| 8949 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); | 9023 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); |
| 8950 ExpectSemicolon(); | 9024 ExpectSemicolon(); |
| 8951 } | 9025 } |
| 8952 return statement; | 9026 return statement; |
| 8953 } | 9027 } |
| (...skipping 3614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12568 void Parser::SkipQualIdent() { | 12642 void Parser::SkipQualIdent() { |
| 12569 ASSERT(IsIdentifier()); | 12643 ASSERT(IsIdentifier()); |
| 12570 ConsumeToken(); | 12644 ConsumeToken(); |
| 12571 if (CurrentToken() == Token::kPERIOD) { | 12645 if (CurrentToken() == Token::kPERIOD) { |
| 12572 ConsumeToken(); // Consume the kPERIOD token. | 12646 ConsumeToken(); // Consume the kPERIOD token. |
| 12573 ExpectIdentifier("identifier expected after '.'"); | 12647 ExpectIdentifier("identifier expected after '.'"); |
| 12574 } | 12648 } |
| 12575 } | 12649 } |
| 12576 | 12650 |
| 12577 } // namespace dart | 12651 } // namespace dart |
| OLD | NEW |