| Index: dart/runtime/vm/parser.cc
|
| ===================================================================
|
| --- dart/runtime/vm/parser.cc (revision 29802)
|
| +++ dart/runtime/vm/parser.cc (working copy)
|
| @@ -1015,23 +1015,17 @@
|
| ident_pos,
|
| field,
|
| new LiteralNode(ident_pos, Object::transition_sentinel())));
|
| - // TODO(hausner): If evaluation of the field value throws an exception,
|
| - // we leave the field value as 'transition_sentinel', which is wrong.
|
| - // A second reference to the field later throws a circular dependency
|
| - // exception. The field should instead be set to null after an exception.
|
| - const String& init_name =
|
| - String::Handle(Symbols::New(String::Handle(
|
| - String::Concat(Symbols::InitPrefix(), String::Handle(field.name())))));
|
| + const String& init_name = String::Handle(
|
| + Symbols::New(String::Handle(String::Concat(
|
| + Symbols::InitPrefix(), String::Handle(field.name())))));
|
| const Function& init_function = Function::ZoneHandle(
|
| field_class.LookupStaticFunction(init_name));
|
| ASSERT(!init_function.IsNull());
|
| ArgumentListNode* arguments = new ArgumentListNode(expr_pos);
|
| StaticCallNode* init_call =
|
| new StaticCallNode(expr_pos, init_function, arguments);
|
| + initialize_field->Add(init_call);
|
|
|
| - initialize_field->Add(new StoreStaticFieldNode(ident_pos,
|
| - field,
|
| - init_call));
|
| AstNode* uninitialized_check =
|
| new IfNode(ident_pos, compare_uninitialized, initialize_field, NULL);
|
| current_block_->statements->Add(uninitialized_check);
|
| @@ -1057,10 +1051,96 @@
|
| OpenFunctionBlock(func);
|
| AddFormalParamsToScope(¶ms, current_block_->scope);
|
|
|
| - intptr_t expr_pos = func.token_pos();
|
| + // Move forward to the start of the initializer expression.
|
| + ExpectIdentifier("identifier expected");
|
| + ExpectToken(Token::kASSIGN);
|
| + intptr_t token_pos = TokenPos();
|
| +
|
| + // Synthesize a try-catch block to wrap the initializer expression.
|
| + LocalVariable* context_var =
|
| + current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
|
| + if (context_var == NULL) {
|
| + context_var = new LocalVariable(token_pos,
|
| + Symbols::SavedTryContextVar(),
|
| + Type::ZoneHandle(Type::DynamicType()));
|
| + current_block_->scope->AddVariable(context_var);
|
| + }
|
| + LocalVariable* catch_excp_var =
|
| + current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar());
|
| + if (catch_excp_var == NULL) {
|
| + catch_excp_var = new LocalVariable(token_pos,
|
| + Symbols::ExceptionVar(),
|
| + Type::ZoneHandle(Type::DynamicType()));
|
| + current_block_->scope->AddVariable(catch_excp_var);
|
| + }
|
| + LocalVariable* catch_trace_var =
|
| + current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar());
|
| + if (catch_trace_var == NULL) {
|
| + catch_trace_var = new LocalVariable(token_pos,
|
| + Symbols::StacktraceVar(),
|
| + Type::ZoneHandle(Type::DynamicType()));
|
| + current_block_->scope->AddVariable(catch_trace_var);
|
| + }
|
| +
|
| + OpenBlock(); // Start try block.
|
| AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
|
| - ReturnNode* return_node = new ReturnNode(expr_pos, expr);
|
| - current_block_->statements->Add(return_node);
|
| + const Field& field = Field::ZoneHandle(func.saved_static_field());
|
| + ASSERT(!field.is_const());
|
| + StoreStaticFieldNode* store = new StoreStaticFieldNode(field.token_pos(),
|
| + field,
|
| + expr);
|
| + current_block_->statements->Add(store);
|
| + SequenceNode* try_block = CloseBlock(); // End try block.
|
| +
|
| + OpenBlock(); // Start catch handler list.
|
| + SourceLabel* end_catch_label =
|
| + SourceLabel::New(token_pos, NULL, SourceLabel::kCatch);
|
| + current_block_->scope->AddLabel(end_catch_label);
|
| +
|
| + OpenBlock(); // Start catch clause.
|
| + AstNode* compare_transition_sentinel = new ComparisonNode(
|
| + token_pos,
|
| + Token::kEQ_STRICT,
|
| + new LoadStaticFieldNode(token_pos, field),
|
| + new LiteralNode(field.token_pos(), Object::transition_sentinel()));
|
| +
|
| + SequenceNode* store_null = new SequenceNode(token_pos, NULL);
|
| + store_null->Add(new StoreStaticFieldNode(
|
| + field.token_pos(),
|
| + field,
|
| + new LiteralNode(token_pos, Instance::ZoneHandle())));
|
| + AstNode* transition_sentinel_check =
|
| + new IfNode(token_pos, compare_transition_sentinel, store_null, NULL);
|
| + current_block_->statements->Add(transition_sentinel_check);
|
| +
|
| + current_block_->statements->Add(
|
| + new ThrowNode(token_pos,
|
| + new LoadLocalNode(token_pos, catch_excp_var),
|
| + new LoadLocalNode(token_pos, catch_trace_var)));
|
| + current_block_->statements->Add(
|
| + new JumpNode(token_pos, Token::kCONTINUE, end_catch_label));
|
| + SequenceNode* catch_clause = CloseBlock(); // End catch clause.
|
| +
|
| + current_block_->statements->Add(catch_clause);
|
| + SequenceNode* catch_handler_list = CloseBlock(); // End catch handler list.
|
| + CatchClauseNode* catch_block =
|
| + new CatchClauseNode(token_pos,
|
| + catch_handler_list,
|
| + Array::ZoneHandle(Object::empty_array().raw()),
|
| + context_var,
|
| + catch_excp_var,
|
| + catch_trace_var,
|
| + CatchClauseNode::kInvalidTryIndex,
|
| + false); // No stack trace needed.
|
| +
|
| + AstNode* try_catch_node = new TryCatchNode(token_pos,
|
| + try_block,
|
| + end_catch_label,
|
| + context_var,
|
| + catch_block,
|
| + NULL, // No finally block.
|
| + AllocateTryIndex());
|
| + current_block_->statements->Add(try_catch_node);
|
| return CloseBlock();
|
| }
|
|
|
| @@ -3307,7 +3387,6 @@
|
| Function& setter = Function::Handle();
|
| Field& class_field = Field::ZoneHandle();
|
| Instance& init_value = Instance::Handle();
|
| - intptr_t expr_pos = -1;
|
| while (true) {
|
| bool has_initializer = CurrentToken() == Token::kASSIGN;
|
| bool has_simple_literal = false;
|
| @@ -3332,7 +3411,6 @@
|
| (LookaheadToken(1) == Token::kSEMICOLON)) {
|
| has_simple_literal = IsSimpleLiteral(*field->type, &init_value);
|
| }
|
| - expr_pos = TokenPos();
|
| SkipExpr();
|
| } else {
|
| // Static const and static final fields must have an initializer.
|
| @@ -3377,13 +3455,12 @@
|
| getter.set_result_type(*field->type);
|
| members->AddFunction(getter);
|
|
|
| - // Create initializer function.
|
| - const Function& init_function = Function::ZoneHandle(
|
| - Function::NewStaticInitializer(*field->name,
|
| - *field->type,
|
| - current_class(),
|
| - expr_pos));
|
| - members->AddFunction(init_function);
|
| + // Create initializer function for non-const fields.
|
| + if (!class_field.is_const()) {
|
| + const Function& init_function = Function::ZoneHandle(
|
| + Function::NewStaticInitializer(class_field));
|
| + members->AddFunction(init_function);
|
| + }
|
| }
|
| }
|
|
|
| @@ -4493,7 +4570,6 @@
|
| if ((is_const || is_final) && (LookaheadToken(1) == Token::kSEMICOLON)) {
|
| has_simple_literal = IsSimpleLiteral(type, &field_value);
|
| }
|
| - const intptr_t expr_pos = TokenPos();
|
| SkipExpr();
|
| field.set_value(field_value);
|
| if (!has_simple_literal) {
|
| @@ -4511,12 +4587,11 @@
|
| top_level->functions.Add(getter);
|
|
|
| // Create initializer function.
|
| - const Function& init_function = Function::ZoneHandle(
|
| - Function::NewStaticInitializer(var_name,
|
| - type,
|
| - current_class(),
|
| - expr_pos));
|
| - top_level->functions.Add(init_function);
|
| + if (!field.is_const()) {
|
| + const Function& init_function = Function::ZoneHandle(
|
| + Function::NewStaticInitializer(field));
|
| + top_level->functions.Add(init_function);
|
| + }
|
| }
|
| } else if (is_final) {
|
| ErrorMsg(name_pos, "missing initializer for final or const variable");
|
| @@ -6742,7 +6817,6 @@
|
| // operator.
|
| bool catch_seen = false;
|
| bool generic_catch_seen = false;
|
| - SequenceNode* catch_handler_list = NULL;
|
| const intptr_t handler_pos = TokenPos();
|
| OpenBlock(); // Start the catch block sequence.
|
| current_block_->scope->AddLabel(end_catch_label);
|
| @@ -6866,7 +6940,7 @@
|
| // Add this individual catch handler to the catch handlers list.
|
| current_block_->statements->Add(catch_clause);
|
| }
|
| - catch_handler_list = CloseBlock();
|
| + SequenceNode* catch_handler_list = CloseBlock();
|
| TryBlocks* inner_try_block = PopTryBlock();
|
| const intptr_t try_index = inner_try_block->try_index();
|
| TryBlocks* outer_try_block = try_blocks_list_;
|
|
|