| 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 "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
| 8 #include "vm/class_finalizer.h" | 8 #include "vm/class_finalizer.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/compiler_stats.h" | 10 #include "vm/compiler_stats.h" |
| (...skipping 5829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5840 condition, | 5840 condition, |
| 5841 NodeAsSequenceNode(condition_pos, assert_throw, NULL), | 5841 NodeAsSequenceNode(condition_pos, assert_throw, NULL), |
| 5842 NULL); | 5842 NULL); |
| 5843 } | 5843 } |
| 5844 | 5844 |
| 5845 | 5845 |
| 5846 // TODO(hausner): This structure can be simplified once the old catch | 5846 // TODO(hausner): This structure can be simplified once the old catch |
| 5847 // syntax is removed. All catch parameters in the new syntax are final. | 5847 // syntax is removed. All catch parameters in the new syntax are final. |
| 5848 struct CatchParamDesc { | 5848 struct CatchParamDesc { |
| 5849 CatchParamDesc() | 5849 CatchParamDesc() |
| 5850 : token_pos(0), type(NULL), var(NULL), is_final(false) { } | 5850 : token_pos(0), type(NULL), var(NULL) { } |
| 5851 intptr_t token_pos; | 5851 intptr_t token_pos; |
| 5852 const AbstractType* type; | 5852 const AbstractType* type; |
| 5853 const String* var; | 5853 const String* var; |
| 5854 bool is_final; | |
| 5855 }; | 5854 }; |
| 5856 | 5855 |
| 5857 | 5856 |
| 5858 // Parse the parameter specified in the catch clause. | |
| 5859 void Parser::ParseCatchParameter(CatchParamDesc* catch_param) { | |
| 5860 TRACE_PARSER("ParseCatchParameter"); | |
| 5861 ASSERT(catch_param != NULL); | |
| 5862 catch_param->is_final = (CurrentToken() == Token::kFINAL); | |
| 5863 // The type of the catch parameter must always be resolved, even in unchecked | |
| 5864 // mode. | |
| 5865 if (CurrentToken() == Token::kCONST) { | |
| 5866 ErrorMsg("Catch parameter cannot be 'const'"); | |
| 5867 } | |
| 5868 catch_param->type = &AbstractType::ZoneHandle( | |
| 5869 ParseConstFinalVarOrType(ClassFinalizer::kCanonicalizeWellFormed)); | |
| 5870 catch_param->token_pos = TokenPos(); | |
| 5871 catch_param->var = ExpectIdentifier("identifier expected"); | |
| 5872 } | |
| 5873 | |
| 5874 | |
| 5875 // Populate local scope of the catch block with the catch parameters. | 5857 // Populate local scope of the catch block with the catch parameters. |
| 5876 void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, | 5858 void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, |
| 5877 const CatchParamDesc& stack_trace_param, | 5859 const CatchParamDesc& stack_trace_param, |
| 5878 LocalScope* scope) { | 5860 LocalScope* scope) { |
| 5879 ASSERT(exception_param.var != NULL); | 5861 if (exception_param.var != NULL) { |
| 5880 LocalVariable* var = new LocalVariable(exception_param.token_pos, | 5862 LocalVariable* var = new LocalVariable(exception_param.token_pos, |
| 5881 *exception_param.var, | 5863 *exception_param.var, |
| 5882 *exception_param.type); | 5864 *exception_param.type); |
| 5883 if (exception_param.is_final) { | |
| 5884 var->set_is_final(); | 5865 var->set_is_final(); |
| 5866 bool added_to_scope = scope->AddVariable(var); |
| 5867 ASSERT(added_to_scope); |
| 5885 } | 5868 } |
| 5886 bool added_to_scope = scope->AddVariable(var); | |
| 5887 ASSERT(added_to_scope); | |
| 5888 if (stack_trace_param.var != NULL) { | 5869 if (stack_trace_param.var != NULL) { |
| 5889 var = new LocalVariable(TokenPos(), | 5870 LocalVariable* var = new LocalVariable(TokenPos(), |
| 5890 *stack_trace_param.var, | 5871 *stack_trace_param.var, |
| 5891 *stack_trace_param.type); | 5872 *stack_trace_param.type); |
| 5892 if (stack_trace_param.is_final) { | 5873 var->set_is_final(); |
| 5893 var->set_is_final(); | 5874 bool added_to_scope = scope->AddVariable(var); |
| 5894 } | |
| 5895 added_to_scope = scope->AddVariable(var); | |
| 5896 if (!added_to_scope) { | 5875 if (!added_to_scope) { |
| 5897 ErrorMsg(stack_trace_param.token_pos, | 5876 ErrorMsg(stack_trace_param.token_pos, |
| 5898 "name '%s' already exists in scope", | 5877 "name '%s' already exists in scope", |
| 5899 stack_trace_param.var->ToCString()); | 5878 stack_trace_param.var->ToCString()); |
| 5900 } | 5879 } |
| 5901 } | 5880 } |
| 5902 } | 5881 } |
| 5903 | 5882 |
| 5904 | 5883 |
| 5905 SequenceNode* Parser::ParseFinallyBlock() { | 5884 SequenceNode* Parser::ParseFinallyBlock() { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6042 bool generic_catch_seen = false; | 6021 bool generic_catch_seen = false; |
| 6043 SequenceNode* catch_handler_list = NULL; | 6022 SequenceNode* catch_handler_list = NULL; |
| 6044 const intptr_t handler_pos = TokenPos(); | 6023 const intptr_t handler_pos = TokenPos(); |
| 6045 OpenBlock(); // Start the catch block sequence. | 6024 OpenBlock(); // Start the catch block sequence. |
| 6046 current_block_->scope->AddLabel(end_catch_label); | 6025 current_block_->scope->AddLabel(end_catch_label); |
| 6047 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) { | 6026 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) { |
| 6048 const intptr_t catch_pos = TokenPos(); | 6027 const intptr_t catch_pos = TokenPos(); |
| 6049 CatchParamDesc exception_param; | 6028 CatchParamDesc exception_param; |
| 6050 CatchParamDesc stack_trace_param; | 6029 CatchParamDesc stack_trace_param; |
| 6051 catch_seen = true; | 6030 catch_seen = true; |
| 6031 if (IsLiteral("on")) { |
| 6032 ConsumeToken(); |
| 6033 exception_param.type = &AbstractType::ZoneHandle( |
| 6034 ParseType(ClassFinalizer::kCanonicalizeWellFormed)); |
| 6035 } else { |
| 6036 exception_param.type = |
| 6037 &AbstractType::ZoneHandle(Type::DynamicType()); |
| 6038 } |
| 6052 if (CurrentToken() == Token::kCATCH) { | 6039 if (CurrentToken() == Token::kCATCH) { |
| 6053 ConsumeToken(); // Consume the 'catch'. | 6040 ConsumeToken(); // Consume the 'catch'. |
| 6054 ExpectToken(Token::kLPAREN); | 6041 ExpectToken(Token::kLPAREN); |
| 6055 if (IsIdentifier() && | |
| 6056 ((LookaheadToken(1) == Token::kCOMMA) || | |
| 6057 (LookaheadToken(1) == Token::kRPAREN))) { | |
| 6058 // New catch syntax for untyped exception variable: | |
| 6059 // catch(e) or catch (e,s). | |
| 6060 exception_param.is_final = true; | |
| 6061 exception_param.type = | |
| 6062 &AbstractType::ZoneHandle(Type::DynamicType()); | |
| 6063 exception_param.token_pos = TokenPos(); | |
| 6064 exception_param.var = ExpectIdentifier("identifier expected"); | |
| 6065 if (CurrentToken() == Token::kCOMMA) { | |
| 6066 ConsumeToken(); | |
| 6067 stack_trace_param.is_final = true; | |
| 6068 // TODO(hausner): Make implicit type be StackTrace, not Dynamic. | |
| 6069 stack_trace_param.type = | |
| 6070 &AbstractType::ZoneHandle(Type::DynamicType()); | |
| 6071 stack_trace_param.token_pos = TokenPos(); | |
| 6072 stack_trace_param.var = ExpectIdentifier("identifier expected"); | |
| 6073 } | |
| 6074 } else { | |
| 6075 // TODO(hausner): Improve error message and maybe also the | |
| 6076 // structure of the code. Maybe you can get away with simply | |
| 6077 // expecting an identifier followed by a comma or a right | |
| 6078 // parenthesis? | |
| 6079 ErrorMsg("identifier expected here, not type, final, or var"); | |
| 6080 } | |
| 6081 } else { | |
| 6082 // on T catch(e) { ... | |
| 6083 ConsumeToken(); // on | |
| 6084 exception_param.is_final = true; | |
| 6085 exception_param.type = &AbstractType::ZoneHandle( | |
| 6086 ParseType(ClassFinalizer::kCanonicalizeWellFormed)); | |
| 6087 ExpectToken(Token::kCATCH); | |
| 6088 ExpectToken(Token::kLPAREN); | |
| 6089 exception_param.token_pos = TokenPos(); | 6042 exception_param.token_pos = TokenPos(); |
| 6090 exception_param.var = ExpectIdentifier("identifier expected"); | 6043 exception_param.var = ExpectIdentifier("identifier expected"); |
| 6091 if (CurrentToken() == Token::kCOMMA) { | 6044 if (CurrentToken() == Token::kCOMMA) { |
| 6092 ConsumeToken(); | 6045 ConsumeToken(); |
| 6093 stack_trace_param.is_final = true; | 6046 // TODO(hausner): Make implicit type be StackTrace, not Dynamic. |
| 6094 // TODO(hausner): Make imlicit type be StackTrace, not Dynamic. | |
| 6095 stack_trace_param.type = | 6047 stack_trace_param.type = |
| 6096 &AbstractType::ZoneHandle(Type::DynamicType()); | 6048 &AbstractType::ZoneHandle(Type::DynamicType()); |
| 6097 stack_trace_param.token_pos = TokenPos(); | 6049 stack_trace_param.token_pos = TokenPos(); |
| 6098 stack_trace_param.var = ExpectIdentifier("identifier expected"); | 6050 stack_trace_param.var = ExpectIdentifier("identifier expected"); |
| 6099 } | 6051 } |
| 6052 ExpectToken(Token::kRPAREN); |
| 6100 } | 6053 } |
| 6101 ExpectToken(Token::kRPAREN); | |
| 6102 | 6054 |
| 6103 // If a generic "catch all" statement has already been seen then all | 6055 // If a generic "catch all" statement has already been seen then all |
| 6104 // subsequent catch statements are dead. We issue an error for now, | 6056 // subsequent catch statements are dead. We issue an error for now, |
| 6105 // it might make sense to turn this into a warning. | 6057 // it might make sense to turn this into a warning. |
| 6106 if (generic_catch_seen) { | 6058 if (generic_catch_seen) { |
| 6107 ErrorMsg("a generic 'catch all' statement already exists for this " | 6059 ErrorMsg("a generic 'catch all' statement already exists for this " |
| 6108 "try block. All subsequent catch statements are dead code"); | 6060 "try block. All subsequent catch statements are dead code"); |
| 6109 } | 6061 } |
| 6110 OpenBlock(); | 6062 OpenBlock(); |
| 6111 AddCatchParamsToScope(exception_param, | 6063 AddCatchParamsToScope(exception_param, |
| 6112 stack_trace_param, | 6064 stack_trace_param, |
| 6113 current_block_->scope); | 6065 current_block_->scope); |
| 6114 | 6066 |
| 6115 SequenceNode* catch_clause; | |
| 6116 | |
| 6117 // Parse the individual catch handler code and add an unconditional | 6067 // Parse the individual catch handler code and add an unconditional |
| 6118 // JUMP to the end of the try block. | 6068 // JUMP to the end of the try block. |
| 6119 ExpectToken(Token::kLBRACE); | 6069 ExpectToken(Token::kLBRACE); |
| 6120 OpenBlock(); | 6070 OpenBlock(); |
| 6121 | 6071 |
| 6122 // Generate code to load the exception object (:exception_var) into | 6072 if (exception_param.var != NULL) { |
| 6123 // the exception variable specified in this block. | 6073 // Generate code to load the exception object (:exception_var) into |
| 6124 ASSERT(exception_param.var != NULL); | 6074 // the exception variable specified in this block. |
| 6125 LocalVariable* var = LookupLocalScope(*exception_param.var); | 6075 LocalVariable* var = LookupLocalScope(*exception_param.var); |
| 6126 ASSERT(var != NULL); | 6076 ASSERT(var != NULL); |
| 6127 ASSERT(catch_excp_var != NULL); | 6077 ASSERT(catch_excp_var != NULL); |
| 6128 current_block_->statements->Add( | 6078 current_block_->statements->Add( |
| 6129 new StoreLocalNode(catch_pos, | 6079 new StoreLocalNode(catch_pos, var, |
| 6130 var, | 6080 new LoadLocalNode(catch_pos, catch_excp_var))); |
| 6131 new LoadLocalNode(catch_pos, catch_excp_var))); | 6081 } |
| 6132 if (stack_trace_param.var != NULL) { | 6082 if (stack_trace_param.var != NULL) { |
| 6133 // A stack trace variable is specified in this block, so generate code | 6083 // A stack trace variable is specified in this block, so generate code |
| 6134 // to load the stack trace object (:stacktrace_var) into the stack trace | 6084 // to load the stack trace object (:stacktrace_var) into the stack trace |
| 6135 // variable specified in this block. | 6085 // variable specified in this block. |
| 6136 LocalVariable* trace = LookupLocalScope(*stack_trace_param.var); | 6086 LocalVariable* trace = LookupLocalScope(*stack_trace_param.var); |
| 6137 ASSERT(catch_trace_var != NULL); | 6087 ASSERT(catch_trace_var != NULL); |
| 6138 current_block_->statements->Add( | 6088 current_block_->statements->Add( |
| 6139 new StoreLocalNode(catch_pos, | 6089 new StoreLocalNode(catch_pos, trace, |
| 6140 trace, | |
| 6141 new LoadLocalNode(catch_pos, catch_trace_var))); | 6090 new LoadLocalNode(catch_pos, catch_trace_var))); |
| 6142 } | 6091 } |
| 6143 | 6092 |
| 6144 ParseStatementSequence(); // Parse the catch handler code. | 6093 ParseStatementSequence(); // Parse the catch handler code. |
| 6145 current_block_->statements->Add( | 6094 current_block_->statements->Add( |
| 6146 new JumpNode(catch_pos, Token::kCONTINUE, end_catch_label)); | 6095 new JumpNode(catch_pos, Token::kCONTINUE, end_catch_label)); |
| 6147 SequenceNode* catch_handler = CloseBlock(); | 6096 SequenceNode* catch_handler = CloseBlock(); |
| 6148 ExpectToken(Token::kRBRACE); | 6097 ExpectToken(Token::kRBRACE); |
| 6149 | 6098 |
| 6150 if (!exception_param.type->IsDynamicType()) { // Has a type specification. | 6099 if (!exception_param.type->IsDynamicType()) { // Has a type specification. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 6163 AstNode* type_cond_expr = new ComparisonNode( | 6112 AstNode* type_cond_expr = new ComparisonNode( |
| 6164 catch_pos, Token::kIS, exception_var, exception_type); | 6113 catch_pos, Token::kIS, exception_var, exception_type); |
| 6165 current_block_->statements->Add( | 6114 current_block_->statements->Add( |
| 6166 new IfNode(catch_pos, type_cond_expr, catch_handler, NULL)); | 6115 new IfNode(catch_pos, type_cond_expr, catch_handler, NULL)); |
| 6167 } else { | 6116 } else { |
| 6168 // No exception type exists in the catch specifier so execute the | 6117 // No exception type exists in the catch specifier so execute the |
| 6169 // catch handler code unconditionally. | 6118 // catch handler code unconditionally. |
| 6170 current_block_->statements->Add(catch_handler); | 6119 current_block_->statements->Add(catch_handler); |
| 6171 generic_catch_seen = true; | 6120 generic_catch_seen = true; |
| 6172 } | 6121 } |
| 6173 catch_clause = CloseBlock(); | 6122 SequenceNode* catch_clause = CloseBlock(); |
| 6174 | 6123 |
| 6175 // Add this individual catch handler to the catch handlers list. | 6124 // Add this individual catch handler to the catch handlers list. |
| 6176 current_block_->statements->Add(catch_clause); | 6125 current_block_->statements->Add(catch_clause); |
| 6177 } | 6126 } |
| 6178 catch_handler_list = CloseBlock(); | 6127 catch_handler_list = CloseBlock(); |
| 6179 TryBlocks* inner_try_block = PopTryBlock(); | 6128 TryBlocks* inner_try_block = PopTryBlock(); |
| 6180 | 6129 |
| 6181 // Finally parse the 'finally' block. | 6130 // Finally parse the 'finally' block. |
| 6182 SequenceNode* finally_block = NULL; | 6131 SequenceNode* finally_block = NULL; |
| 6183 if (CurrentToken() == Token::kFINALLY) { | 6132 if (CurrentToken() == Token::kFINALLY) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 6202 if (!generic_catch_seen) { | 6151 if (!generic_catch_seen) { |
| 6203 // No generic catch handler exists so execute this finally block | 6152 // No generic catch handler exists so execute this finally block |
| 6204 // before rethrowing the exception. | 6153 // before rethrowing the exception. |
| 6205 finally_block = ParseFinallyBlock(); | 6154 finally_block = ParseFinallyBlock(); |
| 6206 catch_handler_list->Add(finally_block); | 6155 catch_handler_list->Add(finally_block); |
| 6207 tokens_iterator_.SetCurrentPosition(finally_pos); | 6156 tokens_iterator_.SetCurrentPosition(finally_pos); |
| 6208 } | 6157 } |
| 6209 finally_block = ParseFinallyBlock(); | 6158 finally_block = ParseFinallyBlock(); |
| 6210 } else { | 6159 } else { |
| 6211 if (!catch_seen) { | 6160 if (!catch_seen) { |
| 6212 ErrorMsg("'catch' or 'finally' expected"); | 6161 ErrorMsg("catch or finally clause expected"); |
| 6213 } | 6162 } |
| 6214 } | 6163 } |
| 6215 | 6164 |
| 6216 if (!generic_catch_seen) { | 6165 if (!generic_catch_seen) { |
| 6217 // No generic catch handler exists so rethrow the exception so that | 6166 // No generic catch handler exists so rethrow the exception so that |
| 6218 // the next catch handler can deal with it. | 6167 // the next catch handler can deal with it. |
| 6219 catch_handler_list->Add( | 6168 catch_handler_list->Add( |
| 6220 new ThrowNode(handler_pos, | 6169 new ThrowNode(handler_pos, |
| 6221 new LoadLocalNode(handler_pos, catch_excp_var), | 6170 new LoadLocalNode(handler_pos, catch_excp_var), |
| 6222 new LoadLocalNode(handler_pos, catch_trace_var))); | 6171 new LoadLocalNode(handler_pos, catch_trace_var))); |
| (...skipping 3523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9746 void Parser::SkipQualIdent() { | 9695 void Parser::SkipQualIdent() { |
| 9747 ASSERT(IsIdentifier()); | 9696 ASSERT(IsIdentifier()); |
| 9748 ConsumeToken(); | 9697 ConsumeToken(); |
| 9749 if (CurrentToken() == Token::kPERIOD) { | 9698 if (CurrentToken() == Token::kPERIOD) { |
| 9750 ConsumeToken(); // Consume the kPERIOD token. | 9699 ConsumeToken(); // Consume the kPERIOD token. |
| 9751 ExpectIdentifier("identifier expected after '.'"); | 9700 ExpectIdentifier("identifier expected after '.'"); |
| 9752 } | 9701 } |
| 9753 } | 9702 } |
| 9754 | 9703 |
| 9755 } // namespace dart | 9704 } // namespace dart |
| OLD | NEW |