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

Unified Diff: runtime/vm/ast_transformer.cc

Issue 447003003: Introduce await (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 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/ast_transformer.cc
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3645d1196d3acd7d2f22e63d24694519933f8310
--- /dev/null
+++ b/runtime/vm/ast_transformer.cc
@@ -0,0 +1,527 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/ast_transformer.h"
+
+#include "vm/parser.h"
+
+namespace dart {
+
hausner 2014/08/07 21:48:43 It would be nice to write up a few lines of commen
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+#define I Isolate::Current()
hausner 2014/08/07 21:48:42 It might be good to cache the current isolate in t
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+
+// Nodes that are unreachable from already parsed expressions.
+#define FOR_EACH_UNREACHABLE_NODE(V) \
+ V(Case) \
+ V(CatchClause) \
+ V(CloneContext) \
+ V(ClosureCall) \
+ V(DoWhile) \
+ V(If) \
+ V(InlinedFinally) \
+ V(For) \
+ V(Jump) \
+ V(LoadInstanceField) \
+ V(NativeBody) \
+ V(Primary) \
+ V(Return) \
+ V(Sequence) \
+ V(StoreInstanceField) \
+ V(Switch) \
+ V(TryCatch) \
+ V(While)
+
+#define DEFINE_UNREACHABLE(BaseName) \
+void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \
+ UNREACHABLE(); \
+}
+
+FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE)
+#undef DEFINE_UNREACHABLE
+
+
+void AwaitTransformer::Transform(AstNode* expr) {
+ expr->Visit(this);
+}
+
+
+LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
+ const String& cnt_str = String::Handle(
+ String::NewFormatted(
+ "%s%" Pd "", Symbols::AwaitTempVarPrefix().ToCString(), temp_cnt_));
hausner 2014/08/07 21:48:41 I'm not sure it makes sense to create a symbol for
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+ const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str));
+ ASSERT(!symbol.IsNull());
+ LocalVariable* await_tmp =
+ parsed_function_->await_temps_scope()->LookupVariable(symbol, false);
+ if (await_tmp == NULL) {
+ await_tmp = new (I) LocalVariable(
+ Scanner::kNoSourcePos,
+ symbol,
+ Type::ZoneHandle(I, Type::DynamicType()));
+ parsed_function_->await_temps_scope()->AddVariable(await_tmp);
+ }
+ return await_tmp;
+}
+
+
+LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
+ LocalVariable* tmp_var = EnsureCurrentTempVar();
+ preamble_->Add(new (I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
+ NextTempVar();
+ return tmp_var;
+}
+
+
+void AwaitTransformer::VisitLiteralNode(LiteralNode* node) {
+ result_ = new (I) LiteralNode(node->token_pos(), node->literal());
hausner 2014/08/07 21:48:43 Could you not just return the node given as a para
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+}
+
+
+void AwaitTransformer::VisitTypeNode(TypeNode* node) {
+ result_ = new (I) TypeNode(node->token_pos(), node->type());
+}
+
+
+
+void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
+ // Await transformation:
+ //
+ // :await_temp_var_X = <expr>;
+ // :result_param = :await_temp_var_X;
+ // if (:result_param is Future) {
+ // // :result_param.then(:async_op);
+ // }
+ // :await_temp_var_(X+1) = :result_param;
+
+ LocalVariable* async_op = preamble_->scope()->LookupVariable(
hausner 2014/08/07 21:48:42 LookupVariable() will search outer scopes, which i
Michael Lippautz (Google) 2014/08/08 18:12:17 I think LookupVariable() is right here. The scope
+ Symbols::AsyncOperation(), false);
+ ASSERT(async_op != NULL);
+ LocalVariable* result_param = preamble_->scope()->LookupVariable(
+ Symbols::AsyncOperationParam(), false);
+ ASSERT(result_param != NULL);
+
+ node->expr()->Visit(this);
+ preamble_->Add(new (I) StoreLocalNode(Scanner::kNoSourcePos,
+ result_param,
+ result_));
+ LoadLocalNode* load_result_param = new (I) LoadLocalNode(
+ Scanner::kNoSourcePos, result_param);
+ SequenceNode* is_future_branch = new (I) SequenceNode(
+ Scanner::kNoSourcePos, preamble_->scope());
+ ArgumentListNode* args = new (I) ArgumentListNode(Scanner::kNoSourcePos);
+ args->Add(new (I) LoadLocalNode(Scanner::kNoSourcePos, async_op));
+ // TODO(mlippautz): Once continuations are supported, just call .then().
+ // is_future_branch->Add(new (I) InstanceCallNode(
+ // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args));
+ is_future_branch->Add(new (I) ReturnNode(Scanner::kNoSourcePos));
hausner 2014/08/07 21:48:42 Instead of silently return null, maybe throw an ex
Michael Lippautz (Google) 2014/08/08 18:12:17 Done. I am not sure why the literal needs to be a
+ const Class& cls = Class::Handle(library_.LookupClass(
+ String::Handle(String::New("Future"))));
hausner 2014/08/07 21:48:42 We should probably have a predefined symbol for "F
Michael Lippautz (Google) 2014/08/08 18:12:17 Done. We already had a symbol.
+ const AbstractType& future_type = AbstractType::ZoneHandle(I,
+ cls.RareType());
+ ASSERT(!future_type.IsNull());
+ TypeNode* future_type_node = new (I) TypeNode(
+ Scanner::kNoSourcePos, future_type);
+ IfNode* is_future_if = new (I) IfNode(
+ Scanner::kNoSourcePos,
+ new (I) ComparisonNode(Scanner::kNoSourcePos,
+ Token::kIS,
+ load_result_param,
+ future_type_node),
+ is_future_branch,
+ NULL);
+ preamble_->Add(is_future_if);
+
+ // TODO(mlippautz): Jump target (label) should be added here.
+
+ LocalVariable* result = AddToPreambleNewTempVar(new (I) LoadLocalNode(
+ Scanner::kNoSourcePos, result_param));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+AstNode* AwaitTransformer::LazyTransform(const Token::Kind kind,
hausner 2014/08/07 21:48:42 How about renaming this parameter to logical_op or
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+ AstNode* new_left,
+ AstNode* right) {
+ ASSERT(kind == Token::kAND || kind == Token::kOR);
+ AstNode* result = NULL;
+ const Token::Kind compare_kind = (kind == Token::kAND) ?
+ Token::kEQ : Token::kNE;
+ SequenceNode* eval = new SequenceNode(
+ Scanner::kNoSourcePos, preamble_->scope());
+ SequenceNode* saved_preamble = preamble_;
+ preamble_ = eval;
+ right->Visit(this);
+ result = result_;
+ preamble_ = saved_preamble;
+ IfNode* right_body = new (I) IfNode(
+ Scanner::kNoSourcePos,
+ new (I) ComparisonNode(
+ Scanner::kNoSourcePos,
+ compare_kind,
+ new_left,
+ new (I) LiteralNode(Scanner::kNoSourcePos, Bool::True())),
+ eval,
+ NULL);
+ preamble_->Add(right_body);
+ return result;
+}
+
+
+void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) {
+ node->left()->Visit(this);
+ AstNode* new_left = result_;
+ AstNode* new_right = new (I) LiteralNode(
hausner 2014/08/07 21:48:42 Why do you allocate a node here when new_right get
Michael Lippautz (Google) 2014/08/08 18:12:17 Not needed. Done.
+ Scanner::kNoSourcePos,
+ Object::null_instance());
+ // Preserve lazy evaluaton.
+ if (node->kind() == Token::kAND || node->kind() == Token::kOR) {
+ new_right = LazyTransform(node->kind(), new_left, node->right());
+ } else {
+ node->right()->Visit(this);
+ new_right = result_;
+ }
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) BinaryOpNode(node->token_pos(),
+ node->kind(),
+ new_left,
+ new_right));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitBinaryOpWithMask32Node(
+ BinaryOpWithMask32Node* node) {
+ node->left()->Visit(this);
+ AstNode* new_left = result_;
+ AstNode* new_right = new (I) LiteralNode(
hausner 2014/08/07 21:48:42 See note above.
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+ Scanner::kNoSourcePos,
+ Object::null_instance());
+ // Preserve lazy evaluaton.
+ if (node->kind() == Token::kAND || node->kind() == Token::kOR) {
+ new_right = LazyTransform(node->kind(), new_left, node->right());
+ } else {
+ node->right()->Visit(this);
+ new_right = result_;
+ }
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) BinaryOpWithMask32Node(node->token_pos(),
+ node->kind(),
+ new_left,
+ new_right,
+ node->mask32()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) {
+ node->left()->Visit(this);
+ AstNode* new_left = result_;
+ node->right()->Visit(this);
+ AstNode* new_right = result_;
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) ComparisonNode(node->token_pos(),
+ node->kind(),
+ new_left,
+ new_right));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
+ node->operand()->Visit(this);
+ AstNode* new_operand = result_;
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) UnaryOpNode(node->token_pos(),
+ node->kind(),
+ new_operand));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+// ::= (<condition>) ? <true-branch> : <false-branch>
hausner 2014/08/07 21:48:42 Nit: add empty line.
Michael Lippautz (Google) 2014/08/08 18:12:17 Done.
+void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
+ // TODO(mlippautz): Optimize variable assingments and branching.
+ node->condition()->Visit(this);
+ AstNode* new_condition = result_;
+ SequenceNode* new_true = new (I) SequenceNode(
+ Scanner::kNoSourcePos, preamble_->scope());
+ SequenceNode* saved_preamble = preamble_;
+ preamble_ = new_true;
+ node->true_expr()->Visit(this);
+ AstNode* new_true_result = result_;
+ SequenceNode* new_false = new (I) SequenceNode(
+ Scanner::kNoSourcePos, preamble_->scope());
+ preamble_ = new_false;
+ node->false_expr()->Visit(this);
+ AstNode* new_false_result = result_;
+ preamble_ = saved_preamble;
+ IfNode* new_if = new (I) IfNode(Scanner::kNoSourcePos,
+ new_condition,
+ new_true,
+ new_false);
+ preamble_->Add(new_if);
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) ConditionalExprNode(Scanner::kNoSourcePos,
+ new_condition,
+ new_true_result,
+ new_false_result));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) {
+ ArgumentListNode* new_args = new (I) ArgumentListNode(node->token_pos());
+ for (intptr_t i = 0; i < node->length(); i++) {
+ node->NodeAt(i)->Visit(this);
+ new_args->Add(result_);
+ }
+ result_ = new_args;
+}
+
+
+void AwaitTransformer::VisitArrayNode(ArrayNode* node) {
+ GrowableArray<AstNode*> new_elements;
+ for (intptr_t i = 0; i < node->length(); i++) {
+ node->ElementAt(i)->Visit(this);
+ new_elements.Add(result_);
+ }
+ result_ = new (I) ArrayNode(node->token_pos(), node->type(), new_elements);
+}
+
+
+void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) {
+ node->value()->Visit(this);
+ ArrayNode* new_value = result_->AsArrayNode();
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StringInterpolateNode(node->token_pos(),
+ new_value));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitClosureNode(ClosureNode* node) {
+ AstNode* new_receiver = node->receiver();
+ if (new_receiver != NULL) {
+ new_receiver->Visit(this);
+ new_receiver = result_;
+ }
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) ClosureNode(node->token_pos(),
+ node->function(),
+ new_receiver,
+ node->scope()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) {
+ node->receiver()->Visit(this);
+ AstNode* new_receiver = result_;
+ node->arguments()->Visit(this);
+ ArgumentListNode* new_args = result_->AsArgumentListNode();
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) InstanceCallNode(node->token_pos(),
+ new_receiver,
+ node->function_name(),
+ new_args));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) {
+ node->arguments()->Visit(this);
+ ArgumentListNode* new_args = result_->AsArgumentListNode();
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StaticCallNode(node->token_pos(),
+ node->function(),
+ new_args));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) {
+ node->arguments()->Visit(this);
+ ArgumentListNode* new_args = result_->AsArgumentListNode();
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) ConstructorCallNode(node->token_pos(),
+ node->type_arguments(),
+ node->constructor(),
+ new_args));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) {
+ node->receiver()->Visit(this);
+ AstNode* new_receiver = result_;
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) InstanceGetterNode(node->token_pos(),
+ new_receiver,
+ node->field_name()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) {
+ AstNode* new_receiver = node->receiver();
+ if (new_receiver != NULL) {
+ new_receiver->Visit(this);
+ new_receiver = result_;
+ }
+
+ node->value()->Visit(this);
+ AstNode* new_value = result_;
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) InstanceSetterNode(node->token_pos(),
+ new_receiver,
+ node->field_name(),
+ new_value));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) {
+ AstNode* new_receiver = node->receiver();
+ if (new_receiver != NULL) {
+ new_receiver->Visit(this);
+ new_receiver = result_;
+ }
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StaticGetterNode(node->token_pos(),
+ new_receiver,
+ node->is_super_getter(),
+ node->cls(),
+ node->field_name()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) {
+ AstNode* new_receiver = node->receiver();
+ if (new_receiver != NULL) {
+ new_receiver->Visit(this);
+ new_receiver = result_;
+ }
+ node->value()->Visit(this);
+ AstNode* new_value = result_;
+
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StaticSetterNode(node->token_pos(),
+ new_receiver,
+ node->cls(),
+ node->field_name(),
+ new_value));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) {
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) LoadLocalNode(node->token_pos(), &node->local()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) {
+ node->value()->Visit(this);
+ AstNode* new_value = result_;
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StoreLocalNode(node->token_pos(),
+ &node->local(),
+ new_value));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) LoadStaticFieldNode(node->token_pos(),
+ node->field()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
+ node->value()->Visit(this);
+ AstNode* new_value = result_;
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StoreStaticFieldNode(node->token_pos(),
+ node->field(),
+ new_value));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) {
+ node->array()->Visit(this);
+ AstNode* new_array = result_;
+ node->index_expr()->Visit(this);
+ AstNode* new_index = result_;
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) LoadIndexedNode(node->token_pos(),
+ new_array,
+ new_index,
+ node->super_class()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) {
+ node->array()->Visit(this);
+ AstNode* new_array = result_;
+ node->index_expr()->Visit(this);
+ AstNode* new_index = result_;
+ node->value()->Visit(this);
+ AstNode* new_value = result_;
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) StoreIndexedNode(node->token_pos(),
+ new_array,
+ new_index,
+ new_value,
+ node->super_class()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitAssignableNode(AssignableNode* node) {
+ node->expr()->Visit(this);
+ AstNode* new_expr = result_;
+ LocalVariable* result = AddToPreambleNewTempVar(
+ new (I) AssignableNode(node->token_pos(),
+ new_expr,
+ node->type(),
+ node->dst_name()));
+ result_ = new (I) LoadLocalNode(Scanner::kNoSourcePos, result);
+}
+
+
+void AwaitTransformer::VisitLetNode(LetNode* node) {
+ // TODO(mlippautz): Check initializers and their temps.
+ LetNode* result = new (I) LetNode(node->token_pos());
+ for (intptr_t i = 0; i < node->nodes().length(); i++) {
+ node->nodes()[i]->Visit(this);
+ result->AddNode(result_);
+ }
+ result_ = result;
+}
+
+
+void AwaitTransformer::VisitThrowNode(ThrowNode* node) {
+ // TODO(mlippautz): Check if relevant.
+ node->exception()->Visit(this);
+ AstNode* new_exception = result_;
+ node->stacktrace()->Visit(this);
+ AstNode* new_stacktrace = result_;
+ result_ = new (I) ThrowNode(node->token_pos(),
+ new_exception,
+ new_stacktrace);
+}
+
+} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698