| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 9873)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -6264,6 +6264,30 @@
|
| ErrorMsg("identifier or [ expected after ..");
|
| }
|
| expr = ParseSelectors(load_cascade_receiver, true);
|
| +
|
| + // Assignments after a cascade are part of the cascade. The
|
| + // assigned expression must not contain cascades.
|
| + if (Token::IsAssignmentOperator(CurrentToken())) {
|
| + Token::Kind assignment_op = CurrentToken();
|
| + const intptr_t assignment_pos = TokenPos();
|
| + ConsumeToken();
|
| + AstNode* right_expr = ParseExpr(kAllowConst, kNoCascades);
|
| + AstNode* left_expr = expr;
|
| + if (assignment_op != Token::kASSIGN) {
|
| + // Compound assignment: store inputs with side effects into
|
| + // temporary locals.
|
| + left_expr = PrepareCompoundAssignmentNodes(&expr);
|
| + }
|
| + right_expr =
|
| + ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
|
| + AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr);
|
| + if (assign_expr == NULL) {
|
| + ErrorMsg(assignment_pos,
|
| + "left hand side of '%s' is not assignable",
|
| + Token::Str(assignment_op));
|
| + }
|
| + expr = assign_expr;
|
| + }
|
| current_block_->statements->Add(expr);
|
| }
|
| // Result of the cascade is the receiver.
|
| @@ -6293,7 +6317,7 @@
|
| if (require_compiletime_const && (assignment_op != Token::kASSIGN)) {
|
| ErrorMsg(right_expr_pos, "expression must be a compile time constant");
|
| }
|
| - AstNode* right_expr = ParseExpr(require_compiletime_const, kConsumeCascades);
|
| + AstNode* right_expr = ParseExpr(require_compiletime_const, consume_cascades);
|
| AstNode* left_expr = expr;
|
| if (assignment_op != Token::kASSIGN) {
|
| // Compound assignment: store inputs with side effects into temp. locals.
|
| @@ -6517,32 +6541,6 @@
|
| }
|
|
|
|
|
| -AstNode* Parser::ParseInstanceFieldAccess(AstNode* receiver,
|
| - const String& field_name,
|
| - bool consume_cascades) {
|
| - TRACE_PARSER("ParseInstanceFieldAccess");
|
| - AstNode* access = NULL;
|
| - const intptr_t call_pos = TokenPos();
|
| - if (Token::IsAssignmentOperator(CurrentToken())) {
|
| - Token::Kind assignment_op = CurrentToken();
|
| - ConsumeToken();
|
| - AstNode* value = ParseExpr(kAllowConst, consume_cascades);
|
| - AstNode* load_access =
|
| - new InstanceGetterNode(call_pos, receiver, field_name);
|
| - AstNode* left_load_access = load_access;
|
| - if (assignment_op != Token::kASSIGN) {
|
| - // Compound assignment: store inputs with side effects into temp. locals.
|
| - left_load_access = PrepareCompoundAssignmentNodes(&load_access);
|
| - }
|
| - value = ExpandAssignableOp(call_pos, assignment_op, load_access, value);
|
| - access = CreateAssignmentNode(left_load_access, value);
|
| - } else {
|
| - access = CallGetter(call_pos, receiver, field_name);
|
| - }
|
| - return access;
|
| -}
|
| -
|
| -
|
| AstNode* Parser::GenerateStaticFieldLookup(const Field& field,
|
| intptr_t ident_pos) {
|
| // If the static field has an initializer, initialize the field at compile
|
| @@ -6574,7 +6572,7 @@
|
| const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name));
|
| Function& func = Function::ZoneHandle();
|
| if (Token::IsAssignmentOperator(CurrentToken())) {
|
| - Token::Kind assignment_op = CurrentToken();
|
| + // Make sure an assignment is legal.
|
| if (field.IsNull()) {
|
| // No field, check if we have an explicit setter function.
|
| const String& setter_name =
|
| @@ -6590,23 +6588,16 @@
|
| // No field or explicit setter function, this is an error.
|
| ErrorMsg(ident_pos, "unknown static field '%s'",
|
| field_name.ToCString());
|
| - return access;
|
| }
|
| - }
|
| - ConsumeToken();
|
| - AstNode* value = ParseExpr(kAllowConst, consume_cascades);
|
| - AstNode* load_access = NULL;
|
| - if (field.IsNull()) {
|
| - // No field found, we must have at least a setter function defined.
|
| - ASSERT(!func.IsNull());
|
| +
|
| // Explicit setter function for the field found, field does not exist.
|
| // Create a getter node first in case it is needed. If getter node
|
| // is used as part of, e.g., "+=", and the explicit getter does not
|
| // exist, and error will be reported by the code generator.
|
| - load_access = new StaticGetterNode(call_pos,
|
| - NULL,
|
| - Class::ZoneHandle(cls.raw()),
|
| - String::ZoneHandle(field_name.raw()));
|
| + access = new StaticGetterNode(call_pos,
|
| + NULL,
|
| + Class::ZoneHandle(cls.raw()),
|
| + String::ZoneHandle(field_name.raw()));
|
| } else {
|
| // Field exists.
|
| if (field.is_final()) {
|
| @@ -6615,12 +6606,9 @@
|
| ErrorMsg(ident_pos,
|
| "field '%s' is const static, cannot assign to it",
|
| field_name.ToCString());
|
| - return access;
|
| }
|
| - load_access = GenerateStaticFieldLookup(field, TokenPos());
|
| + access = GenerateStaticFieldLookup(field, TokenPos());
|
| }
|
| - value = ExpandAssignableOp(call_pos, assignment_op, load_access, value);
|
| - access = CreateAssignmentNode(load_access, value);
|
| } else { // Not Token::IsAssignmentOperator(CurrentToken()).
|
| if (field.IsNull()) {
|
| // No field, check if we have an explicit getter function.
|
| @@ -6641,7 +6629,6 @@
|
| // No field or explicit getter function, this is an error.
|
| ErrorMsg(ident_pos,
|
| "unknown static field '%s'", field_name.ToCString());
|
| - return access;
|
| }
|
| access = CreateImplicitClosureNode(func, call_pos, NULL);
|
| } else {
|
| @@ -6652,7 +6639,7 @@
|
| field_name);
|
| }
|
| } else {
|
| - return GenerateStaticFieldLookup(field, TokenPos());
|
| + access = GenerateStaticFieldLookup(field, TokenPos());
|
| }
|
| }
|
| return access;
|
| @@ -6746,7 +6733,7 @@
|
| }
|
| if (cls.IsNull()) {
|
| // Instance field access.
|
| - selector = ParseInstanceFieldAccess(left, *ident, !is_cascade);
|
| + selector = CallGetter(ident_pos, left, *ident);
|
| } else {
|
| // Static field access.
|
| selector =
|
| @@ -8632,10 +8619,10 @@
|
| }
|
|
|
|
|
| -void Parser::SkipPostfixExpr() {
|
| - SkipPrimary();
|
| +void Parser::SkipSelectors() {
|
| while (true) {
|
| - if (CurrentToken() == Token::kPERIOD) {
|
| + if ((CurrentToken() == Token::kPERIOD) ||
|
| + (CurrentToken() == Token::kCASCADE)) {
|
| ConsumeToken();
|
| ExpectIdentifier("identifier expected");
|
| } else if (CurrentToken() == Token::kLBRACK) {
|
| @@ -8648,6 +8635,11 @@
|
| break;
|
| }
|
| }
|
| +}
|
| +
|
| +void Parser::SkipPostfixExpr() {
|
| + SkipPrimary();
|
| + SkipSelectors();
|
| if (IsIncrementOperator(CurrentToken())) {
|
| ConsumeToken();
|
| }
|
| @@ -8688,6 +8680,9 @@
|
|
|
| void Parser::SkipExpr() {
|
| SkipConditionalExpr();
|
| + if (CurrentToken() == Token::kCASCADE) {
|
| + SkipSelectors();
|
| + }
|
| if (Token::IsAssignmentOperator(CurrentToken())) {
|
| ConsumeToken();
|
| SkipExpr();
|
|
|