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

Unified Diff: runtime/vm/parser.cc

Issue 2574003003: Add optional message argument to assert statements in the VM. (Closed)
Patch Set: Update dart2js status file Created 4 years 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/code_generator.cc ('k') | runtime/vm/symbols.h » ('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 4ebafa283ba85f6787b024ad754c81440bd2552f..16d8ec20652c339b00f12a130a63fbb42c47817b 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)) {
+ 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 assertion condition being a function if not const.
+ ArgumentListNode* arguments = new (Z) ArgumentListNode(condition_pos);
+ arguments->Add(condition);
+ condition = MakeStaticCall(
+ Symbols::AssertionError(),
+ Library::PrivateCoreLibName(Symbols::EvaluateAssertion()), 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 (!condition) _AsertionError._throwNew(...)
+ assertion_check = new (Z)
+ IfNode(condition_pos, not_condition,
+ NodeAsSequenceNode(condition_pos, assert_throw, NULL), NULL);
+ }
+ return assertion_check;
}
« no previous file with comments | « runtime/vm/code_generator.cc ('k') | runtime/vm/symbols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698