Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: runtime/vm/parser.cc

Issue 11051031: Add catchless catch clauses (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/language/try_catch_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/language/try_catch_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698