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

Unified Diff: runtime/vm/parser.cc

Issue 1180903002: null-aware operators in the VM (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: updating test and status files Created 5 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/scanner.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 1abb8621a1bd8e41ee89bae504aa43693551f148..387bb6033014c950f0121eba5fe6521c72bb89f5 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -2979,8 +2979,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);
}
@@ -7136,9 +7135,9 @@ AstNode* Parser::LoadReceiver(intptr_t token_pos) {
}
-AstNode* Parser::CallGetter(intptr_t token_pos,
- AstNode* object,
- const String& name) {
+InstanceGetterNode* Parser::CallGetter(intptr_t token_pos,
+ AstNode* object,
+ const String& name) {
return new(Z) InstanceGetterNode(token_pos, object, name);
}
@@ -10141,7 +10140,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())) {
@@ -10191,12 +10190,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.
@@ -10279,9 +10272,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)) {
@@ -10339,6 +10329,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",
@@ -10394,7 +10386,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;
@@ -10457,13 +10449,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(Z) BinaryOpNode(rhs->token_pos(),
+ Token::kIFNULL,
+ original,
+ modified_assign);
}
return result;
}
@@ -10645,7 +10649,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();
@@ -10852,11 +10856,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);
}
@@ -11002,7 +11011,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();
@@ -11011,7 +11023,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' "
@@ -11029,6 +11041,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().
@@ -11043,10 +11067,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.
@@ -11063,9 +11088,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()) {
@@ -11149,7 +11178,8 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
}
selector = ParseInstanceCall(LoadReceiver(primary_pos),
func_name,
- primary_pos);
+ primary_pos,
+ false /* is_conditional */);
}
} else if (primary_node->primary().IsString()) {
// Primary is an unresolved name.
@@ -11165,7 +11195,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 /* is_conditional */);
}
} else if (primary_node->primary().IsTypeParameter()) {
const String& name = String::ZoneHandle(Z,
@@ -11180,7 +11211,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 /* is_conditional */);
}
} else if (primary_node->primary().IsClass()) {
const Class& type_class = Class::Cast(primary_node->primary());
@@ -13102,6 +13134,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());
}
@@ -13388,7 +13422,8 @@ void Parser::SkipSelectors() {
} else {
ExpectIdentifier("identifier or [ expected after ..");
}
- } else if (current_token == Token::kPERIOD) {
+ } else if ((current_token == Token::kPERIOD) ||
+ (current_token == Token::kQM_PERIOD)) {
ConsumeToken();
ExpectIdentifier("identifier expected");
} else if (current_token == Token::kLBRACK) {
@@ -13426,7 +13461,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))) {
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/scanner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698