Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index 7829fd6649a6beabf94128613d149f589b16b56b..778a338d6c6714bc5b28ccd343b358d368ac2a85 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -71,6 +71,7 @@ DEFINE_FLAG(bool, |
assert_initializer, |
false, |
"Allow asserts in initializer lists."); |
+DEFINE_FLAG(bool, assert_message, false, "Allow message in assert statements"); |
DECLARE_FLAG(bool, profile_vm); |
DECLARE_FLAG(bool, trace_service); |
@@ -9189,6 +9190,24 @@ AstNode* Parser::MakeStaticCall(const String& cls_name, |
} |
+AstNode* Parser::MakeAssertCall(TokenPosition begin, |
+ TokenPosition end, |
+ AstNode* message) { |
+ ArgumentListNode* arguments = new (Z) ArgumentListNode(begin); |
+ arguments->Add(new (Z) LiteralNode( |
+ begin, Integer::ZoneHandle(Z, Integer::New(begin.Pos())))); |
+ arguments->Add(new (Z) LiteralNode( |
+ end, Integer::ZoneHandle(Z, Integer::New(end.Pos())))); |
+ if (message == NULL) { |
+ message = new (Z) LiteralNode(end, Instance::ZoneHandle(Z)); |
+ } |
+ arguments->Add(message); |
+ return MakeStaticCall(Symbols::AssertionError(), |
+ Library::PrivateCoreLibName(Symbols::ThrowNew()), |
+ arguments); |
+} |
+ |
+ |
AstNode* Parser::ParseAssertStatement(bool is_const) { |
TRACE_PARSER("ParseAssertStatement"); |
ConsumeToken(); // Consume assert keyword. |
@@ -9196,6 +9215,10 @@ AstNode* Parser::ParseAssertStatement(bool is_const) { |
const TokenPosition condition_pos = TokenPos(); |
if (!I->asserts()) { |
SkipExpr(); |
+ if (FLAG_assert_message && CurrentToken() == Token::kCOMMA) { |
+ ConsumeToken(); |
+ SkipExpr(); |
+ } |
ExpectToken(Token::kRPAREN); |
return NULL; |
} |
@@ -9205,23 +9228,36 @@ AstNode* Parser::ParseAssertStatement(bool is_const) { |
"initializer assert expression must be compile time constant."); |
} |
const TokenPosition condition_end = TokenPos(); |
+ AstNode* message = NULL; |
+ TokenPosition message_pos = TokenPosition::kNoSource; |
+ if (FLAG_assert_message && CurrentToken() == Token::kCOMMA) { |
+ ConsumeToken(); |
+ message_pos = TokenPos(); |
+ message = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); |
+ if (is_const && !message->IsPotentiallyConst()) { |
+ ReportError( |
+ message_pos, |
+ "initializer assert expression must be compile time constant."); |
+ } |
+ } |
ExpectToken(Token::kRPAREN); |
- ArgumentListNode* arguments = new (Z) ArgumentListNode(condition_pos); |
- 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)))); |
- AstNode* assert_throw = MakeStaticCall( |
- Symbols::AssertionError(), |
- Library::PrivateCoreLibName(is_const ? Symbols::CheckConstAssertion() |
- : Symbols::CheckAssertion()), |
- arguments); |
- |
- return assert_throw; |
+ if (!is_const) { |
+ // Check for being a function if not const. |
+ ArgumentListNode* arguments = new (Z) ArgumentListNode(condition_pos); |
+ arguments->Add(condition); |
+ condition = MakeStaticCall( |
+ Symbols::AssertionError(), |
+ Library::PrivateCoreLibName(Symbols::CheckAssertion()), arguments); |
+ } |
+ AstNode* not_condition = |
+ new (Z) UnaryOpNode(condition_pos, Token::kNOT, condition); |
+ AstNode* assert_throw = MakeAssertCall(condition_pos, condition_end, message); |
+ return new (Z) |
+ IfNode(condition_pos, not_condition, |
+ NodeAsSequenceNode((message == NULL) ? condition_pos : message_pos, |
+ assert_throw, NULL), |
+ NULL); |
} |