Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index c90263909dc9b3c5aedec1d54b889f740be59732..bb7921e5e9f3d12792f03ef387197a94f9a3308a 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -52,6 +52,8 @@ DEFINE_FLAG(bool, warn_super, false, |
"Warning if super initializer not last in initializer list."); |
DEFINE_FLAG(bool, await_is_keyword, false, |
"await and yield are treated as proper keywords in synchronous code."); |
+DEFINE_FLAG(bool, assert_initializer, false, |
+ "Allow asserts in initializer lists."); |
DECLARE_FLAG(bool, profile_vm); |
DECLARE_FLAG(bool, trace_service); |
@@ -2591,6 +2593,9 @@ AstNode* Parser::ParseInitializer(const Class& cls, |
GrowableArray<Field*>* initialized_fields) { |
TRACE_PARSER("ParseInitializer"); |
const TokenPosition field_pos = TokenPos(); |
+ if (FLAG_assert_initializer && CurrentToken() == Token::kASSERT) { |
hausner
2016/08/15 20:54:26
Extra parens around the == expression.
|
+ return ParseAssertStatement(current_function().is_const()); |
+ } |
if (CurrentToken() == Token::kTHIS) { |
ConsumeToken(); |
ExpectToken(Token::kPERIOD); |
@@ -2880,7 +2885,9 @@ void Parser::ParseInitializers(const Class& cls, |
AstNode* init_statement = |
ParseInitializer(cls, receiver, initialized_fields); |
super_init_is_last = false; |
- current_block_->statements->Add(init_statement); |
+ if (init_statement != NULL) { |
+ current_block_->statements->Add(init_statement); |
+ } |
} |
} while (CurrentToken() == Token::kCOMMA); |
} |
@@ -3591,6 +3598,10 @@ void Parser::SkipInitializers() { |
} |
CheckToken(Token::kLPAREN); |
SkipToMatchingParenthesis(); |
+ } else if (FLAG_assert_initializer && CurrentToken() == Token::kASSERT) { |
hausner
2016/08/15 20:54:26
Extra parens around the == expression.
Lasse Reichstein Nielsen
2016/08/23 07:05:30
Done.
|
+ ConsumeToken(); |
+ CheckToken(Token::kLPAREN); |
+ SkipToMatchingParenthesis(); |
} else { |
SkipIf(Token::kTHIS); |
SkipIf(Token::kPERIOD); |
@@ -9194,7 +9205,7 @@ AstNode* Parser::MakeStaticCall(const String& cls_name, |
} |
-AstNode* Parser::ParseAssertStatement() { |
+AstNode* Parser::ParseAssertStatement(bool is_const) { |
TRACE_PARSER("ParseAssertStatement"); |
ConsumeToken(); // Consume assert keyword. |
ExpectToken(Token::kLPAREN); |
@@ -9205,18 +9216,36 @@ AstNode* Parser::ParseAssertStatement() { |
return NULL; |
} |
AstNode* condition = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); |
+ if (is_const && !condition->IsPotentiallyConst()) { |
+ ReportError(condition_pos, |
+ "initializer assert expression must be compile time constant."); |
+ } |
const TokenPosition condition_end = TokenPos(); |
ExpectToken(Token::kRPAREN); |
+ // Reuse the _AssertionError._checkAssertion function for const calls as well, |
+ // but ensure that the value is a bool. |
Lasse Reichstein Nielsen
2016/07/07 12:48:41
Another option is to have a separate function that
hausner
2016/08/15 20:54:26
Maybe option 2 is cleaner. I'd prefer a separate f
Lasse Reichstein Nielsen
2016/08/23 07:05:31
Will do.
|
ArgumentListNode* arguments = new(Z) ArgumentListNode(condition_pos); |
- arguments->Add(condition); |
+ if (is_const) { |
+ arguments->Add(new(Z) LiteralNode(condition_pos, Bool::False())); |
hausner
2016/08/15 20:54:26
I don't see a bool parameter in _AssertionError._c
Lasse Reichstein Nielsen
2016/08/23 07:05:31
Since I already checked the condition in the `IfNo
|
+ } else { |
+ arguments->Add(condition); |
+ } |
arguments->Add(new(Z) LiteralNode(condition_pos, |
Integer::ZoneHandle(Z, Integer::New(condition_pos.value(), Heap::kOld)))); |
arguments->Add(new(Z) LiteralNode(condition_end, |
Integer::ZoneHandle(Z, Integer::New(condition_end.value(), Heap::kOld)))); |
- return MakeStaticCall(Symbols::AssertionError(), |
- Library::PrivateCoreLibName(Symbols::CheckAssertion()), |
- arguments); |
+ AstNode* assert_throw = MakeStaticCall(Symbols::AssertionError(), |
+ Library::PrivateCoreLibName(Symbols::CheckAssertion()), |
+ arguments); |
+ |
+ if (!is_const) return assert_throw; |
+ condition = new(Z) UnaryOpNode(condition_pos, Token::kNOT, condition); |
+ return new(Z) IfNode( |
+ condition_pos, |
+ condition, |
hausner
2016/08/15 20:54:26
I don't think you can use the 'condition' expressi
Lasse Reichstein Nielsen
2016/08/23 07:05:31
I don't, as explained above.
|
+ NodeAsSequenceNode(condition_pos, assert_throw, NULL), |
+ NULL); |
} |