Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index d3b62f69fb59dda151d5db756e868abd91a19172..b0981d3a67eb8a5331cf70087b2175ed7a93ccf2 100644 |
| --- a/runtime/vm/parser.cc |
| +++ b/runtime/vm/parser.cc |
| @@ -70,6 +70,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); |
| @@ -9164,32 +9165,91 @@ AstNode* Parser::ParseAssertStatement(bool is_const) { |
| const TokenPosition condition_pos = TokenPos(); |
| if (!I->asserts()) { |
| SkipExpr(); |
| + if (FLAG_assert_message && CurrentToken() == Token::kCOMMA) { |
|
regis
2016/12/13 23:26:51
No parens?
hausner
2016/12/14 16:59:35
Added parens. The formatter was happy without them
|
| + ConsumeToken(); |
| + SkipExpr(); |
| + } |
| ExpectToken(Token::kRPAREN); |
| return NULL; |
| } |
| - AstNode* condition = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); |
| + |
| + BoolScope saved_seen_await(&parsed_function()->have_seen_await_expr_, false); |
| + AstNode* condition = ParseExpr(kAllowConst, kConsumeCascades); |
| if (is_const && !condition->IsPotentiallyConst()) { |
| ReportError(condition_pos, |
| "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 = ParseExpr(kAllowConst, kConsumeCascades); |
| + if (is_const && !message->IsPotentiallyConst()) { |
| + ReportError( |
| + message_pos, |
| + "initializer assert expression must be compile time constant."); |
| + } |
| + } |
| ExpectToken(Token::kRPAREN); |
| + 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); |
| + |
| + // Build call to _AsertionError._throwNew(start, end, message) |
| 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)))); |
| + Integer::ZoneHandle(Z, Integer::New(condition_pos.Pos())))); |
| arguments->Add(new (Z) LiteralNode( |
| condition_end, |
| - Integer::ZoneHandle(Z, Integer::New(condition_end.value(), Heap::kOld)))); |
| + Integer::ZoneHandle(Z, Integer::New(condition_end.Pos())))); |
| + if (message == NULL) { |
| + message = new (Z) LiteralNode(condition_end, Instance::ZoneHandle(Z)); |
| + } |
| + arguments->Add(message); |
| AstNode* assert_throw = MakeStaticCall( |
| Symbols::AssertionError(), |
| - Library::PrivateCoreLibName(is_const ? Symbols::CheckConstAssertion() |
| - : Symbols::CheckAssertion()), |
| - arguments); |
| + Library::PrivateCoreLibName(Symbols::ThrowNew()), arguments); |
| - return assert_throw; |
| + AstNode* assertion_check = NULL; |
| + if (parsed_function()->have_seen_await()) { |
| + // The await transformation must be done manually because assertions |
| + // are parsed as statements, not expressions. Thus, we need to check |
| + // explicitely whether the arguments contain await operators. (Note that |
| + // we must not parse the arguments with ParseAwaitableExpr(). In the |
| + // corner case of assert(await a, await b), this would create two |
| + // sibling scopes containing the temporary values for a and b. Both |
| + // values would be allocated in the same internal context variable.) |
| + // |
| + // Build !condition ? _AsertionError._throwNew(...) : null; |
| + // We need to use a conditional expression because the await transformer |
| + // cannot transform if statements. |
| + assertion_check = new (Z) ConditionalExprNode( |
| + condition_pos, not_condition, assert_throw, |
| + new (Z) LiteralNode(condition_pos, Object::null_instance())); |
| + OpenBlock(); |
| + AwaitTransformer at(current_block_->statements, async_temp_scope_); |
| + AstNode* transformed_assertion = at.Transform(assertion_check); |
| + SequenceNode* preamble = CloseBlock(); |
| + preamble->Add(transformed_assertion); |
| + assertion_check = preamble; |
| + } else { |
| + // Build if (!condtition) _AsertionError._throwNew(...) |
|
regis
2016/12/13 23:26:51
condtition -> condition
hausner
2016/12/14 16:59:35
Done.
|
| + assertion_check = new (Z) |
| + IfNode(condition_pos, not_condition, |
| + NodeAsSequenceNode(condition_pos, assert_throw, NULL), NULL); |
| + } |
| + return assertion_check; |
| } |