OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "vm/ast_transformer.h" |
| 6 |
| 7 #include "vm/parser.h" |
| 8 |
| 9 namespace dart { |
| 10 |
| 11 // Quick access to the locally defined isolate() method. |
| 12 #define I (isolate()) |
| 13 |
| 14 // Nodes that are unreachable from already parsed expressions. |
| 15 #define FOR_EACH_UNREACHABLE_NODE(V) \ |
| 16 V(Case) \ |
| 17 V(CatchClause) \ |
| 18 V(CloneContext) \ |
| 19 V(ClosureCall) \ |
| 20 V(DoWhile) \ |
| 21 V(If) \ |
| 22 V(InlinedFinally) \ |
| 23 V(For) \ |
| 24 V(Jump) \ |
| 25 V(LoadInstanceField) \ |
| 26 V(NativeBody) \ |
| 27 V(Primary) \ |
| 28 V(Return) \ |
| 29 V(Sequence) \ |
| 30 V(StoreInstanceField) \ |
| 31 V(Switch) \ |
| 32 V(TryCatch) \ |
| 33 V(While) |
| 34 |
| 35 #define DEFINE_UNREACHABLE(BaseName) \ |
| 36 void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \ |
| 37 UNREACHABLE(); \ |
| 38 } |
| 39 |
| 40 FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE) |
| 41 #undef DEFINE_UNREACHABLE |
| 42 |
| 43 |
| 44 AstNode* AwaitTransformer::Transform(AstNode* expr) { |
| 45 expr->Visit(this); |
| 46 return result_; |
| 47 } |
| 48 |
| 49 |
| 50 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() { |
| 51 const char* await_temp_prefix = ":await_temp_var_"; |
| 52 const String& cnt_str = String::ZoneHandle(I, |
| 53 String::NewFormatted( |
| 54 "%s%" Pd "", await_temp_prefix, temp_cnt_)); |
| 55 const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str)); |
| 56 ASSERT(!symbol.IsNull()); |
| 57 LocalVariable* await_tmp = |
| 58 parsed_function_->await_temps_scope()->LookupVariable(symbol, false); |
| 59 if (await_tmp == NULL) { |
| 60 await_tmp = new(I) LocalVariable( |
| 61 Scanner::kNoSourcePos, |
| 62 symbol, |
| 63 Type::ZoneHandle(I, Type::DynamicType())); |
| 64 parsed_function_->await_temps_scope()->AddVariable(await_tmp); |
| 65 } |
| 66 return await_tmp; |
| 67 } |
| 68 |
| 69 |
| 70 LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) { |
| 71 LocalVariable* tmp_var = EnsureCurrentTempVar(); |
| 72 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node)); |
| 73 NextTempVar(); |
| 74 return tmp_var; |
| 75 } |
| 76 |
| 77 |
| 78 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) { |
| 79 result_ = node; |
| 80 } |
| 81 |
| 82 |
| 83 void AwaitTransformer::VisitTypeNode(TypeNode* node) { |
| 84 result_ = new(I) TypeNode(node->token_pos(), node->type()); |
| 85 } |
| 86 |
| 87 |
| 88 |
| 89 void AwaitTransformer::VisitAwaitNode(AwaitNode* node) { |
| 90 // Await transformation: |
| 91 // |
| 92 // :await_temp_var_X = <expr>; |
| 93 // :result_param = :await_temp_var_X; |
| 94 // if (:result_param is Future) { |
| 95 // // :result_param.then(:async_op); |
| 96 // } |
| 97 // :await_temp_var_(X+1) = :result_param; |
| 98 |
| 99 LocalVariable* async_op = preamble_->scope()->LookupVariable( |
| 100 Symbols::AsyncOperation(), false); |
| 101 ASSERT(async_op != NULL); |
| 102 LocalVariable* result_param = preamble_->scope()->LookupVariable( |
| 103 Symbols::AsyncOperationParam(), false); |
| 104 ASSERT(result_param != NULL); |
| 105 |
| 106 node->expr()->Visit(this); |
| 107 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, |
| 108 result_param, |
| 109 result_)); |
| 110 LoadLocalNode* load_result_param = new(I) LoadLocalNode( |
| 111 Scanner::kNoSourcePos, result_param); |
| 112 SequenceNode* is_future_branch = new(I) SequenceNode( |
| 113 Scanner::kNoSourcePos, preamble_->scope()); |
| 114 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos); |
| 115 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); |
| 116 // TODO(mlippautz): Once continuations are supported, just call .then(). |
| 117 // is_future_branch->Add(new(I) InstanceCallNode( |
| 118 // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); |
| 119 // |
| 120 // For now, throw an exception. |
| 121 const String& exception = String::ZoneHandle( |
| 122 I, String::New("awaitable futures not yet supported", Heap::kOld)); |
| 123 is_future_branch->Add(new(I) ThrowNode( |
| 124 Scanner::kNoSourcePos, |
| 125 new(I) LiteralNode( |
| 126 Scanner::kNoSourcePos, |
| 127 String::ZoneHandle(I, Symbols::New(exception))), |
| 128 NULL)); |
| 129 const Class& cls = Class::ZoneHandle( |
| 130 I, library_.LookupClass(Symbols::Future())); |
| 131 const AbstractType& future_type = AbstractType::ZoneHandle(I, |
| 132 cls.RareType()); |
| 133 ASSERT(!future_type.IsNull()); |
| 134 TypeNode* future_type_node = new(I) TypeNode( |
| 135 Scanner::kNoSourcePos, future_type); |
| 136 IfNode* is_future_if = new(I) IfNode( |
| 137 Scanner::kNoSourcePos, |
| 138 new(I) ComparisonNode(Scanner::kNoSourcePos, |
| 139 Token::kIS, |
| 140 load_result_param, |
| 141 future_type_node), |
| 142 is_future_branch, |
| 143 NULL); |
| 144 preamble_->Add(is_future_if); |
| 145 |
| 146 // TODO(mlippautz): Join for await needs to happen here. |
| 147 |
| 148 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode( |
| 149 Scanner::kNoSourcePos, result_param)); |
| 150 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 151 } |
| 152 |
| 153 |
| 154 // Transforms boolean expressions into a sequence of evaluatons that only lazily |
| 155 // evaluate subexpressions. |
| 156 // |
| 157 // Example: |
| 158 // |
| 159 // (a || b) only evaluates b if a is false |
| 160 // |
| 161 // Transformation (roughly): |
| 162 // |
| 163 // t_1 = a; |
| 164 // if (!t_1) { |
| 165 // t_2 = b; |
| 166 // } |
| 167 // t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place |
| 168 // on this level. |
| 169 AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op, |
| 170 AstNode* new_left, |
| 171 AstNode* right) { |
| 172 ASSERT(logical_op == Token::kAND || logical_op == Token::kOR); |
| 173 AstNode* result = NULL; |
| 174 const Token::Kind compare_logical_op = (logical_op == Token::kAND) ? |
| 175 Token::kEQ : Token::kNE; |
| 176 SequenceNode* eval = new(I) SequenceNode( |
| 177 Scanner::kNoSourcePos, preamble_->scope()); |
| 178 SequenceNode* saved_preamble = preamble_; |
| 179 preamble_ = eval; |
| 180 result = Transform(right); |
| 181 preamble_ = saved_preamble; |
| 182 IfNode* right_body = new(I) IfNode( |
| 183 Scanner::kNoSourcePos, |
| 184 new(I) ComparisonNode( |
| 185 Scanner::kNoSourcePos, |
| 186 compare_logical_op, |
| 187 new_left, |
| 188 new(I) LiteralNode(Scanner::kNoSourcePos, Bool::True())), |
| 189 eval, |
| 190 NULL); |
| 191 preamble_->Add(right_body); |
| 192 return result; |
| 193 } |
| 194 |
| 195 |
| 196 void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) { |
| 197 node->left()->Visit(this); |
| 198 AstNode* new_left = result_; |
| 199 AstNode* new_right = NULL; |
| 200 // Preserve lazy evaluaton. |
| 201 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { |
| 202 new_right = LazyTransform(node->kind(), new_left, node->right()); |
| 203 } else { |
| 204 new_right = Transform(node->right()); |
| 205 } |
| 206 LocalVariable* result = AddToPreambleNewTempVar( |
| 207 new(I) BinaryOpNode(node->token_pos(), |
| 208 node->kind(), |
| 209 new_left, |
| 210 new_right)); |
| 211 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 212 } |
| 213 |
| 214 |
| 215 void AwaitTransformer::VisitBinaryOpWithMask32Node( |
| 216 BinaryOpWithMask32Node* node) { |
| 217 node->left()->Visit(this); |
| 218 AstNode* new_left = result_; |
| 219 AstNode* new_right = NULL; |
| 220 // Preserve lazy evaluaton. |
| 221 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { |
| 222 new_right = LazyTransform(node->kind(), new_left, node->right()); |
| 223 } else { |
| 224 new_right = Transform(node->right()); |
| 225 } |
| 226 LocalVariable* result = AddToPreambleNewTempVar( |
| 227 new(I) BinaryOpWithMask32Node(node->token_pos(), |
| 228 node->kind(), |
| 229 new_left, |
| 230 new_right, |
| 231 node->mask32())); |
| 232 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 233 } |
| 234 |
| 235 |
| 236 void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) { |
| 237 AstNode* new_left = Transform(node->left()); |
| 238 AstNode* new_right = Transform(node->right()); |
| 239 LocalVariable* result = AddToPreambleNewTempVar( |
| 240 new(I) ComparisonNode(node->token_pos(), |
| 241 node->kind(), |
| 242 new_left, |
| 243 new_right)); |
| 244 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 245 } |
| 246 |
| 247 |
| 248 void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) { |
| 249 AstNode* new_operand = Transform(node->operand()); |
| 250 LocalVariable* result = AddToPreambleNewTempVar( |
| 251 new(I) UnaryOpNode(node->token_pos(), node->kind(), new_operand)); |
| 252 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 253 } |
| 254 |
| 255 |
| 256 // ::= (<condition>) ? <true-branch> : <false-branch> |
| 257 // |
| 258 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) { |
| 259 AstNode* new_condition = Transform(node->condition()); |
| 260 SequenceNode* new_true = new(I) SequenceNode( |
| 261 Scanner::kNoSourcePos, preamble_->scope()); |
| 262 SequenceNode* saved_preamble = preamble_; |
| 263 preamble_ = new_true; |
| 264 AstNode* new_true_result = Transform(node->true_expr()); |
| 265 SequenceNode* new_false = new(I) SequenceNode( |
| 266 Scanner::kNoSourcePos, preamble_->scope()); |
| 267 preamble_ = new_false; |
| 268 AstNode* new_false_result = Transform(node->false_expr()); |
| 269 preamble_ = saved_preamble; |
| 270 IfNode* new_if = new(I) IfNode(Scanner::kNoSourcePos, |
| 271 new_condition, |
| 272 new_true, |
| 273 new_false); |
| 274 preamble_->Add(new_if); |
| 275 LocalVariable* result = AddToPreambleNewTempVar( |
| 276 new(I) ConditionalExprNode(Scanner::kNoSourcePos, |
| 277 new_condition, |
| 278 new_true_result, |
| 279 new_false_result)); |
| 280 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 281 } |
| 282 |
| 283 |
| 284 void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) { |
| 285 ArgumentListNode* new_args = new(I) ArgumentListNode(node->token_pos()); |
| 286 for (intptr_t i = 0; i < node->length(); i++) { |
| 287 new_args->Add(Transform(node->NodeAt(i))); |
| 288 } |
| 289 result_ = new_args; |
| 290 } |
| 291 |
| 292 |
| 293 void AwaitTransformer::VisitArrayNode(ArrayNode* node) { |
| 294 GrowableArray<AstNode*> new_elements; |
| 295 for (intptr_t i = 0; i < node->length(); i++) { |
| 296 new_elements.Add(Transform(node->ElementAt(i))); |
| 297 } |
| 298 result_ = new(I) ArrayNode(node->token_pos(), node->type(), new_elements); |
| 299 } |
| 300 |
| 301 |
| 302 void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) { |
| 303 ArrayNode* new_value = Transform(node->value())->AsArrayNode(); |
| 304 LocalVariable* result = AddToPreambleNewTempVar( |
| 305 new(I) StringInterpolateNode(node->token_pos(), |
| 306 new_value)); |
| 307 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 308 } |
| 309 |
| 310 |
| 311 void AwaitTransformer::VisitClosureNode(ClosureNode* node) { |
| 312 AstNode* new_receiver = node->receiver(); |
| 313 if (new_receiver != NULL) { |
| 314 new_receiver = Transform(new_receiver); |
| 315 } |
| 316 LocalVariable* result = AddToPreambleNewTempVar( |
| 317 new(I) ClosureNode(node->token_pos(), |
| 318 node->function(), |
| 319 new_receiver, |
| 320 node->scope())); |
| 321 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 322 } |
| 323 |
| 324 |
| 325 void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) { |
| 326 AstNode* new_receiver = Transform(node->receiver()); |
| 327 ArgumentListNode* new_args = |
| 328 Transform(node->arguments())->AsArgumentListNode(); |
| 329 LocalVariable* result = AddToPreambleNewTempVar( |
| 330 new(I) InstanceCallNode(node->token_pos(), |
| 331 new_receiver, |
| 332 node->function_name(), |
| 333 new_args)); |
| 334 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 335 } |
| 336 |
| 337 |
| 338 void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) { |
| 339 ArgumentListNode* new_args = |
| 340 Transform(node->arguments())->AsArgumentListNode(); |
| 341 LocalVariable* result = AddToPreambleNewTempVar( |
| 342 new(I) StaticCallNode(node->token_pos(), |
| 343 node->function(), |
| 344 new_args)); |
| 345 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 346 } |
| 347 |
| 348 |
| 349 void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) { |
| 350 ArgumentListNode* new_args = |
| 351 Transform(node->arguments())->AsArgumentListNode(); |
| 352 LocalVariable* result = AddToPreambleNewTempVar( |
| 353 new(I) ConstructorCallNode(node->token_pos(), |
| 354 node->type_arguments(), |
| 355 node->constructor(), |
| 356 new_args)); |
| 357 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 358 } |
| 359 |
| 360 |
| 361 void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) { |
| 362 AstNode* new_receiver = Transform(node->receiver()); |
| 363 LocalVariable* result = AddToPreambleNewTempVar( |
| 364 new(I) InstanceGetterNode(node->token_pos(), |
| 365 new_receiver, |
| 366 node->field_name())); |
| 367 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 368 } |
| 369 |
| 370 |
| 371 void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) { |
| 372 AstNode* new_receiver = node->receiver(); |
| 373 if (new_receiver != NULL) { |
| 374 new_receiver = Transform(new_receiver); |
| 375 } |
| 376 AstNode* new_value = Transform(node->value()); |
| 377 LocalVariable* result = AddToPreambleNewTempVar( |
| 378 new(I) InstanceSetterNode(node->token_pos(), |
| 379 new_receiver, |
| 380 node->field_name(), |
| 381 new_value)); |
| 382 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 383 } |
| 384 |
| 385 |
| 386 void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) { |
| 387 AstNode* new_receiver = node->receiver(); |
| 388 if (new_receiver != NULL) { |
| 389 new_receiver = Transform(new_receiver); |
| 390 } |
| 391 LocalVariable* result = AddToPreambleNewTempVar( |
| 392 new(I) StaticGetterNode(node->token_pos(), |
| 393 new_receiver, |
| 394 node->is_super_getter(), |
| 395 node->cls(), |
| 396 node->field_name())); |
| 397 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 398 } |
| 399 |
| 400 |
| 401 void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) { |
| 402 AstNode* new_receiver = node->receiver(); |
| 403 if (new_receiver != NULL) { |
| 404 new_receiver = Transform(new_receiver); |
| 405 } |
| 406 AstNode* new_value = Transform(node->value()); |
| 407 LocalVariable* result = AddToPreambleNewTempVar( |
| 408 new(I) StaticSetterNode(node->token_pos(), |
| 409 new_receiver, |
| 410 node->cls(), |
| 411 node->field_name(), |
| 412 new_value)); |
| 413 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 414 } |
| 415 |
| 416 |
| 417 void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) { |
| 418 LocalVariable* result = AddToPreambleNewTempVar( |
| 419 new(I) LoadLocalNode(node->token_pos(), &node->local())); |
| 420 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 421 } |
| 422 |
| 423 |
| 424 void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) { |
| 425 AstNode* new_value = Transform(node->value()); |
| 426 LocalVariable* result = AddToPreambleNewTempVar( |
| 427 new(I) StoreLocalNode(node->token_pos(), |
| 428 &node->local(), |
| 429 new_value)); |
| 430 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 431 } |
| 432 |
| 433 |
| 434 void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) { |
| 435 LocalVariable* result = AddToPreambleNewTempVar( |
| 436 new(I) LoadStaticFieldNode(node->token_pos(), |
| 437 node->field())); |
| 438 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 439 } |
| 440 |
| 441 |
| 442 void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { |
| 443 AstNode* new_value = Transform(node->value()); |
| 444 LocalVariable* result = AddToPreambleNewTempVar( |
| 445 new(I) StoreStaticFieldNode(node->token_pos(), |
| 446 node->field(), |
| 447 new_value)); |
| 448 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 449 } |
| 450 |
| 451 |
| 452 void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 453 AstNode* new_array = Transform(node->array()); |
| 454 AstNode* new_index = Transform(node->index_expr()); |
| 455 LocalVariable* result = AddToPreambleNewTempVar( |
| 456 new(I) LoadIndexedNode(node->token_pos(), |
| 457 new_array, |
| 458 new_index, |
| 459 node->super_class())); |
| 460 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 461 } |
| 462 |
| 463 |
| 464 void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) { |
| 465 AstNode* new_array = Transform(node->array()); |
| 466 AstNode* new_index = Transform(node->index_expr()); |
| 467 AstNode* new_value = Transform(node->value()); |
| 468 LocalVariable* result = AddToPreambleNewTempVar( |
| 469 new(I) StoreIndexedNode(node->token_pos(), |
| 470 new_array, |
| 471 new_index, |
| 472 new_value, |
| 473 node->super_class())); |
| 474 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 475 } |
| 476 |
| 477 |
| 478 void AwaitTransformer::VisitAssignableNode(AssignableNode* node) { |
| 479 AstNode* new_expr = Transform(node->expr()); |
| 480 LocalVariable* result = AddToPreambleNewTempVar( |
| 481 new(I) AssignableNode(node->token_pos(), |
| 482 new_expr, |
| 483 node->type(), |
| 484 node->dst_name())); |
| 485 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 486 } |
| 487 |
| 488 |
| 489 void AwaitTransformer::VisitLetNode(LetNode* node) { |
| 490 // TODO(mlippautz): Check initializers and their temps. |
| 491 LetNode* result = new(I) LetNode(node->token_pos()); |
| 492 for (intptr_t i = 0; i < node->nodes().length(); i++) { |
| 493 result->AddNode(Transform(node->nodes()[i])); |
| 494 } |
| 495 result_ = result; |
| 496 } |
| 497 |
| 498 |
| 499 void AwaitTransformer::VisitThrowNode(ThrowNode* node) { |
| 500 // TODO(mlippautz): Check if relevant. |
| 501 AstNode* new_exception = Transform(node->exception()); |
| 502 AstNode* new_stacktrace = Transform(node->stacktrace()); |
| 503 result_ = new(I) ThrowNode(node->token_pos(), |
| 504 new_exception, |
| 505 new_stacktrace); |
| 506 } |
| 507 |
| 508 } // namespace dart |
OLD | NEW |