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

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: Implement remainder of null-aware operators 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
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))) {

Powered by Google App Engine
This is Rietveld 408576698