e449cd0329
This patch does not provide a full async stack trace, it only ensures that the inner-most stack frame will be the point of the initial throw. BUG=http://dartbug.com/22009 R=iposva@google.com Review URL: https://codereview.chromium.org//893193004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@43463 260f80e4-7a28-3924-810f-c04153c831b5
609 lines
23 KiB
C++
609 lines
23 KiB
C++
// 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/object_store.h"
|
|
#include "vm/parser.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
// Quick access to the current zone.
|
|
#define Z (thread()->zone())
|
|
|
|
// Nodes that are unreachable from already parsed expressions.
|
|
#define FOR_EACH_UNREACHABLE_NODE(V) \
|
|
V(AwaitMarker) \
|
|
V(Case) \
|
|
V(CatchClause) \
|
|
V(CloneContext) \
|
|
V(ClosureCall) \
|
|
V(DoWhile) \
|
|
V(If) \
|
|
V(InitStaticField) \
|
|
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
|
|
|
|
AwaitTransformer::AwaitTransformer(SequenceNode* preamble,
|
|
const ParsedFunction& parsed_function,
|
|
LocalScope* function_top)
|
|
: preamble_(preamble),
|
|
temp_cnt_(0),
|
|
parsed_function_(parsed_function),
|
|
function_top_(function_top),
|
|
thread_(Thread::Current()) {
|
|
ASSERT(function_top_ != NULL);
|
|
}
|
|
|
|
|
|
AstNode* AwaitTransformer::Transform(AstNode* expr) {
|
|
expr->Visit(this);
|
|
return result_;
|
|
}
|
|
|
|
|
|
LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
|
|
const char* await_temp_prefix = ":await_temp_var_";
|
|
const String& cnt_str = String::ZoneHandle(
|
|
Z, String::NewFormatted("%s%d", await_temp_prefix, temp_cnt_));
|
|
const String& symbol = String::ZoneHandle(Z, Symbols::New(cnt_str));
|
|
ASSERT(!symbol.IsNull());
|
|
// Look up the variable through the preamble scope.
|
|
LocalVariable* await_tmp = preamble_->scope()->LookupVariable(symbol, false);
|
|
if (await_tmp == NULL) {
|
|
// If we need a new temp variable, we add it to the function's top scope.
|
|
await_tmp = new (Z) LocalVariable(
|
|
Scanner::kNoSourcePos, symbol, Type::ZoneHandle(Type::DynamicType()));
|
|
function_top_->AddVariable(await_tmp);
|
|
// After adding it to the top scope, we can look it up from the preamble.
|
|
// The following call includes an ASSERT check.
|
|
await_tmp = GetVariableInScope(preamble_->scope(), symbol);
|
|
}
|
|
return await_tmp;
|
|
}
|
|
|
|
|
|
LocalVariable* AwaitTransformer::GetVariableInScope(LocalScope* scope,
|
|
const String& symbol) {
|
|
LocalVariable* var = scope->LookupVariable(symbol, false);
|
|
ASSERT(var != NULL);
|
|
return var;
|
|
}
|
|
|
|
|
|
LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
|
|
LocalVariable* tmp_var = EnsureCurrentTempVar();
|
|
preamble_->Add(new(Z) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
|
|
NextTempVar();
|
|
return tmp_var;
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitLiteralNode(LiteralNode* node) {
|
|
result_ = node;
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitTypeNode(TypeNode* node) {
|
|
result_ = new(Z) 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 = Future.value(:result_param);
|
|
// }
|
|
// AwaitMarker(kNewContinuationState);
|
|
// :result_param = :result_param.then(:async_op);
|
|
// _asyncCatchHelper(:result_param.catchError, :async_op);
|
|
// return; // (return_type() == kContinuationTarget)
|
|
//
|
|
// :saved_try_ctx_var = :await_saved_try_ctx_var_y;
|
|
// :await_temp_var_(X+1) = :result_param;
|
|
|
|
LocalVariable* async_op = GetVariableInScope(
|
|
preamble_->scope(), Symbols::AsyncOperation());
|
|
LocalVariable* result_param = GetVariableInScope(
|
|
preamble_->scope(), Symbols::AsyncOperationParam());
|
|
LocalVariable* error_param = GetVariableInScope(
|
|
preamble_->scope(), Symbols::AsyncOperationErrorParam());
|
|
LocalVariable* stack_trace_param = GetVariableInScope(
|
|
preamble_->scope(), Symbols::AsyncOperationStackTraceParam());
|
|
|
|
AstNode* transformed_expr = Transform(node->expr());
|
|
preamble_->Add(new(Z) StoreLocalNode(
|
|
Scanner::kNoSourcePos, result_param, transformed_expr));
|
|
|
|
LoadLocalNode* load_result_param = new(Z) LoadLocalNode(
|
|
Scanner::kNoSourcePos, result_param);
|
|
|
|
const Class& future_cls =
|
|
Class::ZoneHandle(Z, thread()->isolate()->object_store()->future_class());
|
|
ASSERT(!future_cls.IsNull());
|
|
const AbstractType& future_type =
|
|
AbstractType::ZoneHandle(Z, future_cls.RareType());
|
|
ASSERT(!future_type.IsNull());
|
|
|
|
LocalScope* is_not_future_scope = ChainNewScope(preamble_->scope());
|
|
SequenceNode* is_not_future_branch =
|
|
new (Z) SequenceNode(Scanner::kNoSourcePos, is_not_future_scope);
|
|
|
|
// if (:result_param is !Future) {
|
|
// :result_param = Future.value(:result_param);
|
|
// }
|
|
const Function& value_ctor = Function::ZoneHandle(
|
|
Z, future_cls.LookupFunction(Symbols::FutureValue()));
|
|
ASSERT(!value_ctor.IsNull());
|
|
ArgumentListNode* ctor_args = new (Z) ArgumentListNode(Scanner::kNoSourcePos);
|
|
ctor_args->Add(new (Z) LoadLocalNode(Scanner::kNoSourcePos, result_param));
|
|
ConstructorCallNode* ctor_call =
|
|
new (Z) ConstructorCallNode(Scanner::kNoSourcePos,
|
|
TypeArguments::ZoneHandle(Z),
|
|
value_ctor,
|
|
ctor_args);
|
|
is_not_future_branch->Add(new (Z) StoreLocalNode(
|
|
Scanner::kNoSourcePos, result_param, ctor_call));
|
|
AstNode* is_not_future_test = new (Z) ComparisonNode(
|
|
Scanner::kNoSourcePos,
|
|
Token::kISNOT,
|
|
load_result_param,
|
|
new (Z) TypeNode(Scanner::kNoSourcePos, future_type));
|
|
preamble_->Add(new(Z) IfNode(Scanner::kNoSourcePos,
|
|
is_not_future_test,
|
|
is_not_future_branch,
|
|
NULL));
|
|
|
|
AwaitMarkerNode* await_marker = new (Z) AwaitMarkerNode();
|
|
await_marker->set_scope(preamble_->scope());
|
|
preamble_->Add(await_marker);
|
|
ArgumentListNode* args = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
|
|
|
|
args->Add(new(Z) LoadLocalNode(Scanner::kNoSourcePos, async_op));
|
|
preamble_->Add(new (Z) StoreLocalNode(
|
|
Scanner::kNoSourcePos,
|
|
result_param,
|
|
new(Z) InstanceCallNode(Scanner::kNoSourcePos,
|
|
load_result_param,
|
|
Symbols::FutureThen(),
|
|
args)));
|
|
const Library& core_lib = Library::Handle(Library::CoreLibrary());
|
|
const Function& async_catch_helper = Function::ZoneHandle(
|
|
Z, core_lib.LookupFunctionAllowPrivate(Symbols::AsyncCatchHelper()));
|
|
ASSERT(!async_catch_helper.IsNull());
|
|
ArgumentListNode* catch_helper_args = new (Z) ArgumentListNode(
|
|
Scanner::kNoSourcePos);
|
|
InstanceGetterNode* catch_error_getter = new (Z) InstanceGetterNode(
|
|
Scanner::kNoSourcePos,
|
|
load_result_param,
|
|
Symbols::FutureCatchError());
|
|
catch_helper_args->Add(catch_error_getter);
|
|
catch_helper_args->Add(new (Z) LoadLocalNode(
|
|
Scanner::kNoSourcePos, async_op));
|
|
preamble_->Add(new (Z) StaticCallNode(
|
|
Scanner::kNoSourcePos,
|
|
async_catch_helper,
|
|
catch_helper_args));
|
|
ReturnNode* continuation_return = new(Z) ReturnNode(Scanner::kNoSourcePos);
|
|
continuation_return->set_return_type(ReturnNode::kContinuationTarget);
|
|
preamble_->Add(continuation_return);
|
|
|
|
// If this expression is part of a try block, also append the code for
|
|
// restoring the saved try context that lives on the stack.
|
|
const String& async_saved_try_ctx_name =
|
|
String::Handle(Z, parsed_function_.async_saved_try_ctx_name());
|
|
if (!async_saved_try_ctx_name.IsNull()) {
|
|
LocalVariable* async_saved_try_ctx =
|
|
GetVariableInScope(preamble_->scope(), async_saved_try_ctx_name);
|
|
preamble_->Add(new (Z) StoreLocalNode(
|
|
Scanner::kNoSourcePos,
|
|
parsed_function_.saved_try_ctx(),
|
|
new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_saved_try_ctx)));
|
|
}
|
|
|
|
LoadLocalNode* load_error_param = new (Z) LoadLocalNode(
|
|
Scanner::kNoSourcePos, error_param);
|
|
LoadLocalNode* load_stack_trace_param = new (Z) LoadLocalNode(
|
|
Scanner::kNoSourcePos, stack_trace_param);
|
|
SequenceNode* error_ne_null_branch = new (Z) SequenceNode(
|
|
Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
|
error_ne_null_branch->Add(new (Z) ThrowNode(
|
|
Scanner::kNoSourcePos,
|
|
load_error_param,
|
|
load_stack_trace_param));
|
|
preamble_->Add(new (Z) IfNode(
|
|
Scanner::kNoSourcePos,
|
|
new (Z) ComparisonNode(
|
|
Scanner::kNoSourcePos,
|
|
Token::kNE,
|
|
load_error_param,
|
|
new (Z) LiteralNode(Scanner::kNoSourcePos,
|
|
Object::null_instance())),
|
|
error_ne_null_branch,
|
|
NULL));
|
|
|
|
LocalVariable* result = AddToPreambleNewTempVar(new(Z) LoadLocalNode(
|
|
Scanner::kNoSourcePos, result_param));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
// Transforms boolean expressions into a sequence of evaluatons that only lazily
|
|
// evaluate subexpressions.
|
|
//
|
|
// Example:
|
|
//
|
|
// (a || b) only evaluates b if a is false
|
|
//
|
|
// Transformation (roughly):
|
|
//
|
|
// t_1 = a;
|
|
// if (!t_1) {
|
|
// t_2 = b;
|
|
// }
|
|
// t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place
|
|
// on this level.
|
|
AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op,
|
|
AstNode* new_left,
|
|
AstNode* right) {
|
|
ASSERT(logical_op == Token::kAND || logical_op == Token::kOR);
|
|
AstNode* result = NULL;
|
|
const Token::Kind compare_logical_op = (logical_op == Token::kAND) ?
|
|
Token::kEQ : Token::kNE;
|
|
SequenceNode* eval = new (Z) SequenceNode(
|
|
Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
|
SequenceNode* saved_preamble = preamble_;
|
|
preamble_ = eval;
|
|
result = Transform(right);
|
|
preamble_ = saved_preamble;
|
|
IfNode* right_body = new(Z) IfNode(
|
|
Scanner::kNoSourcePos,
|
|
new(Z) ComparisonNode(
|
|
Scanner::kNoSourcePos,
|
|
compare_logical_op,
|
|
new_left,
|
|
new(Z) LiteralNode(Scanner::kNoSourcePos, Bool::True())),
|
|
eval,
|
|
NULL);
|
|
preamble_->Add(right_body);
|
|
return result;
|
|
}
|
|
|
|
|
|
LocalScope* AwaitTransformer::ChainNewScope(LocalScope* parent) {
|
|
return new (Z) LocalScope(
|
|
parent, parent->function_level(), parent->loop_level());
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) {
|
|
AstNode* new_left = Transform(node->left());
|
|
AstNode* new_right = NULL;
|
|
// Preserve lazy evaluaton.
|
|
if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
|
|
new_right = LazyTransform(node->kind(), new_left, node->right());
|
|
} else {
|
|
new_right = Transform(node->right());
|
|
}
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) BinaryOpNode(node->token_pos(),
|
|
node->kind(),
|
|
new_left,
|
|
new_right));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitBinaryOpWithMask32Node(
|
|
BinaryOpWithMask32Node* node) {
|
|
ASSERT((node->kind() != Token::kAND) && (node->kind() != Token::kOR));
|
|
AstNode* new_left = Transform(node->left());
|
|
AstNode* new_right = Transform(node->right());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) BinaryOpWithMask32Node(node->token_pos(),
|
|
node->kind(),
|
|
new_left,
|
|
new_right,
|
|
node->mask32()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) {
|
|
AstNode* new_left = Transform(node->left());
|
|
AstNode* new_right = Transform(node->right());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) ComparisonNode(node->token_pos(),
|
|
node->kind(),
|
|
new_left,
|
|
new_right));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
|
|
AstNode* new_operand = Transform(node->operand());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) UnaryOpNode(node->token_pos(), node->kind(), new_operand));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
// ::= (<condition>) ? <true-branch> : <false-branch>
|
|
//
|
|
void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
|
|
AstNode* new_condition = Transform(node->condition());
|
|
SequenceNode* new_true = new (Z) SequenceNode(
|
|
Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
|
SequenceNode* saved_preamble = preamble_;
|
|
preamble_ = new_true;
|
|
AstNode* new_true_result = Transform(node->true_expr());
|
|
SequenceNode* new_false = new (Z) SequenceNode(
|
|
Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
|
preamble_ = new_false;
|
|
AstNode* new_false_result = Transform(node->false_expr());
|
|
preamble_ = saved_preamble;
|
|
IfNode* new_if = new(Z) IfNode(Scanner::kNoSourcePos,
|
|
new_condition,
|
|
new_true,
|
|
new_false);
|
|
preamble_->Add(new_if);
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) ConditionalExprNode(Scanner::kNoSourcePos,
|
|
new_condition,
|
|
new_true_result,
|
|
new_false_result));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) {
|
|
ArgumentListNode* new_args = new(Z) ArgumentListNode(node->token_pos());
|
|
for (intptr_t i = 0; i < node->length(); i++) {
|
|
new_args->Add(Transform(node->NodeAt(i)));
|
|
}
|
|
new_args->set_names(node->names());
|
|
result_ = new_args;
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitArrayNode(ArrayNode* node) {
|
|
GrowableArray<AstNode*> new_elements;
|
|
for (intptr_t i = 0; i < node->length(); i++) {
|
|
new_elements.Add(Transform(node->ElementAt(i)));
|
|
}
|
|
result_ = new(Z) ArrayNode(node->token_pos(), node->type(), new_elements);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) {
|
|
ArrayNode* new_value = Transform(node->value())->AsArrayNode();
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StringInterpolateNode(node->token_pos(),
|
|
new_value));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitClosureNode(ClosureNode* node) {
|
|
AstNode* new_receiver = node->receiver();
|
|
if (new_receiver != NULL) {
|
|
new_receiver = Transform(new_receiver);
|
|
}
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) ClosureNode(node->token_pos(),
|
|
node->function(),
|
|
new_receiver,
|
|
node->scope()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) {
|
|
AstNode* new_receiver = Transform(node->receiver());
|
|
ArgumentListNode* new_args =
|
|
Transform(node->arguments())->AsArgumentListNode();
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) InstanceCallNode(node->token_pos(),
|
|
new_receiver,
|
|
node->function_name(),
|
|
new_args));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) {
|
|
ArgumentListNode* new_args =
|
|
Transform(node->arguments())->AsArgumentListNode();
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StaticCallNode(node->token_pos(),
|
|
node->function(),
|
|
new_args));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) {
|
|
ArgumentListNode* new_args =
|
|
Transform(node->arguments())->AsArgumentListNode();
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) ConstructorCallNode(node->token_pos(),
|
|
node->type_arguments(),
|
|
node->constructor(),
|
|
new_args));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) {
|
|
AstNode* new_receiver = Transform(node->receiver());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) InstanceGetterNode(node->token_pos(),
|
|
new_receiver,
|
|
node->field_name()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) {
|
|
AstNode* new_receiver = node->receiver();
|
|
if (new_receiver != NULL) {
|
|
new_receiver = Transform(new_receiver);
|
|
}
|
|
AstNode* new_value = Transform(node->value());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) InstanceSetterNode(node->token_pos(),
|
|
new_receiver,
|
|
node->field_name(),
|
|
new_value));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) {
|
|
AstNode* new_receiver = node->receiver();
|
|
if (new_receiver != NULL) {
|
|
new_receiver = Transform(new_receiver);
|
|
}
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StaticGetterNode(node->token_pos(),
|
|
new_receiver,
|
|
node->is_super_getter(),
|
|
node->cls(),
|
|
node->field_name()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) {
|
|
AstNode* new_receiver = node->receiver();
|
|
if (new_receiver != NULL) {
|
|
new_receiver = Transform(new_receiver);
|
|
}
|
|
AstNode* new_value = Transform(node->value());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StaticSetterNode(node->token_pos(),
|
|
new_receiver,
|
|
node->cls(),
|
|
node->field_name(),
|
|
new_value));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) {
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) LoadLocalNode(node->token_pos(), &node->local()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) {
|
|
AstNode* new_value = Transform(node->value());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StoreLocalNode(node->token_pos(),
|
|
&node->local(),
|
|
new_value));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) LoadStaticFieldNode(node->token_pos(),
|
|
node->field()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
|
|
AstNode* new_value = Transform(node->value());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StoreStaticFieldNode(node->token_pos(),
|
|
node->field(),
|
|
new_value));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) {
|
|
AstNode* new_array = Transform(node->array());
|
|
AstNode* new_index = Transform(node->index_expr());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) LoadIndexedNode(node->token_pos(),
|
|
new_array,
|
|
new_index,
|
|
node->super_class()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) {
|
|
AstNode* new_array = Transform(node->array());
|
|
AstNode* new_index = Transform(node->index_expr());
|
|
AstNode* new_value = Transform(node->value());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) StoreIndexedNode(node->token_pos(),
|
|
new_array,
|
|
new_index,
|
|
new_value,
|
|
node->super_class()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitAssignableNode(AssignableNode* node) {
|
|
AstNode* new_expr = Transform(node->expr());
|
|
LocalVariable* result = AddToPreambleNewTempVar(
|
|
new(Z) AssignableNode(node->token_pos(),
|
|
new_expr,
|
|
node->type(),
|
|
node->dst_name()));
|
|
result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitLetNode(LetNode* node) {
|
|
// TODO(mlippautz): Check initializers and their temps.
|
|
LetNode* result = new(Z) LetNode(node->token_pos());
|
|
for (intptr_t i = 0; i < node->nodes().length(); i++) {
|
|
result->AddNode(Transform(node->nodes()[i]));
|
|
}
|
|
result_ = result;
|
|
}
|
|
|
|
|
|
void AwaitTransformer::VisitThrowNode(ThrowNode* node) {
|
|
// TODO(mlippautz): Check if relevant.
|
|
AstNode* new_exception = Transform(node->exception());
|
|
AstNode* new_stacktrace = Transform(node->stacktrace());
|
|
result_ = new(Z) ThrowNode(node->token_pos(),
|
|
new_exception,
|
|
new_stacktrace);
|
|
}
|
|
|
|
} // namespace dart
|