Chromium Code Reviews| 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 |
|
hausner
2013/11/12 19:21:45
Please keep unrelated changes separate. The includ
Florian Schneider
2013/11/13 10:25:42
I think we all agree changing includes to include
| |
| 7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
| 8 #include "vm/bigint_operations.h" | 8 #include "platform/utils.h" |
| 9 #include "vm/bootstrap.h" | 9 #include "vm/bootstrap.h" |
| 10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
| 11 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
| 12 #include "vm/compiler_stats.h" | 12 #include "vm/compiler_stats.h" |
| 13 #include "vm/dart_api_impl.h" | 13 #include "vm/dart_api_impl.h" |
| 14 #include "vm/dart_entry.h" | 14 #include "vm/dart_entry.h" |
| 15 #include "vm/flags.h" | 15 #include "vm/flags.h" |
| 16 #include "vm/growable_array.h" | 16 #include "vm/growable_array.h" |
| 17 #include "vm/handles.h" | |
| 18 #include "vm/heap.h" | |
| 19 #include "vm/isolate.h" | |
| 17 #include "vm/longjump.h" | 20 #include "vm/longjump.h" |
| 21 #include "vm/native_arguments.h" | |
| 18 #include "vm/native_entry.h" | 22 #include "vm/native_entry.h" |
| 19 #include "vm/object.h" | 23 #include "vm/object.h" |
| 20 #include "vm/object_store.h" | 24 #include "vm/object_store.h" |
| 25 #include "vm/os.h" | |
| 21 #include "vm/resolver.h" | 26 #include "vm/resolver.h" |
| 27 #include "vm/scanner.h" | |
| 22 #include "vm/scopes.h" | 28 #include "vm/scopes.h" |
| 23 #include "vm/stack_frame.h" | 29 #include "vm/stack_frame.h" |
| 24 #include "vm/symbols.h" | 30 #include "vm/symbols.h" |
| 31 #include "vm/timer.h" | |
| 32 #include "vm/zone.h" | |
| 25 | 33 |
| 26 namespace dart { | 34 namespace dart { |
| 27 | 35 |
| 28 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); | 36 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); |
| 29 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); | 37 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); |
| 30 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); | 38 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); |
| 31 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); | 39 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); |
| 32 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); | 40 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); |
| 33 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef"); | 41 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef"); |
| 34 DECLARE_FLAG(bool, error_on_bad_type); | 42 DECLARE_FLAG(bool, error_on_bad_type); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 187 | 195 |
| 188 // Class which describes an inlined finally block which is used to generate | 196 // Class which describes an inlined finally block which is used to generate |
| 189 // inlined code for the finally blocks when there is an exit from a try | 197 // inlined code for the finally blocks when there is an exit from a try |
| 190 // block using 'return', 'break' or 'continue'. | 198 // block using 'return', 'break' or 'continue'. |
| 191 class Parser::TryBlocks : public ZoneAllocated { | 199 class Parser::TryBlocks : public ZoneAllocated { |
| 192 public: | 200 public: |
| 193 TryBlocks(Block* try_block, TryBlocks* outer_try_block, intptr_t try_index) | 201 TryBlocks(Block* try_block, TryBlocks* outer_try_block, intptr_t try_index) |
| 194 : try_block_(try_block), | 202 : try_block_(try_block), |
| 195 inlined_finally_nodes_(), | 203 inlined_finally_nodes_(), |
| 196 outer_try_block_(outer_try_block), | 204 outer_try_block_(outer_try_block), |
| 197 try_index_(try_index) { } | 205 try_index_(try_index), |
| 206 inside_catch_(false) { } | |
| 198 | 207 |
| 199 TryBlocks* outer_try_block() const { return outer_try_block_; } | 208 TryBlocks* outer_try_block() const { return outer_try_block_; } |
| 200 Block* try_block() const { return try_block_; } | 209 Block* try_block() const { return try_block_; } |
| 201 intptr_t try_index() const { return try_index_; } | 210 intptr_t try_index() const { return try_index_; } |
| 211 bool inside_catch() const { return inside_catch_; } | |
| 212 void enter_catch() { inside_catch_ = true; } | |
| 202 | 213 |
| 203 void AddNodeForFinallyInlining(AstNode* node); | 214 void AddNodeForFinallyInlining(AstNode* node); |
| 204 AstNode* GetNodeToInlineFinally(int index) { | 215 AstNode* GetNodeToInlineFinally(int index) { |
| 205 if (0 <= index && index < inlined_finally_nodes_.length()) { | 216 if (0 <= index && index < inlined_finally_nodes_.length()) { |
| 206 return inlined_finally_nodes_[index]; | 217 return inlined_finally_nodes_[index]; |
| 207 } | 218 } |
| 208 return NULL; | 219 return NULL; |
| 209 } | 220 } |
| 210 | 221 |
| 211 private: | 222 private: |
| 212 Block* try_block_; | 223 Block* try_block_; |
| 213 GrowableArray<AstNode*> inlined_finally_nodes_; | 224 GrowableArray<AstNode*> inlined_finally_nodes_; |
| 214 TryBlocks* outer_try_block_; | 225 TryBlocks* outer_try_block_; |
| 215 const intptr_t try_index_; | 226 const intptr_t try_index_; |
| 227 bool inside_catch_; | |
| 216 | 228 |
| 217 DISALLOW_COPY_AND_ASSIGN(TryBlocks); | 229 DISALLOW_COPY_AND_ASSIGN(TryBlocks); |
| 218 }; | 230 }; |
| 219 | 231 |
| 220 | 232 |
| 221 void Parser::TryBlocks::AddNodeForFinallyInlining(AstNode* node) { | 233 void Parser::TryBlocks::AddNodeForFinallyInlining(AstNode* node) { |
| 222 inlined_finally_nodes_.Add(node); | 234 inlined_finally_nodes_.Add(node); |
| 223 } | 235 } |
| 224 | 236 |
| 225 | 237 |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1065 } | 1077 } |
| 1066 LocalVariable* catch_excp_var = | 1078 LocalVariable* catch_excp_var = |
| 1067 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); | 1079 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); |
| 1068 if (catch_excp_var == NULL) { | 1080 if (catch_excp_var == NULL) { |
| 1069 catch_excp_var = new LocalVariable(token_pos, | 1081 catch_excp_var = new LocalVariable(token_pos, |
| 1070 Symbols::ExceptionVar(), | 1082 Symbols::ExceptionVar(), |
| 1071 Type::ZoneHandle(Type::DynamicType())); | 1083 Type::ZoneHandle(Type::DynamicType())); |
| 1072 current_block_->scope->AddVariable(catch_excp_var); | 1084 current_block_->scope->AddVariable(catch_excp_var); |
| 1073 } | 1085 } |
| 1074 LocalVariable* catch_trace_var = | 1086 LocalVariable* catch_trace_var = |
| 1075 current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar()); | 1087 current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar()); |
| 1076 if (catch_trace_var == NULL) { | 1088 if (catch_trace_var == NULL) { |
| 1077 catch_trace_var = new LocalVariable(token_pos, | 1089 catch_trace_var = new LocalVariable(token_pos, |
| 1078 Symbols::StacktraceVar(), | 1090 Symbols::StackTraceVar(), |
| 1079 Type::ZoneHandle(Type::DynamicType())); | 1091 Type::ZoneHandle(Type::DynamicType())); |
| 1080 current_block_->scope->AddVariable(catch_trace_var); | 1092 current_block_->scope->AddVariable(catch_trace_var); |
| 1081 } | 1093 } |
| 1082 | 1094 |
| 1083 OpenBlock(); // Start try block. | 1095 OpenBlock(); // Start try block. |
| 1084 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); | 1096 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); |
| 1085 const Field& field = Field::ZoneHandle(func.saved_static_field()); | 1097 const Field& field = Field::ZoneHandle(func.saved_static_field()); |
| 1086 ASSERT(!field.is_const()); | 1098 ASSERT(!field.is_const()); |
| 1087 StoreStaticFieldNode* store = new StoreStaticFieldNode(field.token_pos(), | 1099 StoreStaticFieldNode* store = new StoreStaticFieldNode(field.token_pos(), |
| 1088 field, | 1100 field, |
| 1089 expr); | 1101 expr); |
| 1090 current_block_->statements->Add(store); | 1102 current_block_->statements->Add(store); |
| 1091 SequenceNode* try_block = CloseBlock(); // End try block. | 1103 SequenceNode* try_block = CloseBlock(); // End try block. |
| 1092 | 1104 |
| 1093 OpenBlock(); // Start catch handler list. | 1105 OpenBlock(); // Start catch handler list. |
| 1094 SourceLabel* end_catch_label = | |
| 1095 SourceLabel::New(token_pos, NULL, SourceLabel::kCatch); | |
| 1096 current_block_->scope->AddLabel(end_catch_label); | |
| 1097 | |
| 1098 OpenBlock(); // Start catch clause. | 1106 OpenBlock(); // Start catch clause. |
| 1099 AstNode* compare_transition_sentinel = new ComparisonNode( | 1107 AstNode* compare_transition_sentinel = new ComparisonNode( |
| 1100 token_pos, | 1108 token_pos, |
| 1101 Token::kEQ_STRICT, | 1109 Token::kEQ_STRICT, |
| 1102 new LoadStaticFieldNode(token_pos, field), | 1110 new LoadStaticFieldNode(token_pos, field), |
| 1103 new LiteralNode(field.token_pos(), Object::transition_sentinel())); | 1111 new LiteralNode(field.token_pos(), Object::transition_sentinel())); |
| 1104 | 1112 |
| 1105 SequenceNode* store_null = new SequenceNode(token_pos, NULL); | 1113 SequenceNode* store_null = new SequenceNode(token_pos, NULL); |
| 1106 store_null->Add(new StoreStaticFieldNode( | 1114 store_null->Add(new StoreStaticFieldNode( |
| 1107 field.token_pos(), | 1115 field.token_pos(), |
| 1108 field, | 1116 field, |
| 1109 new LiteralNode(token_pos, Instance::ZoneHandle()))); | 1117 new LiteralNode(token_pos, Instance::ZoneHandle()))); |
| 1110 AstNode* transition_sentinel_check = | 1118 AstNode* transition_sentinel_check = |
| 1111 new IfNode(token_pos, compare_transition_sentinel, store_null, NULL); | 1119 new IfNode(token_pos, compare_transition_sentinel, store_null, NULL); |
| 1112 current_block_->statements->Add(transition_sentinel_check); | 1120 current_block_->statements->Add(transition_sentinel_check); |
| 1113 | 1121 |
| 1114 current_block_->statements->Add( | 1122 current_block_->statements->Add( |
| 1115 new ThrowNode(token_pos, | 1123 new ThrowNode(token_pos, |
| 1116 new LoadLocalNode(token_pos, catch_excp_var), | 1124 new LoadLocalNode(token_pos, catch_excp_var), |
| 1117 new LoadLocalNode(token_pos, catch_trace_var))); | 1125 new LoadLocalNode(token_pos, catch_trace_var))); |
| 1118 current_block_->statements->Add( | |
| 1119 new JumpNode(token_pos, Token::kCONTINUE, end_catch_label)); | |
| 1120 SequenceNode* catch_clause = CloseBlock(); // End catch clause. | 1126 SequenceNode* catch_clause = CloseBlock(); // End catch clause. |
| 1121 | 1127 |
| 1122 current_block_->statements->Add(catch_clause); | 1128 current_block_->statements->Add(catch_clause); |
| 1123 SequenceNode* catch_handler_list = CloseBlock(); // End catch handler list. | 1129 SequenceNode* catch_handler_list = CloseBlock(); // End catch handler list. |
| 1124 CatchClauseNode* catch_block = | 1130 CatchClauseNode* catch_block = |
| 1125 new CatchClauseNode(token_pos, | 1131 new CatchClauseNode(token_pos, |
| 1126 catch_handler_list, | 1132 catch_handler_list, |
| 1127 Array::ZoneHandle(Object::empty_array().raw()), | 1133 Array::ZoneHandle(Object::empty_array().raw()), |
| 1128 context_var, | 1134 context_var, |
| 1129 catch_excp_var, | 1135 catch_excp_var, |
| 1130 catch_trace_var, | 1136 catch_trace_var, |
| 1131 CatchClauseNode::kInvalidTryIndex, | 1137 CatchClauseNode::kInvalidTryIndex, |
| 1132 false); // No stack trace needed. | 1138 false); // No stack trace needed. |
| 1133 | 1139 |
| 1134 AstNode* try_catch_node = new TryCatchNode(token_pos, | 1140 AstNode* try_catch_node = new TryCatchNode(token_pos, |
| 1135 try_block, | 1141 try_block, |
| 1136 end_catch_label, | |
| 1137 context_var, | 1142 context_var, |
| 1138 catch_block, | 1143 catch_block, |
| 1139 NULL, // No finally block. | 1144 NULL, // No finally block. |
| 1140 AllocateTryIndex()); | 1145 AllocateTryIndex()); |
| 1141 current_block_->statements->Add(try_catch_node); | 1146 current_block_->statements->Add(try_catch_node); |
| 1142 return CloseBlock(); | 1147 return CloseBlock(); |
| 1143 } | 1148 } |
| 1144 | 1149 |
| 1145 | 1150 |
| 1146 // Create AstNodes for an implicit instance getter method: | 1151 // Create AstNodes for an implicit instance getter method: |
| (...skipping 5491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6638 condition = InsertClosureCallNodes(condition); | 6643 condition = InsertClosureCallNodes(condition); |
| 6639 condition = new UnaryOpNode(condition_pos, Token::kNOT, condition); | 6644 condition = new UnaryOpNode(condition_pos, Token::kNOT, condition); |
| 6640 AstNode* assert_throw = MakeAssertCall(condition_pos, condition_end); | 6645 AstNode* assert_throw = MakeAssertCall(condition_pos, condition_end); |
| 6641 return new IfNode(condition_pos, | 6646 return new IfNode(condition_pos, |
| 6642 condition, | 6647 condition, |
| 6643 NodeAsSequenceNode(condition_pos, assert_throw, NULL), | 6648 NodeAsSequenceNode(condition_pos, assert_throw, NULL), |
| 6644 NULL); | 6649 NULL); |
| 6645 } | 6650 } |
| 6646 | 6651 |
| 6647 | 6652 |
| 6648 struct CatchParamDesc { | 6653 struct CatchParameter { |
|
hausner
2013/11/12 19:21:45
Please do not rename CatchParamDesc. I understand
Kevin Millikin (Google)
2013/11/13 13:47:02
I changed it back, but it's not *just* a matter of
| |
| 6649 CatchParamDesc() | 6654 CatchParameter() |
| 6650 : token_pos(0), type(NULL), var(NULL) { } | 6655 : token_pos(0), type(NULL), name(NULL), var(NULL) { } |
| 6651 intptr_t token_pos; | 6656 intptr_t token_pos; |
| 6652 const AbstractType* type; | 6657 const AbstractType* type; |
| 6653 const String* var; | 6658 const String* name; |
| 6659 LocalVariable* var; | |
| 6654 }; | 6660 }; |
| 6655 | 6661 |
| 6656 | 6662 |
| 6657 // Populate local scope of the catch block with the catch parameters. | 6663 // Populate local scope of the catch block with the catch parameters. |
| 6658 void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, | 6664 void Parser::AddCatchParamsToScope(CatchParameter* exception_param, |
| 6659 const CatchParamDesc& stack_trace_param, | 6665 CatchParameter* stack_trace_param, |
| 6660 LocalScope* scope) { | 6666 LocalScope* scope) { |
| 6661 if (exception_param.var != NULL) { | 6667 if (exception_param->name != NULL) { |
| 6662 LocalVariable* var = new LocalVariable(exception_param.token_pos, | 6668 LocalVariable* var = new LocalVariable(exception_param->token_pos, |
| 6663 *exception_param.var, | 6669 *exception_param->name, |
| 6664 *exception_param.type); | 6670 *exception_param->type); |
| 6665 var->set_is_final(); | 6671 var->set_is_final(); |
| 6666 bool added_to_scope = scope->AddVariable(var); | 6672 bool added_to_scope = scope->AddVariable(var); |
| 6667 ASSERT(added_to_scope); | 6673 ASSERT(added_to_scope); |
| 6674 exception_param->var = var; | |
| 6668 } | 6675 } |
| 6669 if (stack_trace_param.var != NULL) { | 6676 if (stack_trace_param->name != NULL) { |
| 6670 LocalVariable* var = new LocalVariable(TokenPos(), | 6677 LocalVariable* var = new LocalVariable(stack_trace_param->token_pos, |
| 6671 *stack_trace_param.var, | 6678 *stack_trace_param->name, |
| 6672 *stack_trace_param.type); | 6679 *stack_trace_param->type); |
| 6673 var->set_is_final(); | 6680 var->set_is_final(); |
| 6674 bool added_to_scope = scope->AddVariable(var); | 6681 bool added_to_scope = scope->AddVariable(var); |
| 6675 if (!added_to_scope) { | 6682 if (!added_to_scope) { |
| 6676 ErrorMsg(stack_trace_param.token_pos, | 6683 ErrorMsg(stack_trace_param->token_pos, |
| 6677 "name '%s' already exists in scope", | 6684 "name '%s' already exists in scope", |
| 6678 stack_trace_param.var->ToCString()); | 6685 stack_trace_param->name->ToCString()); |
| 6679 } | 6686 } |
| 6687 stack_trace_param->var = var; | |
| 6680 } | 6688 } |
| 6681 } | 6689 } |
| 6682 | 6690 |
| 6683 | 6691 |
| 6684 SequenceNode* Parser::ParseFinallyBlock() { | 6692 SequenceNode* Parser::ParseFinallyBlock() { |
| 6685 TRACE_PARSER("ParseFinallyBlock"); | 6693 TRACE_PARSER("ParseFinallyBlock"); |
| 6686 OpenBlock(); | 6694 OpenBlock(); |
| 6687 ExpectToken(Token::kLBRACE); | 6695 ExpectToken(Token::kLBRACE); |
| 6688 ParseStatementSequence(); | 6696 ParseStatementSequence(); |
| 6689 ExpectToken(Token::kRBRACE); | 6697 ExpectToken(Token::kRBRACE); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6738 InlinedFinallyNode* finally_node) { | 6746 InlinedFinallyNode* finally_node) { |
| 6739 if (node->IsReturnNode()) { | 6747 if (node->IsReturnNode()) { |
| 6740 node->AsReturnNode()->AddInlinedFinallyNode(finally_node); | 6748 node->AsReturnNode()->AddInlinedFinallyNode(finally_node); |
| 6741 } else { | 6749 } else { |
| 6742 ASSERT(node->IsJumpNode()); | 6750 ASSERT(node->IsJumpNode()); |
| 6743 node->AsJumpNode()->AddInlinedFinallyNode(finally_node); | 6751 node->AsJumpNode()->AddInlinedFinallyNode(finally_node); |
| 6744 } | 6752 } |
| 6745 } | 6753 } |
| 6746 | 6754 |
| 6747 | 6755 |
| 6748 AstNode* Parser::ParseTryStatement(String* label_name) { | 6756 SequenceNode* Parser::ParseCatchClauses( |
| 6749 TRACE_PARSER("ParseTryStatement"); | 6757 intptr_t handler_pos, |
| 6750 | 6758 LocalVariable* exception_var, |
| 6751 // We create three stack slots for exceptions here: | 6759 LocalVariable* stack_trace_var, |
| 6752 // ':saved_try_context_var' - Used to save the context before start of the try | 6760 const GrowableObjectArray& handler_types, |
| 6753 // block. The context register is restored from | 6761 bool* needs_stack_trace) { |
| 6754 // this slot before processing the catch block | 6762 // All catch blocks are merged into an if-then-else sequence of the |
| 6755 // handler. | 6763 // different types specified using the 'is' operator. While parsing |
| 6756 // ':exception_var' - Used to save the current exception object that was | 6764 // record the type tests (either a ComparisonNode or else the LiteralNode |
| 6757 // thrown. | 6765 // true for a generic catch) and the catch bodies in a pair of parallel |
| 6758 // ':stacktrace_var' - Used to save the current stack trace object into which | 6766 // lists. Afterward, construct the nested if-then-else. |
| 6759 // the stack trace was copied into when an exception was | 6767 GrowableArray<AstNode*> type_tests; |
| 6760 // thrown. | 6768 GrowableArray<SequenceNode*> catch_blocks; |
| 6761 // :exception_var and :stacktrace_var get set with the exception object | 6769 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) { |
| 6762 // and the stacktrace object when an exception is thrown. | 6770 // Open a block that contains the if or an unconditional body. It's |
| 6763 // These three implicit variables can never be captured variables. | 6771 // closed in the loop that builds the if-then-else nest. |
| 6764 LocalVariable* context_var = | |
| 6765 current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); | |
| 6766 if (context_var == NULL) { | |
| 6767 context_var = new LocalVariable(TokenPos(), | |
| 6768 Symbols::SavedTryContextVar(), | |
| 6769 Type::ZoneHandle(Type::DynamicType())); | |
| 6770 current_block_->scope->AddVariable(context_var); | |
| 6771 } | |
| 6772 LocalVariable* catch_excp_var = | |
| 6773 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); | |
| 6774 if (catch_excp_var == NULL) { | |
| 6775 catch_excp_var = new LocalVariable(TokenPos(), | |
| 6776 Symbols::ExceptionVar(), | |
| 6777 Type::ZoneHandle(Type::DynamicType())); | |
| 6778 current_block_->scope->AddVariable(catch_excp_var); | |
| 6779 } | |
| 6780 LocalVariable* catch_trace_var = | |
| 6781 current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar()); | |
| 6782 if (catch_trace_var == NULL) { | |
| 6783 catch_trace_var = new LocalVariable(TokenPos(), | |
| 6784 Symbols::StacktraceVar(), | |
| 6785 Type::ZoneHandle(Type::DynamicType())); | |
| 6786 current_block_->scope->AddVariable(catch_trace_var); | |
| 6787 } | |
| 6788 | |
| 6789 const intptr_t try_pos = TokenPos(); | |
| 6790 ConsumeToken(); // Consume the 'try'. | |
| 6791 | |
| 6792 SourceLabel* try_label = NULL; | |
| 6793 if (label_name != NULL) { | |
| 6794 try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement); | |
| 6795 OpenBlock(); | 6772 OpenBlock(); |
| 6796 current_block_->scope->AddLabel(try_label); | |
| 6797 } | |
| 6798 | |
| 6799 // Now parse the 'try' block. | |
| 6800 OpenBlock(); | |
| 6801 PushTryBlock(current_block_); | |
| 6802 ExpectToken(Token::kLBRACE); | |
| 6803 ParseStatementSequence(); | |
| 6804 ExpectToken(Token::kRBRACE); | |
| 6805 SequenceNode* try_block = CloseBlock(); | |
| 6806 | |
| 6807 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") && | |
| 6808 (CurrentToken() != Token::kFINALLY)) { | |
| 6809 ErrorMsg("catch or finally clause expected"); | |
| 6810 } | |
| 6811 | |
| 6812 // Now create a label for the end of catch block processing so that we can | |
| 6813 // jump over the catch block code after executing the try block. | |
| 6814 SourceLabel* end_catch_label = | |
| 6815 SourceLabel::New(TokenPos(), NULL, SourceLabel::kCatch); | |
| 6816 | |
| 6817 // Now parse the 'catch' blocks if any and merge all of them into | |
| 6818 // an if-then sequence of the different types specified using the 'is' | |
| 6819 // operator. | |
| 6820 bool generic_catch_seen = false; | |
| 6821 const intptr_t handler_pos = TokenPos(); | |
| 6822 OpenBlock(); // Start the catch block sequence. | |
| 6823 current_block_->scope->AddLabel(end_catch_label); | |
| 6824 const GrowableObjectArray& handler_types = | |
| 6825 GrowableObjectArray::Handle(GrowableObjectArray::New()); | |
| 6826 bool needs_stacktrace = false; | |
| 6827 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) { | |
| 6828 const intptr_t catch_pos = TokenPos(); | 6773 const intptr_t catch_pos = TokenPos(); |
| 6829 CatchParamDesc exception_param; | 6774 CatchParameter exception_param; |
| 6830 CatchParamDesc stack_trace_param; | 6775 CatchParameter stack_trace_param; |
| 6831 if (IsLiteral("on")) { | 6776 if (IsLiteral("on")) { |
| 6832 ConsumeToken(); | 6777 ConsumeToken(); |
| 6833 exception_param.type = &AbstractType::ZoneHandle( | 6778 exception_param.type = &AbstractType::ZoneHandle( |
| 6834 ParseType(ClassFinalizer::kCanonicalize)); | 6779 ParseType(ClassFinalizer::kCanonicalize)); |
| 6835 } else { | 6780 } else { |
| 6836 exception_param.type = &AbstractType::ZoneHandle(Type::DynamicType()); | 6781 exception_param.type = &AbstractType::ZoneHandle(Type::DynamicType()); |
| 6837 } | 6782 } |
| 6838 if (CurrentToken() == Token::kCATCH) { | 6783 if (CurrentToken() == Token::kCATCH) { |
| 6839 ConsumeToken(); // Consume the 'catch'. | 6784 ConsumeToken(); // Consume the 'catch'. |
| 6840 ExpectToken(Token::kLPAREN); | 6785 ExpectToken(Token::kLPAREN); |
| 6841 exception_param.token_pos = TokenPos(); | 6786 exception_param.token_pos = TokenPos(); |
| 6842 exception_param.var = ExpectIdentifier("identifier expected"); | 6787 exception_param.name = ExpectIdentifier("identifier expected"); |
| 6843 if (CurrentToken() == Token::kCOMMA) { | 6788 if (CurrentToken() == Token::kCOMMA) { |
| 6844 ConsumeToken(); | 6789 ConsumeToken(); |
| 6845 // TODO(hausner): Make implicit type be StackTrace, not dynamic. | 6790 // TODO(hausner): Make implicit type be StackTrace, not dynamic. |
| 6846 stack_trace_param.type = | 6791 stack_trace_param.type = |
| 6847 &AbstractType::ZoneHandle(Type::DynamicType()); | 6792 &AbstractType::ZoneHandle(Type::DynamicType()); |
| 6848 stack_trace_param.token_pos = TokenPos(); | 6793 stack_trace_param.token_pos = TokenPos(); |
| 6849 stack_trace_param.var = ExpectIdentifier("identifier expected"); | 6794 stack_trace_param.name = ExpectIdentifier("identifier expected"); |
| 6850 } | 6795 } |
| 6851 ExpectToken(Token::kRPAREN); | 6796 ExpectToken(Token::kRPAREN); |
| 6852 } | 6797 } |
| 6853 | 6798 |
| 6854 // Create a block containing the catch clause parameters and | 6799 // Create a block containing the catch clause parameters and the |
| 6855 // the following code: | 6800 // following code: |
| 6856 // 1) Store exception object and stack trace object into user-defined | 6801 // 1) Store exception object and stack trace object into user-defined |
| 6857 // variables (as needed). | 6802 // variables (as needed). |
| 6858 // 2) Nested block with source code from catch clause block. | 6803 // 2) Nested block with source code from catch clause block. |
| 6859 // 3) Unconditional JUMP to the end of the try block. | |
| 6860 OpenBlock(); | 6804 OpenBlock(); |
|
hausner
2013/11/12 01:12:10
You are nesting 3 blocks now per case clause: one
hausner
2013/11/12 19:21:45
Ok, I get it now.
| |
| 6861 AddCatchParamsToScope(exception_param, | 6805 AddCatchParamsToScope(&exception_param, &stack_trace_param, |
| 6862 stack_trace_param, | |
| 6863 current_block_->scope); | 6806 current_block_->scope); |
| 6864 | 6807 |
| 6865 if (exception_param.var != NULL) { | 6808 if (exception_param.var != NULL) { |
| 6866 // Generate code to load the exception object (:exception_var) into | 6809 // Generate code to load the exception object (:exception_var) into |
| 6867 // the exception variable specified in this block. | 6810 // the exception variable specified in this block. |
| 6868 LocalVariable* var = LookupLocalScope(*exception_param.var); | 6811 ASSERT(exception_var != NULL); |
| 6869 ASSERT(var != NULL); | |
| 6870 ASSERT(catch_excp_var != NULL); | |
| 6871 current_block_->statements->Add( | 6812 current_block_->statements->Add( |
| 6872 new StoreLocalNode(catch_pos, var, | 6813 new StoreLocalNode(catch_pos, exception_param.var, |
| 6873 new LoadLocalNode(catch_pos, catch_excp_var))); | 6814 new LoadLocalNode(catch_pos, exception_var))); |
| 6874 } | 6815 } |
| 6875 if (stack_trace_param.var != NULL) { | 6816 if (stack_trace_param.var != NULL) { |
| 6876 // A stack trace variable is specified in this block, so generate code | 6817 // A stack trace variable is specified in this block, so generate code |
| 6877 // to load the stack trace object (:stacktrace_var) into the stack trace | 6818 // to load the stack trace object (:stack_trace_var) into the stack |
| 6878 // variable specified in this block. | 6819 // trace variable specified in this block. |
| 6879 needs_stacktrace = true; | 6820 *needs_stack_trace = true; |
| 6880 ArgumentListNode* no_args = new ArgumentListNode(catch_pos); | 6821 ArgumentListNode* no_args = new ArgumentListNode(catch_pos); |
| 6881 LocalVariable* trace = LookupLocalScope(*stack_trace_param.var); | 6822 ASSERT(stack_trace_var != NULL); |
| 6882 ASSERT(catch_trace_var != NULL); | |
| 6883 current_block_->statements->Add( | 6823 current_block_->statements->Add( |
| 6884 new StoreLocalNode(catch_pos, trace, | 6824 new StoreLocalNode(catch_pos, stack_trace_param.var, |
| 6885 new LoadLocalNode(catch_pos, catch_trace_var))); | 6825 new LoadLocalNode(catch_pos, stack_trace_var))); |
| 6886 current_block_->statements->Add( | 6826 current_block_->statements->Add( |
| 6887 new InstanceCallNode( | 6827 new InstanceCallNode( |
| 6888 catch_pos, | 6828 catch_pos, |
| 6889 new LoadLocalNode(catch_pos, trace), | 6829 new LoadLocalNode(catch_pos, stack_trace_param.var), |
| 6890 Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()), | 6830 Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()), |
| 6891 no_args)); | 6831 no_args)); |
| 6892 } | 6832 } |
| 6893 | 6833 |
| 6894 // Add nested block with user-defined code. | 6834 // Add nested block with user-defined code. This blocks allows |
| 6835 // declarations in the body to shadow the catch parameters. | |
| 6895 CheckToken(Token::kLBRACE); | 6836 CheckToken(Token::kLBRACE); |
| 6896 current_block_->statements->Add(ParseNestedStatement(false, NULL)); | 6837 current_block_->statements->Add(ParseNestedStatement(false, NULL)); |
| 6897 | 6838 catch_blocks.Add(CloseBlock()); |
| 6898 // Add unconditional jump to end of catch clause list. | 6839 |
| 6899 current_block_->statements->Add( | 6840 const bool is_bad_type = |
| 6900 new JumpNode(catch_pos, Token::kCONTINUE, end_catch_label)); | 6841 exception_param.type->IsMalformed() || |
| 6901 | 6842 exception_param.type->IsMalbounded(); |
| 6902 SequenceNode* catch_clause = CloseBlock(); | 6843 if (exception_param.type->IsDynamicType() || is_bad_type) { |
| 6903 | 6844 // There is no exception type or else it is malformed or malbounded. |
| 6904 const bool is_bad_type = exception_param.type->IsMalformed() || | 6845 // In the first cast, unconditionally execute the catch body. In the |
|
hausner
2013/11/12 01:12:10
case
Kevin Millikin (Google)
2013/11/13 13:47:02
Done.
| |
| 6905 exception_param.type->IsMalbounded(); | 6846 // second case, unconditionally throw. |
| 6906 if (!is_bad_type && !exception_param.type->IsDynamicType()) { | 6847 type_tests.Add(new LiteralNode(catch_pos, Bool::True())); |
| 6907 // Has a type specification that is not malformed or malbounded. | 6848 if (is_bad_type) { |
| 6908 // Now form an 'if type check' to guard the catch handler code. | 6849 // Replace the body with one that throws. |
| 6850 SequenceNode* block = new SequenceNode(catch_pos, NULL); | |
| 6851 block->Add(ThrowTypeError(catch_pos, *exception_param.type)); | |
| 6852 catch_blocks.Last() = block; | |
| 6853 } | |
| 6854 // This catch clause will handle all exceptions. We can safely forget | |
| 6855 // all previous catch clause types. | |
| 6856 handler_types.SetLength(0); | |
|
hausner
2013/11/12 19:21:45
Remember here with a bool variable that we've seen
Kevin Millikin (Google)
2013/11/13 13:47:02
Done.
| |
| 6857 handler_types.Add(*exception_param.type); | |
| 6858 } else { | |
| 6859 // Has a type specification that is not malformed or malbounded. Now | |
| 6860 // form an 'if type check' to guard the catch handler code. | |
| 6909 if (!exception_param.type->IsInstantiated() && | 6861 if (!exception_param.type->IsInstantiated() && |
| 6910 (current_block_->scope->function_level() > 0)) { | 6862 (current_block_->scope->function_level() > 0)) { |
| 6911 // Make sure that the instantiator is captured. | 6863 // Make sure that the instantiator is captured. |
| 6912 CaptureInstantiator(); | 6864 CaptureInstantiator(); |
| 6913 } | 6865 } |
| 6914 TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type); | 6866 TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type); |
| 6915 AstNode* exception_var = new LoadLocalNode(catch_pos, catch_excp_var); | 6867 AstNode* exception_value = new LoadLocalNode(catch_pos, exception_var); |
| 6916 if (!exception_type->type().IsInstantiated()) { | 6868 if (!exception_type->type().IsInstantiated()) { |
| 6917 EnsureExpressionTemp(); | 6869 EnsureExpressionTemp(); |
| 6918 } | 6870 } |
| 6919 AstNode* type_cond_expr = new ComparisonNode( | 6871 type_tests.Add(new ComparisonNode(catch_pos, Token::kIS, exception_value, |
| 6920 catch_pos, Token::kIS, exception_var, exception_type); | 6872 exception_type)); |
| 6921 current_block_->statements->Add( | 6873 |
| 6922 new IfNode(catch_pos, type_cond_expr, catch_clause, NULL)); | 6874 // Do not add uninstantiated types (e.g. type parameter T or generic |
| 6923 | 6875 // type List<T>), since the debugger won't be able to instantiate it |
| 6924 // Do not add uninstantiated types (e.g. type parameter T or | 6876 // when walking the stack. |
| 6925 // generic type List<T>), since the debugger won't be able to | 6877 // |
| 6926 // instantiate it when walking the stack. | 6878 // This means that the debugger is not able to determine whether an |
| 6927 // This means that the debugger is not able to determine whether | 6879 // exception is caught if the catch clause uses generic types. It |
| 6928 // an exception is caught if the catch clause uses generic types. | 6880 // will report the exception as uncaught when in fact it might be |
| 6929 // It will report the exception as uncaught when in fact it might | 6881 // caught and handled when we unwind the stack. |
| 6930 // be caught and handled when we unwind the stack. | |
| 6931 if (exception_param.type->IsInstantiated()) { | 6882 if (exception_param.type->IsInstantiated()) { |
|
hausner
2013/11/12 19:21:45
Also guard this with the boolean flag so that no m
Kevin Millikin (Google)
2013/11/13 13:47:02
Done.
| |
| 6932 handler_types.Add(*exception_param.type); | 6883 handler_types.Add(*exception_param.type); |
| 6933 } | 6884 } |
| 6934 } else { | 6885 } |
| 6935 if (is_bad_type) { | 6886 |
| 6936 current_block_->statements->Add(ThrowTypeError(catch_pos, | 6887 ASSERT(type_tests.length() == catch_blocks.length()); |
| 6937 *exception_param.type)); | 6888 } |
| 6938 // We still add the dead code below to satisfy the code generator. | 6889 |
| 6939 } | 6890 // Build the if/then/else nest from the inside out. Keep the AST simple |
| 6940 // No exception type exists in the catch clause so execute the | 6891 // for the case of a single generic catch clause. |
| 6941 // catch handler code unconditionally. | 6892 SequenceNode* current = NULL; |
| 6942 current_block_->statements->Add(catch_clause); | 6893 if (type_tests.is_empty() || !type_tests.Last()->IsLiteralNode()) { |
|
hausner
2013/11/12 19:21:45
You can use the "catch all seen" flag to determine
| |
| 6943 generic_catch_seen = true; | 6894 // Create a clause body that rethrows the exception if there are no |
| 6944 // This catch clause will handle all exceptions. We can safely forget | 6895 // catch clauses or if the last clause is not entered unconditionally. |
| 6945 // all previous catch clause types. | 6896 // In the second case, this body is the last (innermost) else block. |
| 6946 handler_types.SetLength(0); | 6897 current = new SequenceNode(handler_pos, NULL); |
| 6947 handler_types.Add(*exception_param.type); | 6898 current->Add( |
| 6948 } | 6899 new ThrowNode(handler_pos, |
| 6949 } | 6900 new LoadLocalNode(handler_pos, exception_var), |
| 6950 | 6901 new LoadLocalNode(handler_pos, stack_trace_var))); |
| 6951 SequenceNode* catch_handler_list = CloseBlock(); | 6902 } else { |
| 6903 ASSERT(type_tests.Last()->AsLiteralNode()->literal().raw() == | |
| 6904 Bool::True().raw()); | |
| 6905 // The last body is entered unconditionally. Start building the | |
| 6906 // if/then/else nest with that body as the innermost else block. | |
| 6907 // Note that it is nested inside an extra block which we opened | |
| 6908 // before we knew the body was entered unconditionally. | |
| 6909 type_tests.RemoveLast(); | |
| 6910 current_block_->statements->Add(catch_blocks.RemoveLast()); | |
| 6911 current = CloseBlock(); | |
| 6912 } | |
| 6913 | |
| 6914 while (!type_tests.is_empty()) { | |
| 6915 AstNode* type_test = type_tests.RemoveLast(); | |
| 6916 SequenceNode* catch_block = catch_blocks.RemoveLast(); | |
| 6917 current_block_->statements->Add( | |
| 6918 new IfNode(type_test->token_pos(), type_test, catch_block, current)); | |
| 6919 current = CloseBlock(); | |
| 6920 } | |
| 6921 return current; | |
| 6922 } | |
| 6923 | |
| 6924 | |
| 6925 AstNode* Parser::ParseTryStatement(String* label_name) { | |
| 6926 TRACE_PARSER("ParseTryStatement"); | |
| 6927 | |
| 6928 // We create three variables for exceptions here: | |
| 6929 // ':saved_try_context_var' - Used to save the context before the start of | |
| 6930 // the try block. The context register is | |
| 6931 // restored from this variable before | |
| 6932 // processing the catch block handler. | |
| 6933 // ':exception_var' - Used to save the current exception object that was | |
| 6934 // thrown. | |
| 6935 // ':stack_trace_var' - Used to save the current stack trace object which | |
| 6936 // the stack trace was copied into when an exception | |
| 6937 // was thrown. | |
| 6938 // :exception_var and :stack_trace_var get set with the exception object | |
| 6939 // and the stack trace object when an exception is thrown. These three | |
| 6940 // implicit variables can never be captured. | |
| 6941 LocalVariable* context_var = | |
| 6942 current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); | |
| 6943 if (context_var == NULL) { | |
| 6944 context_var = new LocalVariable(TokenPos(), | |
| 6945 Symbols::SavedTryContextVar(), | |
| 6946 Type::ZoneHandle(Type::DynamicType())); | |
| 6947 current_block_->scope->AddVariable(context_var); | |
| 6948 } | |
| 6949 LocalVariable* exception_var = | |
| 6950 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); | |
| 6951 if (exception_var == NULL) { | |
| 6952 exception_var = new LocalVariable(TokenPos(), | |
| 6953 Symbols::ExceptionVar(), | |
| 6954 Type::ZoneHandle(Type::DynamicType())); | |
| 6955 current_block_->scope->AddVariable(exception_var); | |
| 6956 } | |
| 6957 LocalVariable* stack_trace_var = | |
| 6958 current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar()); | |
| 6959 if (stack_trace_var == NULL) { | |
| 6960 stack_trace_var = new LocalVariable(TokenPos(), | |
| 6961 Symbols::StackTraceVar(), | |
| 6962 Type::ZoneHandle(Type::DynamicType())); | |
| 6963 current_block_->scope->AddVariable(stack_trace_var); | |
| 6964 } | |
| 6965 | |
| 6966 const intptr_t try_pos = TokenPos(); | |
| 6967 ConsumeToken(); // Consume the 'try'. | |
| 6968 | |
| 6969 SourceLabel* try_label = NULL; | |
| 6970 if (label_name != NULL) { | |
| 6971 try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement); | |
| 6972 OpenBlock(); | |
| 6973 current_block_->scope->AddLabel(try_label); | |
| 6974 } | |
| 6975 | |
| 6976 // Now parse the 'try' block. | |
| 6977 OpenBlock(); | |
| 6978 PushTryBlock(current_block_); | |
| 6979 ExpectToken(Token::kLBRACE); | |
| 6980 ParseStatementSequence(); | |
| 6981 ExpectToken(Token::kRBRACE); | |
| 6982 SequenceNode* try_block = CloseBlock(); | |
| 6983 | |
| 6984 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") && | |
| 6985 (CurrentToken() != Token::kFINALLY)) { | |
| 6986 ErrorMsg("catch or finally clause expected"); | |
| 6987 } | |
| 6988 | |
| 6989 // Now parse the 'catch' blocks if any. | |
| 6990 try_blocks_list_->enter_catch(); | |
| 6991 const intptr_t handler_pos = TokenPos(); | |
| 6992 const GrowableObjectArray& handler_types = | |
| 6993 GrowableObjectArray::Handle(GrowableObjectArray::New()); | |
| 6994 bool needs_stack_trace = false; | |
| 6995 SequenceNode* catch_handler_list = | |
| 6996 ParseCatchClauses(handler_pos, exception_var, stack_trace_var, | |
| 6997 handler_types, &needs_stack_trace); | |
| 6998 | |
| 6952 TryBlocks* inner_try_block = PopTryBlock(); | 6999 TryBlocks* inner_try_block = PopTryBlock(); |
| 6953 const intptr_t try_index = inner_try_block->try_index(); | 7000 const intptr_t try_index = inner_try_block->try_index(); |
| 6954 TryBlocks* outer_try_block = try_blocks_list_; | 7001 TryBlocks* outer_try_block = try_blocks_list_; |
| 6955 const intptr_t outer_try_index = (outer_try_block != NULL) | 7002 const intptr_t outer_try_index = (outer_try_block != NULL) |
| 6956 ? outer_try_block->try_index() | 7003 ? outer_try_block->try_index() |
| 6957 : CatchClauseNode::kInvalidTryIndex; | 7004 : CatchClauseNode::kInvalidTryIndex; |
| 6958 | 7005 |
| 6959 // Finally parse the 'finally' block. | 7006 // Finally parse the 'finally' block. |
| 6960 SequenceNode* finally_block = NULL; | 7007 SequenceNode* finally_block = NULL; |
| 6961 if (CurrentToken() == Token::kFINALLY) { | 7008 if (CurrentToken() == Token::kFINALLY) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 6973 context_var, | 7020 context_var, |
| 6974 outer_try_index); | 7021 outer_try_index); |
| 6975 AddFinallyBlockToNode(node_to_inline, node); | 7022 AddFinallyBlockToNode(node_to_inline, node); |
| 6976 node_index += 1; | 7023 node_index += 1; |
| 6977 node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index); | 7024 node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index); |
| 6978 tokens_iterator_.SetCurrentPosition(finally_pos); | 7025 tokens_iterator_.SetCurrentPosition(finally_pos); |
| 6979 } | 7026 } |
| 6980 finally_block = ParseFinallyBlock(); | 7027 finally_block = ParseFinallyBlock(); |
| 6981 } | 7028 } |
| 6982 | 7029 |
| 6983 if (!generic_catch_seen) { | 7030 CatchClauseNode* catch_clause = |
| 6984 // No generic catch handler exists so rethrow the exception so that | |
| 6985 // the next catch handler can deal with it. | |
| 6986 catch_handler_list->Add( | |
| 6987 new ThrowNode(handler_pos, | |
| 6988 new LoadLocalNode(handler_pos, catch_excp_var), | |
| 6989 new LoadLocalNode(handler_pos, catch_trace_var))); | |
| 6990 } | |
| 6991 CatchClauseNode* catch_block = | |
| 6992 new CatchClauseNode(handler_pos, | 7031 new CatchClauseNode(handler_pos, |
| 6993 catch_handler_list, | 7032 catch_handler_list, |
| 6994 Array::ZoneHandle(Array::MakeArray(handler_types)), | 7033 Array::ZoneHandle(Array::MakeArray(handler_types)), |
| 6995 context_var, | 7034 context_var, |
| 6996 catch_excp_var, | 7035 exception_var, |
| 6997 catch_trace_var, | 7036 stack_trace_var, |
| 6998 (finally_block != NULL) | 7037 (finally_block != NULL) |
| 6999 ? AllocateTryIndex() | 7038 ? AllocateTryIndex() |
| 7000 : CatchClauseNode::kInvalidTryIndex, | 7039 : CatchClauseNode::kInvalidTryIndex, |
| 7001 needs_stacktrace); | 7040 needs_stack_trace); |
| 7002 | 7041 |
| 7003 // Now create the try/catch ast node and return it. If there is a label | 7042 // Now create the try/catch ast node and return it. If there is a label |
| 7004 // on the try/catch, close the block that's embedding the try statement | 7043 // on the try/catch, close the block that's embedding the try statement |
| 7005 // and attach the label to it. | 7044 // and attach the label to it. |
| 7006 AstNode* try_catch_node = | 7045 AstNode* try_catch_node = |
| 7007 new TryCatchNode(try_pos, try_block, end_catch_label, | 7046 new TryCatchNode(try_pos, try_block, context_var, catch_clause, |
| 7008 context_var, catch_block, finally_block, try_index); | 7047 finally_block, try_index); |
| 7009 | 7048 |
| 7010 if (try_label != NULL) { | 7049 if (try_label != NULL) { |
| 7011 current_block_->statements->Add(try_catch_node); | 7050 current_block_->statements->Add(try_catch_node); |
| 7012 SequenceNode* sequence = CloseBlock(); | 7051 SequenceNode* sequence = CloseBlock(); |
| 7013 sequence->set_label(try_label); | 7052 sequence->set_label(try_label); |
| 7014 try_catch_node = sequence; | 7053 try_catch_node = sequence; |
| 7015 } | 7054 } |
| 7016 return try_catch_node; | 7055 return try_catch_node; |
| 7017 } | 7056 } |
| 7018 | 7057 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7155 AddNodeForFinallyInlining(statement); | 7194 AddNodeForFinallyInlining(statement); |
| 7156 ExpectSemicolon(); | 7195 ExpectSemicolon(); |
| 7157 } else if (CurrentToken() == Token::kSEMICOLON) { | 7196 } else if (CurrentToken() == Token::kSEMICOLON) { |
| 7158 // Empty statement, nothing to do. | 7197 // Empty statement, nothing to do. |
| 7159 ConsumeToken(); | 7198 ConsumeToken(); |
| 7160 } else if (CurrentToken() == Token::kRETHROW) { | 7199 } else if (CurrentToken() == Token::kRETHROW) { |
| 7161 // Rethrow of current exception. | 7200 // Rethrow of current exception. |
| 7162 ConsumeToken(); | 7201 ConsumeToken(); |
| 7163 ExpectSemicolon(); | 7202 ExpectSemicolon(); |
| 7164 // Check if it is ok to do a rethrow. | 7203 // Check if it is ok to do a rethrow. |
| 7165 SourceLabel* label = current_block_->scope->LookupInnermostCatchLabel(); | 7204 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { |
|
hausner
2013/11/12 19:21:45
I think you can eliminate the LookupInnermostCatch
Kevin Millikin (Google)
2013/11/13 13:47:02
Yes, thank you. Done.
| |
| 7166 if (label == NULL || | |
| 7167 label->FunctionLevel() != current_block_->scope->function_level()) { | |
| 7168 ErrorMsg(statement_pos, "rethrow of an exception is not valid here"); | 7205 ErrorMsg(statement_pos, "rethrow of an exception is not valid here"); |
| 7169 } | 7206 } |
| 7170 ASSERT(label->owner() != NULL); | 7207 // The exception and stack trace variables are bound in the block |
| 7171 LocalScope* scope = label->owner()->parent(); | 7208 // containing the try. |
| 7209 LocalScope* scope = try_blocks_list_->try_block()->scope->parent(); | |
| 7172 ASSERT(scope != NULL); | 7210 ASSERT(scope != NULL); |
| 7173 LocalVariable* excp_var = | 7211 LocalVariable* excp_var = |
| 7174 scope->LocalLookupVariable(Symbols::ExceptionVar()); | 7212 scope->LocalLookupVariable(Symbols::ExceptionVar()); |
| 7175 ASSERT(excp_var != NULL); | 7213 ASSERT(excp_var != NULL); |
| 7176 LocalVariable* trace_var = | 7214 LocalVariable* trace_var = |
| 7177 scope->LocalLookupVariable(Symbols::StacktraceVar()); | 7215 scope->LocalLookupVariable(Symbols::StackTraceVar()); |
| 7178 ASSERT(trace_var != NULL); | 7216 ASSERT(trace_var != NULL); |
| 7179 statement = new ThrowNode(statement_pos, | 7217 statement = new ThrowNode(statement_pos, |
| 7180 new LoadLocalNode(statement_pos, excp_var), | 7218 new LoadLocalNode(statement_pos, excp_var), |
| 7181 new LoadLocalNode(statement_pos, trace_var)); | 7219 new LoadLocalNode(statement_pos, trace_var)); |
| 7182 } else { | 7220 } else { |
| 7183 statement = ParseExpr(kAllowConst, kConsumeCascades); | 7221 statement = ParseExpr(kAllowConst, kConsumeCascades); |
| 7184 ExpectSemicolon(); | 7222 ExpectSemicolon(); |
| 7185 } | 7223 } |
| 7186 return statement; | 7224 return statement; |
| 7187 } | 7225 } |
| (...skipping 3544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10732 void Parser::SkipQualIdent() { | 10770 void Parser::SkipQualIdent() { |
| 10733 ASSERT(IsIdentifier()); | 10771 ASSERT(IsIdentifier()); |
| 10734 ConsumeToken(); | 10772 ConsumeToken(); |
| 10735 if (CurrentToken() == Token::kPERIOD) { | 10773 if (CurrentToken() == Token::kPERIOD) { |
| 10736 ConsumeToken(); // Consume the kPERIOD token. | 10774 ConsumeToken(); // Consume the kPERIOD token. |
| 10737 ExpectIdentifier("identifier expected after '.'"); | 10775 ExpectIdentifier("identifier expected after '.'"); |
| 10738 } | 10776 } |
| 10739 } | 10777 } |
| 10740 | 10778 |
| 10741 } // namespace dart | 10779 } // namespace dart |
| OLD | NEW |