Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index 0307c908c9111041103b55eab058e4c044f9e85e..9771922da52a11c60ce06866f70ef8c7fc442d3c 100644 |
| --- a/runtime/vm/parser.cc |
| +++ b/runtime/vm/parser.cc |
| @@ -2978,8 +2978,7 @@ SequenceNode* Parser::ParseConstructor(const Function& func, |
| for (int i = 2; i < ctor_args->length(); i++) { |
| AstNode* arg = ctor_args->NodeAt(i); |
| if (!IsSimpleLocalOrLiteralNode(arg)) { |
| - LocalVariable* temp = |
| - CreateTempConstVariable(arg->token_pos(), "sca"); |
| + LocalVariable* temp = CreateTempConstVariable(arg->token_pos(), "sca"); |
| AstNode* save_temp = new StoreLocalNode(arg->token_pos(), temp, arg); |
| ctor_args->SetNodeAt(i, save_temp); |
| } |
| @@ -7129,7 +7128,7 @@ AstNode* Parser::LoadReceiver(intptr_t token_pos) { |
| } |
| -AstNode* Parser::CallGetter(intptr_t token_pos, |
| +InstanceGetterNode* Parser::CallGetter(intptr_t token_pos, |
| AstNode* object, |
| const String& name) { |
|
srdjan
2015/06/17 18:15:36
Fix indentation.
hausner
2015/06/17 22:24:57
Done.
|
| return new(Z) InstanceGetterNode(token_pos, object, name); |
| @@ -10134,7 +10133,7 @@ AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos, |
| AstNode* Parser::ParseBinaryExpr(int min_preced) { |
| TRACE_PARSER("ParseBinaryExpr"); |
| - ASSERT(min_preced >= Token::Precedence(Token::kOR)); |
| + ASSERT(min_preced >= Token::Precedence(Token::kIFNULL)); |
| AstNode* left_operand = ParseUnaryExpr(); |
| if (left_operand->IsPrimaryNode() && |
| (left_operand->AsPrimaryNode()->IsSuper())) { |
| @@ -10184,12 +10183,6 @@ AstNode* Parser::ParseBinaryExpr(int min_preced) { |
| || Token::IsTypeTestOperator(op_kind) |
| || Token::IsTypeCastOperator(op_kind) |
| || Token::IsEqualityOperator(op_kind)) { |
| - if (Token::IsTypeTestOperator(op_kind) || |
| - Token::IsTypeCastOperator(op_kind)) { |
| - if (!right_operand->AsTypeNode()->type().IsInstantiated()) { |
| - EnsureExpressionTemp(); |
| - } |
| - } |
| left_operand = new(Z) ComparisonNode( |
| op_pos, op_kind, left_operand, right_operand); |
| break; // Equality and relational operators cannot be chained. |
| @@ -10272,9 +10265,6 @@ AstNode* Parser::OptimizeBinaryOpNode(intptr_t op_pos, |
| } |
| } |
| } |
| - if ((binary_op == Token::kAND) || (binary_op == Token::kOR)) { |
| - EnsureExpressionTemp(); |
| - } |
| if (binary_op == Token::kBIT_AND) { |
| // Normalize so that rhs is a literal if any is. |
| if ((rhs_literal == NULL) && (lhs_literal != NULL)) { |
| @@ -10332,6 +10322,8 @@ AstNode* Parser::ExpandAssignableOp(intptr_t op_pos, |
| return new(Z) BinaryOpNode(op_pos, Token::kBIT_AND, lhs, rhs); |
| case Token::kASSIGN_XOR: |
| return new(Z) BinaryOpNode(op_pos, Token::kBIT_XOR, lhs, rhs); |
| + case Token::kASSIGN_COND: |
| + return new(Z) BinaryOpNode(op_pos, Token::kIFNULL, lhs, rhs); |
| default: |
| ReportError(op_pos, |
| "internal error: ExpandAssignableOp '%s' unimplemented", |
| @@ -10387,7 +10379,7 @@ LetNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) { |
| receiver = new(Z) LoadLocalNode(token_pos, t0); |
| } |
| *expr = new(Z) InstanceGetterNode( |
| - token_pos, receiver, getter->field_name()); |
| + token_pos, receiver, getter->field_name(), getter->is_conditional()); |
| return result; |
| } |
| return result; |
| @@ -10450,13 +10442,25 @@ AstNode* Parser::CreateAssignmentNode(AstNode* original, |
| InvocationMirror::kLocalVar : InvocationMirror::kSetter, |
| NULL)); // No existing function. |
| result = let_node; |
| - } else if (result->IsStoreIndexedNode() || |
| - result->IsInstanceSetterNode() || |
| - result->IsStaticSetterNode() || |
| - result->IsStoreStaticFieldNode() || |
| - result->IsStoreLocalNode()) { |
| - // Ensure that the expression temp is allocated for nodes that may need it. |
| - EnsureExpressionTemp(); |
| + } |
| + // The compound assignment operator a ??= b is different from other |
| + // a op= b assignments. If a is non-null, the assignment to a must be |
| + // dropped: |
| + // normally: a op= b ==> a = a op b |
| + // however: a ??= b ==> a ?? (a = b) |
| + // Therefore, we need to transform a = (a ?? b) into a ?? (a = b) |
| + if (rhs->IsBinaryOpNode() && |
| + (rhs->AsBinaryOpNode()->kind() == Token::kIFNULL)) { |
| + BinaryOpNode* ifnull = rhs->AsBinaryOpNode(); |
| + AstNode* modified_assign = |
| + CreateAssignmentNode(ifnull->left(), |
| + ifnull->right(), |
| + left_ident, |
| + left_pos); |
| + result = new BinaryOpNode(rhs->token_pos(), |
|
srdjan
2015/06/17 18:15:36
new (Z)
hausner
2015/06/17 22:24:57
Done.
|
| + Token::kIFNULL, |
| + original, |
| + modified_assign); |
| } |
| return result; |
| } |
| @@ -10638,7 +10642,7 @@ LiteralNode* Parser::ParseConstExpr() { |
| AstNode* Parser::ParseConditionalExpr() { |
| TRACE_PARSER("ParseConditionalExpr"); |
| const intptr_t expr_pos = TokenPos(); |
| - AstNode* expr = ParseBinaryExpr(Token::Precedence(Token::kOR)); |
| + AstNode* expr = ParseBinaryExpr(Token::Precedence(Token::kIFNULL)); |
| if (CurrentToken() == Token::kCONDITIONAL) { |
| EnsureExpressionTemp(); |
| ConsumeToken(); |
| @@ -10845,11 +10849,16 @@ AstNode* Parser::ParseStaticCall(const Class& cls, |
| AstNode* Parser::ParseInstanceCall(AstNode* receiver, |
| const String& func_name, |
| - intptr_t ident_pos) { |
| + intptr_t ident_pos, |
| + bool is_conditional) { |
| TRACE_PARSER("ParseInstanceCall"); |
| CheckToken(Token::kLPAREN); |
| ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst); |
| - return new(Z) InstanceCallNode(ident_pos, receiver, func_name, arguments); |
| + return new(Z) InstanceCallNode(ident_pos, |
| + receiver, |
| + func_name, |
| + arguments, |
| + is_conditional); |
| } |
| @@ -10995,7 +11004,10 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| AstNode* left = primary; |
| while (true) { |
| AstNode* selector = NULL; |
| - if (CurrentToken() == Token::kPERIOD) { |
| + if ((CurrentToken() == Token::kPERIOD) || |
| + (CurrentToken() == Token::kQM_PERIOD)) { |
| + // Unconditional or conditional property extraction or method call. |
| + bool is_conditional = CurrentToken() == Token::kQM_PERIOD; |
| ConsumeToken(); |
| if (left->IsPrimaryNode()) { |
| PrimaryNode* primary_node = left->AsPrimaryNode(); |
| @@ -11004,7 +11016,7 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| left = LoadClosure(primary_node); |
| } else if (primary_node->primary().IsTypeParameter()) { |
| if (ParsingStaticMember()) { |
| - const String& name = String::ZoneHandle(Z, |
| + const String& name = String::Handle(Z, |
| TypeParameter::Cast(primary_node->primary()).name()); |
| ReportError(primary_pos, |
| "cannot access type parameter '%s' " |
| @@ -11022,6 +11034,18 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| ClassFinalizer::kCanonicalize); |
| ASSERT(!type_parameter.IsMalformed()); |
| left = new(Z) TypeNode(primary->token_pos(), type_parameter); |
| + } else if (is_conditional && primary_node->primary().IsClass()) { |
| + // The left-hand side of ?. is interpreted as an expression |
| + // of type Type, not as a class literal. |
| + const Class& type_class = Class::Cast(primary_node->primary()); |
| + AbstractType& type = Type::ZoneHandle(Z, |
| + Type::New(type_class, TypeArguments::Handle(Z), |
| + primary_pos, Heap::kOld)); |
| + type ^= ClassFinalizer::FinalizeType( |
| + current_class(), type, ClassFinalizer::kCanonicalize); |
| + // Type may be malbounded, but not malformed. |
| + ASSERT(!type.IsMalformed()); |
| + left = new(Z) TypeNode(primary_pos, type); |
| } else { |
| // Super field access handled in ParseSuperFieldAccess(), |
| // super calls handled in ParseSuperCall(). |
| @@ -11036,10 +11060,11 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| if (left->IsPrimaryNode() && |
| left->AsPrimaryNode()->primary().IsClass()) { |
| // Static method call prefixed with class name. |
| + ASSERT(!is_conditional); |
| const Class& cls = Class::Cast(left->AsPrimaryNode()->primary()); |
| selector = ParseStaticCall(cls, *ident, ident_pos); |
| } else { |
| - selector = ParseInstanceCall(left, *ident, ident_pos); |
| + selector = ParseInstanceCall(left, *ident, ident_pos, is_conditional); |
| } |
| } else { |
| // Field access. |
| @@ -11056,9 +11081,13 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| } |
| if (cls.IsNull()) { |
| // Instance field access. |
| - selector = CallGetter(ident_pos, left, *ident); |
| + selector = new(Z) InstanceGetterNode(ident_pos, |
| + left, |
| + *ident, |
| + is_conditional); |
| } else { |
| // Static field access. |
| + ASSERT(!is_conditional); |
| selector = GenerateStaticFieldAccess(cls, *ident, ident_pos); |
| ASSERT(selector != NULL); |
| if (selector->IsLoadStaticFieldNode()) { |
| @@ -11142,7 +11171,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| } |
| selector = ParseInstanceCall(LoadReceiver(primary_pos), |
| func_name, |
| - primary_pos); |
| + primary_pos, |
| + false); |
|
srdjan
2015/06/17 18:15:36
Add comment what 'false' means:
false /* is_c
hausner
2015/06/17 22:24:57
Done.
|
| } |
| } else if (primary_node->primary().IsString()) { |
| // Primary is an unresolved name. |
| @@ -11158,7 +11188,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| // Treat as call to unresolved (instance) method. |
| selector = ParseInstanceCall(LoadReceiver(primary_pos), |
| name, |
| - primary_pos); |
| + primary_pos, |
| + false); |
| } |
| } else if (primary_node->primary().IsTypeParameter()) { |
| const String& name = String::ZoneHandle(Z, |
| @@ -11173,7 +11204,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
| // Treat as call to unresolved (instance) method. |
| selector = ParseInstanceCall(LoadReceiver(primary_pos), |
| name, |
| - primary_pos); |
| + primary_pos, |
| + false); |
| } |
| } else if (primary_node->primary().IsClass()) { |
| const Class& type_class = Class::Cast(primary_node->primary()); |
| @@ -13095,6 +13127,8 @@ AstNode* Parser::ParsePrimary() { |
| Token::CanBeOverloaded(CurrentToken()) || |
| (CurrentToken() == Token::kNE)) { |
| primary = ParseSuperOperator(); |
| + } else if (CurrentToken() == Token::kQM_PERIOD) { |
| + ReportError("super call or super getter may not use ?."); |
| } else { |
| primary = new(Z) PrimaryNode(super_pos, Symbols::Super()); |
| } |
| @@ -13419,7 +13453,7 @@ void Parser::SkipUnaryExpr() { |
| void Parser::SkipBinaryExpr() { |
| SkipUnaryExpr(); |
| - const int min_prec = Token::Precedence(Token::kOR); |
| + const int min_prec = Token::Precedence(Token::kIFNULL); |
| const int max_prec = Token::Precedence(Token::kMUL); |
| while (((min_prec <= Token::Precedence(CurrentToken())) && |
| (Token::Precedence(CurrentToken()) <= max_prec))) { |