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 "vm/bigint_operations.h" | 8 #include "platform/utils.h" |
Kevin Millikin (Google)
2013/11/08 11:03:56
This file defines a single type which is not used
|
Kevin Millikin (Google)
2013/11/08 11:03:56
This file uses inline functions from class Utils.
|
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" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Uses the macro HANDLESCOPE, needs its definition.
| |
18 #include "vm/heap.h" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Uses the enumeration values Heap::kOld and Heap::k
| |
19 #include "vm/isolate.h" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Uses inline function Isolate::Current().
| |
17 #include "vm/longjump.h" | 20 #include "vm/longjump.h" |
21 #include "vm/native_arguments.h" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Uses inline function NativeArguments::ParameterCou
| |
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" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Inline functions from class OS.
| |
21 #include "vm/resolver.h" | 26 #include "vm/resolver.h" |
27 #include "vm/scanner.h" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Needs definition of class Scanner (uses constants
| |
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" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Class TimerScope.
| |
32 #include "vm/zone.h" | |
Kevin Millikin (Google)
2013/11/08 11:03:56
Class StackZone.
| |
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 { |
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 // Return false if the stack trace parameter shadows the exception |
6659 const CatchParamDesc& stack_trace_param, | 6665 // parameter. |
6660 LocalScope* scope) { | 6666 static bool AddCatchParamsToScope(CatchParameter* exception_param, |
6661 if (exception_param.var != NULL) { | 6667 CatchParameter* stack_trace_param, |
6662 LocalVariable* var = new LocalVariable(exception_param.token_pos, | 6668 LocalScope* scope) { |
6663 *exception_param.var, | 6669 if (exception_param->name != NULL) { |
6664 *exception_param.type); | 6670 LocalVariable* var = new LocalVariable(exception_param->token_pos, |
6671 *exception_param->name, | |
6672 *exception_param->type); | |
6665 var->set_is_final(); | 6673 var->set_is_final(); |
6666 bool added_to_scope = scope->AddVariable(var); | 6674 bool added_to_scope = scope->AddVariable(var); |
6667 ASSERT(added_to_scope); | 6675 ASSERT(added_to_scope); |
6676 exception_param->var = var; | |
6668 } | 6677 } |
6669 if (stack_trace_param.var != NULL) { | 6678 if (stack_trace_param->name != NULL) { |
6670 LocalVariable* var = new LocalVariable(TokenPos(), | 6679 LocalVariable* var = new LocalVariable(stack_trace_param->token_pos, |
6671 *stack_trace_param.var, | 6680 *stack_trace_param->name, |
6672 *stack_trace_param.type); | 6681 *stack_trace_param->type); |
6673 var->set_is_final(); | 6682 var->set_is_final(); |
6674 bool added_to_scope = scope->AddVariable(var); | 6683 bool added_to_scope = scope->AddVariable(var); |
6675 if (!added_to_scope) { | 6684 stack_trace_param->var = var; |
6676 ErrorMsg(stack_trace_param.token_pos, | 6685 return added_to_scope; |
6677 "name '%s' already exists in scope", | |
6678 stack_trace_param.var->ToCString()); | |
6679 } | |
6680 } | 6686 } |
6687 return true; | |
6681 } | 6688 } |
6682 | 6689 |
6683 | 6690 |
6684 SequenceNode* Parser::ParseFinallyBlock() { | 6691 SequenceNode* Parser::ParseFinallyBlock() { |
6685 TRACE_PARSER("ParseFinallyBlock"); | 6692 TRACE_PARSER("ParseFinallyBlock"); |
6686 OpenBlock(); | 6693 OpenBlock(); |
6687 ExpectToken(Token::kLBRACE); | 6694 ExpectToken(Token::kLBRACE); |
6688 ParseStatementSequence(); | 6695 ParseStatementSequence(); |
6689 ExpectToken(Token::kRBRACE); | 6696 ExpectToken(Token::kRBRACE); |
6690 SequenceNode* finally_block = CloseBlock(); | 6697 SequenceNode* finally_block = CloseBlock(); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6738 InlinedFinallyNode* finally_node) { | 6745 InlinedFinallyNode* finally_node) { |
6739 if (node->IsReturnNode()) { | 6746 if (node->IsReturnNode()) { |
6740 node->AsReturnNode()->AddInlinedFinallyNode(finally_node); | 6747 node->AsReturnNode()->AddInlinedFinallyNode(finally_node); |
6741 } else { | 6748 } else { |
6742 ASSERT(node->IsJumpNode()); | 6749 ASSERT(node->IsJumpNode()); |
6743 node->AsJumpNode()->AddInlinedFinallyNode(finally_node); | 6750 node->AsJumpNode()->AddInlinedFinallyNode(finally_node); |
6744 } | 6751 } |
6745 } | 6752 } |
6746 | 6753 |
6747 | 6754 |
6755 AstNode* Parser::ParseCatchClause(intptr_t handler_pos, | |
6756 LocalVariable* exception_var, | |
6757 LocalVariable* stack_trace_var, | |
6758 const GrowableObjectArray& handler_types, | |
6759 bool* needs_stack_trace) { | |
6760 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on")) { | |
6761 // When we run out of catch clauses, rethrow the exception in case it | |
6762 // was not caught. | |
6763 return new ThrowNode(handler_pos, | |
6764 new LoadLocalNode(handler_pos, exception_var), | |
6765 new LoadLocalNode(handler_pos, stack_trace_var)); | |
6766 } | |
6767 | |
6768 // All catch blocks are merged into an if-then sequence of the different | |
6769 // types specified using the 'is' operator. | |
6770 const intptr_t catch_pos = TokenPos(); | |
6771 CatchParameter exception_param; | |
6772 CatchParameter stack_trace_param; | |
6773 if (IsLiteral("on")) { | |
6774 ConsumeToken(); | |
6775 exception_param.type = &AbstractType::ZoneHandle( | |
6776 ParseType(ClassFinalizer::kCanonicalize)); | |
6777 } else { | |
6778 exception_param.type = &AbstractType::ZoneHandle(Type::DynamicType()); | |
6779 } | |
6780 if (CurrentToken() == Token::kCATCH) { | |
6781 ConsumeToken(); // Consume the 'catch'. | |
6782 ExpectToken(Token::kLPAREN); | |
6783 exception_param.token_pos = TokenPos(); | |
6784 exception_param.name = ExpectIdentifier("identifier expected"); | |
6785 if (CurrentToken() == Token::kCOMMA) { | |
6786 ConsumeToken(); | |
6787 // TODO(hausner): Make implicit type be StackTrace, not dynamic. | |
6788 stack_trace_param.type = | |
6789 &AbstractType::ZoneHandle(Type::DynamicType()); | |
6790 stack_trace_param.token_pos = TokenPos(); | |
6791 stack_trace_param.name = ExpectIdentifier("identifier expected"); | |
6792 } | |
6793 ExpectToken(Token::kRPAREN); | |
6794 } | |
6795 | |
6796 // Create a block containing the catch clause parameters and the following | |
6797 // code: | |
6798 // 1) Store exception object and stack trace object into user-defined | |
6799 // variables (as needed). | |
6800 // 2) Nested block with source code from catch clause block. | |
6801 OpenBlock(); | |
6802 if (!AddCatchParamsToScope(&exception_param, &stack_trace_param, | |
6803 current_block_->scope)) { | |
6804 ErrorMsg(stack_trace_param.token_pos, | |
6805 "name '%s' already exists in scope", | |
6806 stack_trace_param.name->ToCString()); | |
6807 } | |
6808 | |
6809 if (exception_param.var != NULL) { | |
6810 // Generate code to load the exception object (:exception_var) into | |
6811 // the exception variable specified in this block. | |
6812 ASSERT(exception_var != NULL); | |
6813 current_block_->statements->Add( | |
6814 new StoreLocalNode(catch_pos, exception_param.var, | |
6815 new LoadLocalNode(catch_pos, exception_var))); | |
6816 } | |
6817 if (stack_trace_param.var != NULL) { | |
6818 // A stack trace variable is specified in this block, so generate code | |
6819 // to load the stack trace object (:stack_trace_var) into the stack | |
6820 // trace variable specified in this block. | |
6821 *needs_stack_trace = true; | |
6822 ArgumentListNode* no_args = new ArgumentListNode(catch_pos); | |
6823 ASSERT(stack_trace_var != NULL); | |
6824 current_block_->statements->Add( | |
6825 new StoreLocalNode(catch_pos, stack_trace_param.var, | |
6826 new LoadLocalNode(catch_pos, stack_trace_var))); | |
6827 current_block_->statements->Add( | |
6828 new InstanceCallNode( | |
6829 catch_pos, | |
6830 new LoadLocalNode(catch_pos, stack_trace_param.var), | |
6831 Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()), | |
6832 no_args)); | |
6833 } | |
6834 | |
6835 // Add nested block with user-defined code. | |
6836 CheckToken(Token::kLBRACE); | |
6837 current_block_->statements->Add(ParseNestedStatement(false, NULL)); | |
6838 SequenceNode* then_block = CloseBlock(); | |
6839 | |
6840 AstNode* type_test = NULL; | |
6841 if (exception_param.type->IsMalformed() || | |
6842 exception_param.type->IsMalbounded()) { | |
6843 type_test = new LiteralNode(catch_pos, Bool::Get(true)); | |
6844 then_block = new SequenceNode(catch_pos, NULL); | |
6845 then_block->Add(ThrowTypeError(catch_pos, *exception_param.type)); | |
6846 // This catch clause will handle all exceptions. We can safely forget | |
6847 // all previous catch clause types. | |
6848 handler_types.SetLength(0); | |
6849 handler_types.Add(*exception_param.type); | |
6850 } else if (exception_param.type->IsDynamicType()) { | |
6851 // No exception type exists in the catch clause so execute the | |
6852 // catch handler code unconditionally. | |
6853 type_test = new LiteralNode(catch_pos, Bool::Get(true)); | |
6854 // This catch clause will handle all exceptions. We can safely forget | |
6855 // all previous catch clause types. | |
6856 handler_types.SetLength(0); | |
6857 handler_types.Add(*exception_param.type); | |
6858 } else { | |
6859 // Has a type specification that is not malformed or malbounded. | |
6860 // Now form an 'if type check' to guard the catch handler code. | |
6861 if (!exception_param.type->IsInstantiated() && | |
6862 (current_block_->scope->function_level() > 0)) { | |
6863 // Make sure that the instantiator is captured. | |
6864 CaptureInstantiator(); | |
6865 } | |
6866 TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type); | |
6867 AstNode* exception_value = new LoadLocalNode(catch_pos, exception_var); | |
6868 if (!exception_type->type().IsInstantiated()) { | |
6869 EnsureExpressionTemp(); | |
6870 } | |
6871 type_test = new ComparisonNode( | |
6872 catch_pos, Token::kIS, exception_value, exception_type); | |
6873 | |
6874 // Do not add uninstantiated types (e.g. type parameter T or generic | |
6875 // type List<T>), since the debugger won't be able to instantiate it | |
6876 // when walking the stack. | |
6877 // | |
6878 // This means that the debugger is not able to determine whether an | |
6879 // exception is caught if the catch clause uses generic types. It will | |
6880 // report the exception as uncaught when in fact it might be caught and | |
6881 // handled when we unwind the stack. | |
6882 if (exception_param.type->IsInstantiated()) { | |
6883 handler_types.Add(*exception_param.type); | |
6884 } | |
6885 } | |
6886 | |
6887 SequenceNode* else_block = new SequenceNode(handler_pos, NULL); | |
6888 else_block->Add( | |
6889 ParseCatchClause(handler_pos, exception_var, stack_trace_var, | |
6890 handler_types, needs_stack_trace)); | |
6891 return new IfNode(catch_pos, type_test, then_block, else_block); | |
6892 } | |
6893 | |
6894 | |
6748 AstNode* Parser::ParseTryStatement(String* label_name) { | 6895 AstNode* Parser::ParseTryStatement(String* label_name) { |
6749 TRACE_PARSER("ParseTryStatement"); | 6896 TRACE_PARSER("ParseTryStatement"); |
6750 | 6897 |
6751 // We create three stack slots for exceptions here: | 6898 // We create three stack slots for exceptions here: |
6752 // ':saved_try_context_var' - Used to save the context before start of the try | 6899 // ':saved_try_context_var' - Used to save the context before start of the try |
6753 // block. The context register is restored from | 6900 // block. The context register is restored from |
6754 // this slot before processing the catch block | 6901 // this slot before processing the catch block |
6755 // handler. | 6902 // handler. |
6756 // ':exception_var' - Used to save the current exception object that was | 6903 // ':exception_var' - Used to save the current exception object that was |
6757 // thrown. | 6904 // thrown. |
6758 // ':stacktrace_var' - Used to save the current stack trace object into which | 6905 // ':stack_trace_var' - Used to save the current stack trace object into |
6759 // the stack trace was copied into when an exception was | 6906 // which the stack trace was copied into when an |
6760 // thrown. | 6907 // exception was thrown. |
6761 // :exception_var and :stacktrace_var get set with the exception object | 6908 // :exception_var and :stack_trace_var get set with the exception object |
6762 // and the stacktrace object when an exception is thrown. | 6909 // and the stack trace object when an exception is thrown. These three |
6763 // These three implicit variables can never be captured variables. | 6910 // implicit variables can never be captured variables. |
6764 LocalVariable* context_var = | 6911 LocalVariable* context_var = |
6765 current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); | 6912 current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); |
6766 if (context_var == NULL) { | 6913 if (context_var == NULL) { |
6767 context_var = new LocalVariable(TokenPos(), | 6914 context_var = new LocalVariable(TokenPos(), |
6768 Symbols::SavedTryContextVar(), | 6915 Symbols::SavedTryContextVar(), |
6769 Type::ZoneHandle(Type::DynamicType())); | 6916 Type::ZoneHandle(Type::DynamicType())); |
6770 current_block_->scope->AddVariable(context_var); | 6917 current_block_->scope->AddVariable(context_var); |
6771 } | 6918 } |
6772 LocalVariable* catch_excp_var = | 6919 LocalVariable* exception_var = |
6773 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); | 6920 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); |
6774 if (catch_excp_var == NULL) { | 6921 if (exception_var == NULL) { |
6775 catch_excp_var = new LocalVariable(TokenPos(), | 6922 exception_var = new LocalVariable(TokenPos(), |
6776 Symbols::ExceptionVar(), | 6923 Symbols::ExceptionVar(), |
6777 Type::ZoneHandle(Type::DynamicType())); | 6924 Type::ZoneHandle(Type::DynamicType())); |
6778 current_block_->scope->AddVariable(catch_excp_var); | 6925 current_block_->scope->AddVariable(exception_var); |
6779 } | 6926 } |
6780 LocalVariable* catch_trace_var = | 6927 LocalVariable* stack_trace_var = |
6781 current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar()); | 6928 current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar()); |
6782 if (catch_trace_var == NULL) { | 6929 if (stack_trace_var == NULL) { |
6783 catch_trace_var = new LocalVariable(TokenPos(), | 6930 stack_trace_var = new LocalVariable(TokenPos(), |
6784 Symbols::StacktraceVar(), | 6931 Symbols::StackTraceVar(), |
6785 Type::ZoneHandle(Type::DynamicType())); | 6932 Type::ZoneHandle(Type::DynamicType())); |
6786 current_block_->scope->AddVariable(catch_trace_var); | 6933 current_block_->scope->AddVariable(stack_trace_var); |
6787 } | 6934 } |
6788 | 6935 |
6789 const intptr_t try_pos = TokenPos(); | 6936 const intptr_t try_pos = TokenPos(); |
6790 ConsumeToken(); // Consume the 'try'. | 6937 ConsumeToken(); // Consume the 'try'. |
6791 | 6938 |
6792 SourceLabel* try_label = NULL; | 6939 SourceLabel* try_label = NULL; |
6793 if (label_name != NULL) { | 6940 if (label_name != NULL) { |
6794 try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement); | 6941 try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement); |
6795 OpenBlock(); | 6942 OpenBlock(); |
6796 current_block_->scope->AddLabel(try_label); | 6943 current_block_->scope->AddLabel(try_label); |
6797 } | 6944 } |
6798 | 6945 |
6799 // Now parse the 'try' block. | 6946 // Now parse the 'try' block. |
6800 OpenBlock(); | 6947 OpenBlock(); |
6801 PushTryBlock(current_block_); | 6948 PushTryBlock(current_block_); |
6802 ExpectToken(Token::kLBRACE); | 6949 ExpectToken(Token::kLBRACE); |
6803 ParseStatementSequence(); | 6950 ParseStatementSequence(); |
6804 ExpectToken(Token::kRBRACE); | 6951 ExpectToken(Token::kRBRACE); |
6805 SequenceNode* try_block = CloseBlock(); | 6952 SequenceNode* try_block = CloseBlock(); |
6806 | 6953 |
6807 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") && | 6954 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") && |
6808 (CurrentToken() != Token::kFINALLY)) { | 6955 (CurrentToken() != Token::kFINALLY)) { |
6809 ErrorMsg("catch or finally clause expected"); | 6956 ErrorMsg("catch or finally clause expected"); |
6810 } | 6957 } |
6811 | 6958 |
6812 // Now create a label for the end of catch block processing so that we can | 6959 // Now parse the 'catch' blocks if any. |
6813 // jump over the catch block code after executing the try block. | 6960 try_blocks_list_->enter_catch(); |
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(); | 6961 const intptr_t handler_pos = TokenPos(); |
6822 OpenBlock(); // Start the catch block sequence. | 6962 OpenBlock(); // Start the catch block sequence. |
6823 current_block_->scope->AddLabel(end_catch_label); | |
6824 const GrowableObjectArray& handler_types = | 6963 const GrowableObjectArray& handler_types = |
6825 GrowableObjectArray::Handle(GrowableObjectArray::New()); | 6964 GrowableObjectArray::Handle(GrowableObjectArray::New()); |
6826 bool needs_stacktrace = false; | 6965 bool needs_stack_trace = false; |
6827 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) { | 6966 current_block_->statements->Add( |
6828 const intptr_t catch_pos = TokenPos(); | 6967 ParseCatchClause(handler_pos, exception_var, stack_trace_var, |
6829 CatchParamDesc exception_param; | 6968 handler_types, &needs_stack_trace)); |
6830 CatchParamDesc stack_trace_param; | 6969 SequenceNode* catch_handler_list = CloseBlock(); |
6831 if (IsLiteral("on")) { | |
6832 ConsumeToken(); | |
6833 exception_param.type = &AbstractType::ZoneHandle( | |
6834 ParseType(ClassFinalizer::kCanonicalize)); | |
6835 } else { | |
6836 exception_param.type = &AbstractType::ZoneHandle(Type::DynamicType()); | |
6837 } | |
6838 if (CurrentToken() == Token::kCATCH) { | |
6839 ConsumeToken(); // Consume the 'catch'. | |
6840 ExpectToken(Token::kLPAREN); | |
6841 exception_param.token_pos = TokenPos(); | |
6842 exception_param.var = ExpectIdentifier("identifier expected"); | |
6843 if (CurrentToken() == Token::kCOMMA) { | |
6844 ConsumeToken(); | |
6845 // TODO(hausner): Make implicit type be StackTrace, not dynamic. | |
6846 stack_trace_param.type = | |
6847 &AbstractType::ZoneHandle(Type::DynamicType()); | |
6848 stack_trace_param.token_pos = TokenPos(); | |
6849 stack_trace_param.var = ExpectIdentifier("identifier expected"); | |
6850 } | |
6851 ExpectToken(Token::kRPAREN); | |
6852 } | |
6853 | 6970 |
6854 // Create a block containing the catch clause parameters and | |
6855 // the following code: | |
6856 // 1) Store exception object and stack trace object into user-defined | |
6857 // variables (as needed). | |
6858 // 2) Nested block with source code from catch clause block. | |
6859 // 3) Unconditional JUMP to the end of the try block. | |
6860 OpenBlock(); | |
6861 AddCatchParamsToScope(exception_param, | |
6862 stack_trace_param, | |
6863 current_block_->scope); | |
6864 | |
6865 if (exception_param.var != NULL) { | |
6866 // Generate code to load the exception object (:exception_var) into | |
6867 // the exception variable specified in this block. | |
6868 LocalVariable* var = LookupLocalScope(*exception_param.var); | |
6869 ASSERT(var != NULL); | |
6870 ASSERT(catch_excp_var != NULL); | |
6871 current_block_->statements->Add( | |
6872 new StoreLocalNode(catch_pos, var, | |
6873 new LoadLocalNode(catch_pos, catch_excp_var))); | |
6874 } | |
6875 if (stack_trace_param.var != NULL) { | |
6876 // 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 | |
6878 // variable specified in this block. | |
6879 needs_stacktrace = true; | |
6880 ArgumentListNode* no_args = new ArgumentListNode(catch_pos); | |
6881 LocalVariable* trace = LookupLocalScope(*stack_trace_param.var); | |
6882 ASSERT(catch_trace_var != NULL); | |
6883 current_block_->statements->Add( | |
6884 new StoreLocalNode(catch_pos, trace, | |
6885 new LoadLocalNode(catch_pos, catch_trace_var))); | |
6886 current_block_->statements->Add( | |
6887 new InstanceCallNode( | |
6888 catch_pos, | |
6889 new LoadLocalNode(catch_pos, trace), | |
6890 Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()), | |
6891 no_args)); | |
6892 } | |
6893 | |
6894 // Add nested block with user-defined code. | |
6895 CheckToken(Token::kLBRACE); | |
6896 current_block_->statements->Add(ParseNestedStatement(false, NULL)); | |
6897 | |
6898 // Add unconditional jump to end of catch clause list. | |
6899 current_block_->statements->Add( | |
6900 new JumpNode(catch_pos, Token::kCONTINUE, end_catch_label)); | |
6901 | |
6902 SequenceNode* catch_clause = CloseBlock(); | |
6903 | |
6904 const bool is_bad_type = exception_param.type->IsMalformed() || | |
6905 exception_param.type->IsMalbounded(); | |
6906 if (!is_bad_type && !exception_param.type->IsDynamicType()) { | |
6907 // Has a type specification that is not malformed or malbounded. | |
6908 // Now form an 'if type check' to guard the catch handler code. | |
6909 if (!exception_param.type->IsInstantiated() && | |
6910 (current_block_->scope->function_level() > 0)) { | |
6911 // Make sure that the instantiator is captured. | |
6912 CaptureInstantiator(); | |
6913 } | |
6914 TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type); | |
6915 AstNode* exception_var = new LoadLocalNode(catch_pos, catch_excp_var); | |
6916 if (!exception_type->type().IsInstantiated()) { | |
6917 EnsureExpressionTemp(); | |
6918 } | |
6919 AstNode* type_cond_expr = new ComparisonNode( | |
6920 catch_pos, Token::kIS, exception_var, exception_type); | |
6921 current_block_->statements->Add( | |
6922 new IfNode(catch_pos, type_cond_expr, catch_clause, NULL)); | |
6923 | |
6924 // Do not add uninstantiated types (e.g. type parameter T or | |
6925 // generic type List<T>), since the debugger won't be able to | |
6926 // instantiate it when walking the stack. | |
6927 // This means that the debugger is not able to determine whether | |
6928 // an exception is caught if the catch clause uses generic types. | |
6929 // It will report the exception as uncaught when in fact it might | |
6930 // be caught and handled when we unwind the stack. | |
6931 if (exception_param.type->IsInstantiated()) { | |
6932 handler_types.Add(*exception_param.type); | |
6933 } | |
6934 } else { | |
6935 if (is_bad_type) { | |
6936 current_block_->statements->Add(ThrowTypeError(catch_pos, | |
6937 *exception_param.type)); | |
6938 // We still add the dead code below to satisfy the code generator. | |
6939 } | |
6940 // No exception type exists in the catch clause so execute the | |
6941 // catch handler code unconditionally. | |
6942 current_block_->statements->Add(catch_clause); | |
6943 generic_catch_seen = true; | |
6944 // This catch clause will handle all exceptions. We can safely forget | |
6945 // all previous catch clause types. | |
6946 handler_types.SetLength(0); | |
6947 handler_types.Add(*exception_param.type); | |
6948 } | |
6949 } | |
6950 | |
6951 SequenceNode* catch_handler_list = CloseBlock(); | |
6952 TryBlocks* inner_try_block = PopTryBlock(); | 6971 TryBlocks* inner_try_block = PopTryBlock(); |
6953 const intptr_t try_index = inner_try_block->try_index(); | 6972 const intptr_t try_index = inner_try_block->try_index(); |
6954 TryBlocks* outer_try_block = try_blocks_list_; | 6973 TryBlocks* outer_try_block = try_blocks_list_; |
6955 const intptr_t outer_try_index = (outer_try_block != NULL) | 6974 const intptr_t outer_try_index = (outer_try_block != NULL) |
6956 ? outer_try_block->try_index() | 6975 ? outer_try_block->try_index() |
6957 : CatchClauseNode::kInvalidTryIndex; | 6976 : CatchClauseNode::kInvalidTryIndex; |
6958 | 6977 |
6959 // Finally parse the 'finally' block. | 6978 // Finally parse the 'finally' block. |
6960 SequenceNode* finally_block = NULL; | 6979 SequenceNode* finally_block = NULL; |
6961 if (CurrentToken() == Token::kFINALLY) { | 6980 if (CurrentToken() == Token::kFINALLY) { |
(...skipping 11 matching lines...) Expand all Loading... | |
6973 context_var, | 6992 context_var, |
6974 outer_try_index); | 6993 outer_try_index); |
6975 AddFinallyBlockToNode(node_to_inline, node); | 6994 AddFinallyBlockToNode(node_to_inline, node); |
6976 node_index += 1; | 6995 node_index += 1; |
6977 node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index); | 6996 node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index); |
6978 tokens_iterator_.SetCurrentPosition(finally_pos); | 6997 tokens_iterator_.SetCurrentPosition(finally_pos); |
6979 } | 6998 } |
6980 finally_block = ParseFinallyBlock(); | 6999 finally_block = ParseFinallyBlock(); |
6981 } | 7000 } |
6982 | 7001 |
6983 if (!generic_catch_seen) { | 7002 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, | 7003 new CatchClauseNode(handler_pos, |
6993 catch_handler_list, | 7004 catch_handler_list, |
6994 Array::ZoneHandle(Array::MakeArray(handler_types)), | 7005 Array::ZoneHandle(Array::MakeArray(handler_types)), |
6995 context_var, | 7006 context_var, |
6996 catch_excp_var, | 7007 exception_var, |
6997 catch_trace_var, | 7008 stack_trace_var, |
6998 (finally_block != NULL) | 7009 (finally_block != NULL) |
6999 ? AllocateTryIndex() | 7010 ? AllocateTryIndex() |
7000 : CatchClauseNode::kInvalidTryIndex, | 7011 : CatchClauseNode::kInvalidTryIndex, |
7001 needs_stacktrace); | 7012 needs_stack_trace); |
7002 | 7013 |
7003 // Now create the try/catch ast node and return it. If there is a label | 7014 // 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 | 7015 // on the try/catch, close the block that's embedding the try statement |
7005 // and attach the label to it. | 7016 // and attach the label to it. |
7006 AstNode* try_catch_node = | 7017 AstNode* try_catch_node = |
7007 new TryCatchNode(try_pos, try_block, end_catch_label, | 7018 new TryCatchNode(try_pos, try_block, context_var, catch_clause, |
7008 context_var, catch_block, finally_block, try_index); | 7019 finally_block, try_index); |
7009 | 7020 |
7010 if (try_label != NULL) { | 7021 if (try_label != NULL) { |
7011 current_block_->statements->Add(try_catch_node); | 7022 current_block_->statements->Add(try_catch_node); |
7012 SequenceNode* sequence = CloseBlock(); | 7023 SequenceNode* sequence = CloseBlock(); |
7013 sequence->set_label(try_label); | 7024 sequence->set_label(try_label); |
7014 try_catch_node = sequence; | 7025 try_catch_node = sequence; |
7015 } | 7026 } |
7016 return try_catch_node; | 7027 return try_catch_node; |
7017 } | 7028 } |
7018 | 7029 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7155 AddNodeForFinallyInlining(statement); | 7166 AddNodeForFinallyInlining(statement); |
7156 ExpectSemicolon(); | 7167 ExpectSemicolon(); |
7157 } else if (CurrentToken() == Token::kSEMICOLON) { | 7168 } else if (CurrentToken() == Token::kSEMICOLON) { |
7158 // Empty statement, nothing to do. | 7169 // Empty statement, nothing to do. |
7159 ConsumeToken(); | 7170 ConsumeToken(); |
7160 } else if (CurrentToken() == Token::kRETHROW) { | 7171 } else if (CurrentToken() == Token::kRETHROW) { |
7161 // Rethrow of current exception. | 7172 // Rethrow of current exception. |
7162 ConsumeToken(); | 7173 ConsumeToken(); |
7163 ExpectSemicolon(); | 7174 ExpectSemicolon(); |
7164 // Check if it is ok to do a rethrow. | 7175 // Check if it is ok to do a rethrow. |
7165 SourceLabel* label = current_block_->scope->LookupInnermostCatchLabel(); | 7176 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { |
7166 if (label == NULL || | |
7167 label->FunctionLevel() != current_block_->scope->function_level()) { | |
7168 ErrorMsg(statement_pos, "rethrow of an exception is not valid here"); | 7177 ErrorMsg(statement_pos, "rethrow of an exception is not valid here"); |
7169 } | 7178 } |
7170 ASSERT(label->owner() != NULL); | 7179 // The exception and stack trace variables are bound in the block |
7171 LocalScope* scope = label->owner()->parent(); | 7180 // containing the try. |
7181 LocalScope* scope = try_blocks_list_->try_block()->scope->parent(); | |
7172 ASSERT(scope != NULL); | 7182 ASSERT(scope != NULL); |
7173 LocalVariable* excp_var = | 7183 LocalVariable* excp_var = |
7174 scope->LocalLookupVariable(Symbols::ExceptionVar()); | 7184 scope->LocalLookupVariable(Symbols::ExceptionVar()); |
7175 ASSERT(excp_var != NULL); | 7185 ASSERT(excp_var != NULL); |
7176 LocalVariable* trace_var = | 7186 LocalVariable* trace_var = |
7177 scope->LocalLookupVariable(Symbols::StacktraceVar()); | 7187 scope->LocalLookupVariable(Symbols::StackTraceVar()); |
7178 ASSERT(trace_var != NULL); | 7188 ASSERT(trace_var != NULL); |
7179 statement = new ThrowNode(statement_pos, | 7189 statement = new ThrowNode(statement_pos, |
7180 new LoadLocalNode(statement_pos, excp_var), | 7190 new LoadLocalNode(statement_pos, excp_var), |
7181 new LoadLocalNode(statement_pos, trace_var)); | 7191 new LoadLocalNode(statement_pos, trace_var)); |
7182 } else { | 7192 } else { |
7183 statement = ParseExpr(kAllowConst, kConsumeCascades); | 7193 statement = ParseExpr(kAllowConst, kConsumeCascades); |
7184 ExpectSemicolon(); | 7194 ExpectSemicolon(); |
7185 } | 7195 } |
7186 return statement; | 7196 return statement; |
7187 } | 7197 } |
(...skipping 3544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10732 void Parser::SkipQualIdent() { | 10742 void Parser::SkipQualIdent() { |
10733 ASSERT(IsIdentifier()); | 10743 ASSERT(IsIdentifier()); |
10734 ConsumeToken(); | 10744 ConsumeToken(); |
10735 if (CurrentToken() == Token::kPERIOD) { | 10745 if (CurrentToken() == Token::kPERIOD) { |
10736 ConsumeToken(); // Consume the kPERIOD token. | 10746 ConsumeToken(); // Consume the kPERIOD token. |
10737 ExpectIdentifier("identifier expected after '.'"); | 10747 ExpectIdentifier("identifier expected after '.'"); |
10738 } | 10748 } |
10739 } | 10749 } |
10740 | 10750 |
10741 } // namespace dart | 10751 } // namespace dart |
OLD | NEW |