Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, 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 library fasta.body_builder; | |
| 6 | |
| 7 import 'package:dart_parser/src/parser.dart' show | |
| 8 FormalParameterType, | |
| 9 optional; | |
| 10 | |
| 11 import 'package:dart_parser/src/error_kind.dart' show | |
| 12 ErrorKind; | |
| 13 | |
| 14 import 'package:kernel/ast.dart'; | |
| 15 | |
| 16 import 'package:kernel/clone.dart' show | |
| 17 CloneVisitor; | |
| 18 | |
| 19 import 'package:kernel/transformations/flags.dart' show | |
| 20 TransformerFlag; | |
| 21 | |
| 22 import 'package:kernel/class_hierarchy.dart' show | |
| 23 ClassHierarchy; | |
| 24 | |
| 25 import 'package:kernel/core_types.dart' show | |
| 26 CoreTypes; | |
| 27 | |
| 28 import 'package:dart_scanner/src/token.dart' show | |
| 29 BeginGroupToken, | |
| 30 ErrorToken, | |
| 31 Token, | |
| 32 isBinaryOperator, | |
| 33 isMinusOperator; | |
| 34 | |
| 35 import '../errors.dart' show | |
| 36 InputError, | |
| 37 internalError; | |
| 38 | |
| 39 import '../errors.dart' as errors show | |
| 40 inputError; | |
| 41 | |
| 42 import '../source/scope_listener.dart' show | |
| 43 JumpTargetKind, | |
| 44 NullValue, | |
| 45 ScopeListener; | |
| 46 | |
| 47 import '../builder/scope.dart' show | |
| 48 AccessErrorBuilder, | |
| 49 AmbiguousBuilder, | |
| 50 Scope; | |
| 51 | |
| 52 import '../source/outline_builder.dart' show | |
| 53 asyncMarkerFromTokens; | |
| 54 | |
| 55 import 'builder_accessors.dart'; | |
| 56 | |
| 57 import 'frontend_accessors.dart' show | |
| 58 buildIsNull, | |
| 59 makeBinary, | |
| 60 makeLet; | |
| 61 | |
| 62 import 'builder_accessors.dart' as builder_accessors show | |
| 63 throwNoSuchMethodError; | |
| 64 | |
| 65 import '../quote.dart' show | |
| 66 Quote, | |
| 67 analyzeQuote, | |
| 68 unescape, | |
| 69 unescapeFirstStringPart, | |
| 70 unescapeLastStringPart, | |
| 71 unescapeString; | |
| 72 | |
| 73 import '../modifier.dart' show | |
| 74 Modifier, | |
| 75 constMask, | |
| 76 finalMask; | |
| 77 | |
| 78 import 'redirecting_factory_body.dart' show | |
| 79 getRedirectionTarget; | |
| 80 | |
| 81 import 'kernel_builder.dart'; | |
| 82 | |
| 83 const bool showNits = false; | |
| 84 | |
| 85 class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { | |
| 86 final KernelLibraryBuilder library; | |
| 87 | |
| 88 final MemberBuilder member; | |
| 89 | |
| 90 final KernelClassBuilder classBuilder; | |
| 91 | |
| 92 final ClassHierarchy hierarchy; | |
| 93 | |
| 94 final CoreTypes coreTypes; | |
| 95 | |
| 96 final bool isInstanceMember; | |
| 97 | |
| 98 final Map<String, FieldInitializer> fieldInitializers = | |
| 99 <String, FieldInitializer>{}; | |
| 100 | |
| 101 final Scope enclosingScope; | |
| 102 | |
| 103 Scope formalParameterScope; | |
| 104 | |
| 105 bool isFirstIdentifier = false; | |
| 106 | |
| 107 bool hasParserError = false; | |
| 108 | |
| 109 bool inInitializer = false; | |
| 110 | |
| 111 bool inCatchClause = false; | |
| 112 | |
| 113 int functionNestingLevel = 0; | |
| 114 | |
| 115 Statement compileTimeErrorInTry; | |
| 116 | |
| 117 Statement compileTimeErrorInLoopOrSwitch; | |
| 118 | |
| 119 Scope switchScope; | |
| 120 | |
| 121 CloneVisitor cloner; | |
| 122 | |
| 123 BodyBuilder(this.library, this.member, Scope scope, this.formalParameterScope, | |
| 124 this.hierarchy, this.coreTypes, this.classBuilder, this.isInstanceMember) | |
| 125 : enclosingScope = scope, | |
| 126 super(scope); | |
| 127 | |
| 128 bool get inConstructor { | |
| 129 return functionNestingLevel == 0 && member is KernelConstructorBuilder; | |
| 130 } | |
| 131 | |
| 132 bool get isInstanceContext { | |
| 133 return isInstanceMember || member is KernelConstructorBuilder; | |
| 134 } | |
| 135 | |
| 136 void push(Object node) { | |
| 137 isFirstIdentifier = false; | |
| 138 inInitializer = false; | |
| 139 super.push(node); | |
| 140 } | |
| 141 | |
| 142 Expression popForValue() => toValue(pop()); | |
| 143 | |
| 144 Expression popForEffect() => toEffect(pop()); | |
| 145 | |
| 146 Expression toValue(Object node) { | |
| 147 if (node is UnresolvedIdentifier) { | |
| 148 return throwNoSuchMethodError(node.name.name, new Arguments.empty(), | |
| 149 node.fileOffset, isGetter: true); | |
| 150 } else if (node is BuilderAccessor) { | |
| 151 return node.buildSimpleRead(); | |
| 152 } else if (node is TypeVariableBuilder) { | |
| 153 TypeParameterType type = node.buildTypesWithBuiltArguments(null); | |
| 154 if (!isInstanceContext && type.parameter.parent is Class) { | |
| 155 return buildCompileTimeError( | |
| 156 "Type variables can only be used in instance methods."); | |
| 157 } else { | |
| 158 return new TypeLiteral(type); | |
| 159 } | |
| 160 } else if (node is TypeDeclarationBuilder) { | |
| 161 return new TypeLiteral(node.buildTypesWithBuiltArguments(null)); | |
| 162 } else if (node is KernelTypeBuilder) { | |
| 163 return new TypeLiteral(node.build()); | |
| 164 } else if (node is Expression) { | |
| 165 return node; | |
| 166 } else if (node is PrefixBuilder) { | |
| 167 return buildCompileTimeError("A library can't be used as an expression."); | |
| 168 } else { | |
| 169 return internalError("Unhandled: ${node.runtimeType}"); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 Expression toEffect(Object node) { | |
| 174 if (node is BuilderAccessor) return node.buildForEffect(); | |
| 175 return toValue(node); | |
| 176 } | |
| 177 | |
| 178 List<Expression> popListForValue(int n) { | |
| 179 List<Expression> list = | |
| 180 new List<Expression>.filled(n, null, growable: true); | |
|
asgerf
2017/01/13 18:39:06
I think the recommended way of doing this is <Expr
ahe
2017/01/16 08:32:09
Who makes this recommendation?
asgerf
2017/01/16 11:52:26
It is here:
https://api.dartlang.org/stable/1.21.1
ahe
2017/01/16 12:32:38
I think I disagree with the advice when it comes t
| |
| 181 for (int i = n - 1; i >= 0; i--) { | |
| 182 list[i] = popForValue(); | |
| 183 } | |
| 184 return list; | |
| 185 } | |
| 186 | |
| 187 List<Expression> popListForEffect(int n) { | |
| 188 List<Expression> list = | |
| 189 new List<Expression>.filled(n, null, growable: true); | |
| 190 for (int i = n - 1; i >= 0; i--) { | |
| 191 list[i] = popForEffect(); | |
| 192 } | |
| 193 return list; | |
| 194 } | |
| 195 | |
| 196 Block popBlock(int count) { | |
| 197 List<Statement> statements = popList(count) ?? <Statement>[]; | |
| 198 List<Statement> copy; | |
| 199 for (int i = 0; i < statements.length; i++) { | |
| 200 var statement = statements[i]; | |
| 201 if (statement is List) { | |
| 202 if (copy == null) { | |
| 203 copy = new List<Statement>.from(statements.getRange(0, i)); | |
|
asgerf
2017/01/13 18:39:07
Maybe use ??= here
ahe
2017/01/16 08:32:09
Done.
| |
| 204 } | |
| 205 copy.addAll(statement); | |
| 206 } else if (copy != null) { | |
| 207 copy.add(statement); | |
| 208 } | |
| 209 } | |
| 210 return new Block(copy ?? statements); | |
| 211 } | |
| 212 | |
| 213 Statement popStatementIfNotNull(Object value) { | |
| 214 return value == null ? null : popStatement(); | |
| 215 } | |
| 216 | |
| 217 Statement popStatement() { | |
| 218 var statement = pop(); | |
| 219 if (statement is List) { | |
| 220 return new Block(new List<Statement>.from(statement)); | |
| 221 } else { | |
| 222 return statement; | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 void ignore(Unhandled value) { | |
| 227 pop(); | |
| 228 } | |
| 229 | |
| 230 void enterSwitchScope() { | |
| 231 push(switchScope ?? NullValue.SwitchScope); | |
| 232 switchScope = scope; | |
| 233 } | |
| 234 | |
| 235 void exitSwitchScope() { | |
| 236 switchScope = pop(); | |
| 237 } | |
| 238 | |
| 239 Uri get uri => library.fileUri ?? library.uri; | |
| 240 | |
| 241 JumpTarget createJumpTarget(JumpTargetKind kind) => new JumpTarget(kind); | |
| 242 | |
| 243 void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { | |
| 244 debugEvent("Metadata"); | |
| 245 pop(); // Arguments. | |
| 246 popIfNotNull(periodBeforeName); // Postfix. | |
| 247 pop(); // Type arguments. | |
| 248 pop(); // Expression or type name (depends on arguments). | |
| 249 // TODO(ahe): Implement metadata on local declarations. | |
| 250 } | |
| 251 | |
| 252 void endMetadataStar(int count, bool forParameter) { | |
| 253 debugEvent("MetadataStar"); | |
| 254 push(NullValue.Metadata); | |
| 255 } | |
| 256 | |
| 257 void endTopLevelFields(int count, Token beginToken, Token endToken) { | |
| 258 debugEvent("TopLevelFields"); | |
| 259 doFields(count); | |
| 260 } | |
| 261 | |
| 262 void endFields(int count, Token beginToken, Token endToken) { | |
| 263 debugEvent("Fields"); | |
| 264 doFields(count); | |
| 265 pop(); // Metadata. | |
| 266 } | |
| 267 | |
| 268 void doFields(int count) { | |
| 269 List nodes = popList(count); | |
| 270 pop(); // Type. | |
| 271 pop(); // Modifiers. | |
| 272 for (var node in nodes) { | |
| 273 if (node is Identifier) { | |
| 274 // Ignore, there's no initializer. | |
| 275 } else if (node is VariableDeclaration) { | |
| 276 FieldBuilder field; | |
| 277 if (classBuilder != null) { | |
| 278 field = classBuilder.members[node.name]; | |
|
asgerf
2017/01/13 18:39:07
What if a setter has the same name as a final fiel
ahe
2017/01/16 08:32:09
Added an internal error and TODO.
| |
| 279 } else { | |
| 280 field = library.members[node.name]; | |
| 281 } | |
| 282 field.initializer = node.initializer; | |
| 283 } else { | |
| 284 internalError("Unhandled: ${node.runtimeType}"); | |
| 285 } | |
| 286 } | |
| 287 } | |
| 288 | |
| 289 void endMember() { | |
| 290 debugEvent("Member"); | |
| 291 checkEmpty(); | |
| 292 } | |
| 293 | |
| 294 void endFunctionBody(int count, Token beginToken, Token endToken) { | |
| 295 debugEvent("FunctionBody"); | |
| 296 if (beginToken == null) { | |
| 297 assert(count == 0); | |
| 298 push(NullValue.Block); | |
| 299 } else { | |
| 300 Block block = popBlock(count); | |
| 301 exitLocalScope(); | |
| 302 push(block); | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 void prepareInitializers() { | |
|
asgerf
2017/01/13 18:39:06
It's not clear if this is part of the event listen
ahe
2017/01/16 08:32:09
I like the idea of @override, and I could potentia
ahe
2017/01/18 11:51:44
Followed up in CL 2645513002.
| |
| 307 scope = formalParameterScope; | |
| 308 assert(fieldInitializers.isEmpty); | |
| 309 final member = this.member; | |
| 310 if (member is KernelConstructorBuilder) { | |
| 311 Constructor constructor = member.constructor; | |
| 312 classBuilder.members.forEach((String name, Builder builder) { | |
| 313 if (builder is KernelFieldBuilder && builder.isInstanceMember) { | |
| 314 // TODO(ahe): Compute initializers (as in `field = initializer`). | |
| 315 fieldInitializers[name] = new FieldInitializer(builder.field, null) | |
| 316 ..parent = constructor; | |
| 317 } | |
| 318 }); | |
| 319 if (member.formals != null) { | |
| 320 for (KernelFormalParameterBuilder formal in member.formals) { | |
| 321 if (formal.hasThis) { | |
| 322 FieldInitializer initializer = fieldInitializers[formal.name]; | |
| 323 if (initializer != null) { | |
| 324 fieldInitializers.remove(formal.name); | |
| 325 initializer.value = new VariableGet(formal.declaration) | |
| 326 ..parent = initializer; | |
| 327 member.addInitializer(initializer); | |
| 328 } | |
| 329 } | |
| 330 } | |
| 331 } | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 void beginConstructorInitializer(Token token) { | |
| 336 debugEvent("beginConstructorInitializer"); | |
| 337 inInitializer = true; | |
| 338 } | |
| 339 | |
| 340 void endConstructorInitializer(Token token) { | |
| 341 debugEvent("endConstructorInitializer"); | |
| 342 assert(!inInitializer); | |
| 343 final member = this.member; | |
| 344 var node = pop(); | |
| 345 Initializer initializer; | |
| 346 if (node is Initializer) { | |
| 347 initializer = node; | |
| 348 } else if (node is BuilderAccessor) { | |
| 349 initializer = node.buildFieldInitializer(fieldInitializers); | |
| 350 } else if (node is ConstructorInvocation) { | |
| 351 initializer = new SuperInitializer(node.target, node.arguments); | |
| 352 } else { | |
| 353 if (node is !Throw) { | |
| 354 node = wrapInvalid(node); | |
| 355 } | |
| 356 initializer = | |
| 357 new LocalInitializer(new VariableDeclaration.forValue(node)); | |
| 358 } | |
| 359 if (member is KernelConstructorBuilder) { | |
| 360 member.addInitializer(initializer); | |
| 361 } else { | |
| 362 inputError("Can't have initializers: ${member.name}", token.charOffset); | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 void handleNoInitializers() { | |
| 367 debugEvent("NoInitializers"); | |
| 368 } | |
| 369 | |
| 370 void endInitializers(int count, Token beginToken, Token endToken) { | |
| 371 debugEvent("Initializers"); | |
| 372 } | |
| 373 | |
| 374 void finishFunction(FormalParameters formals, | |
| 375 AsyncMarker asyncModifier, Statement body) { | |
| 376 debugEvent("finishFunction"); | |
| 377 KernelFunctionBuilder builder = member; | |
| 378 if (builder is KernelConstructorBuilder) { | |
| 379 if (asyncModifier != AsyncMarker.Sync) { | |
| 380 // TODO(ahe): Change this to a null check. | |
| 381 inputError("Can't be marked as ${asyncModifier}: ${builder.name}", | |
| 382 body?.fileOffset); | |
| 383 } | |
| 384 } else if (builder is KernelProcedureBuilder) { | |
| 385 builder.asyncModifier = asyncModifier; | |
| 386 } else { | |
| 387 internalError("Unhandled: ${builder.runtimeType}"); | |
| 388 } | |
| 389 builder.body = body; | |
| 390 if (formals?.optional != null) { | |
| 391 Iterator<FormalParameterBuilder> formalBuilders = | |
| 392 builder.formals.skip(formals.required.length).iterator; | |
| 393 for (VariableDeclaration parameter in formals.optional.formals) { | |
| 394 bool hasMore = formalBuilders.moveNext(); | |
| 395 assert(hasMore); | |
| 396 VariableDeclaration realParameter = formalBuilders.current.target; | |
| 397 Expression initializer = parameter.initializer ?? new NullLiteral(); | |
| 398 realParameter.initializer = initializer | |
| 399 ..parent = realParameter; | |
| 400 } | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 void endExpressionStatement(Token token) { | |
| 405 debugEvent("ExpressionStatement"); | |
| 406 push(new ExpressionStatement(popForEffect())); | |
| 407 } | |
| 408 | |
| 409 void endArguments(int count, Token beginToken, Token endToken) { | |
| 410 debugEvent("Arguments"); | |
| 411 List arguments = popList(count) ?? <Expression>[]; | |
| 412 int firstNamedArgument = arguments.length; | |
| 413 for (int i = 0; i < arguments.length; i++) { | |
| 414 var node = arguments[i]; | |
| 415 if (node is NamedExpression) { | |
| 416 firstNamedArgument = i < firstNamedArgument ? i : firstNamedArgument; | |
| 417 } else { | |
| 418 arguments[i] = node = toValue(node); | |
| 419 if (i > firstNamedArgument) { | |
| 420 internalError("Expected named argument: $node"); | |
| 421 } | |
| 422 } | |
| 423 } | |
| 424 if (firstNamedArgument < arguments.length) { | |
| 425 List<Expression> positional = new List<Expression>.from( | |
| 426 arguments.getRange(0, firstNamedArgument)); | |
| 427 List<NamedExpression> named = new List<NamedExpression>.from( | |
| 428 arguments.getRange(firstNamedArgument,arguments.length)); | |
| 429 push(new Arguments(positional, named: named)); | |
| 430 } else { | |
| 431 push(new Arguments(arguments)); | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 void handleParenthesizedExpression(BeginGroupToken token) { | |
| 436 debugEvent("ParenthesizedExpression"); | |
| 437 push(popForValue()); | |
| 438 } | |
| 439 | |
| 440 void endSend(Token token) { | |
| 441 debugEvent("Send"); | |
| 442 Arguments arguments = pop(); | |
| 443 List typeArguments = pop(); | |
| 444 Object receiver = pop(); | |
| 445 if (arguments != null && typeArguments != null) { | |
| 446 arguments.types.addAll(typeArguments); | |
| 447 } else { | |
| 448 assert(typeArguments == null); | |
| 449 } | |
| 450 if (receiver is Identifier) { | |
| 451 Name name = new Name(receiver.name, library.library); | |
| 452 if (arguments == null) { | |
| 453 push(new IncompletePropertyAccessor(this, token.charOffset, name)); | |
| 454 } else { | |
| 455 push(new SendAccessor(this, token.charOffset, name, arguments)); | |
| 456 } | |
| 457 } else if (arguments == null) { | |
| 458 push(receiver); | |
| 459 } else { | |
| 460 push(finishSend(receiver, arguments, token.charOffset)); | |
| 461 } | |
| 462 } | |
| 463 | |
| 464 finishSend(Object receiver, Arguments arguments, int charOffset) { | |
| 465 if (receiver is BuilderAccessor) { | |
| 466 return receiver.doInvocation(charOffset, arguments); | |
| 467 } else if (receiver is UnresolvedIdentifier) { | |
| 468 return throwNoSuchMethodError(receiver.name.name, arguments, | |
| 469 receiver.fileOffset); | |
| 470 } else { | |
| 471 return buildMethodInvocation(toValue(receiver), new Name("call"), | |
|
asgerf
2017/01/13 18:39:07
The Name object should be put in a final static fi
ahe
2017/01/16 08:32:09
Done.
| |
| 472 arguments, charOffset); | |
| 473 } | |
| 474 } | |
| 475 | |
| 476 void beginCascade(Token token) { | |
| 477 debugEvent("beginCascade"); | |
| 478 Expression expression = popForValue(); | |
| 479 if (expression is CascadeReceiver) { | |
| 480 push(expression); | |
| 481 push(new VariableAccessor( | |
| 482 this, expression.fileOffset, expression.variable)); | |
| 483 expression.extend(); | |
| 484 } else { | |
| 485 VariableDeclaration variable = | |
| 486 new VariableDeclaration.forValue(expression); | |
| 487 push(new CascadeReceiver(variable)); | |
| 488 push(new VariableAccessor(this, expression.fileOffset, variable)); | |
| 489 } | |
| 490 } | |
| 491 | |
| 492 void endCascade() { | |
| 493 debugEvent("endCascade"); | |
| 494 Expression expression = popForEffect(); | |
| 495 CascadeReceiver cascadeReceiver = pop(); | |
| 496 cascadeReceiver.finalize(expression); | |
| 497 push(cascadeReceiver); | |
| 498 } | |
| 499 | |
| 500 void handleBinaryExpression(Token token) { | |
| 501 debugEvent("BinaryExpression"); | |
| 502 if (optional(".", token) || optional("..", token)) { | |
| 503 return doDotOrCascadeExpression(token); | |
| 504 } | |
| 505 if (optional("&&", token) || optional("||", token)) { | |
| 506 return doLogicalExpression(token); | |
| 507 } | |
| 508 if (optional("??", token)) return doIfNull(token); | |
| 509 if (optional("?.", token)) return doIfNotNull(token); | |
| 510 Expression argument = popForValue(); | |
| 511 var receiver = pop(); | |
| 512 bool isSuper = false; | |
| 513 if (receiver is ThisAccessor && receiver.isSuper) { | |
| 514 isSuper = true; | |
| 515 receiver = new ThisExpression(); | |
| 516 } | |
| 517 push(buildBinaryOperator(toValue(receiver), token, argument, isSuper)); | |
| 518 } | |
| 519 | |
| 520 Expression buildBinaryOperator(Expression a, Token token, Expression b, | |
| 521 bool isSuper) { | |
| 522 bool negate = false; | |
| 523 String operator = token.stringValue; | |
| 524 if (identical("!=", operator)) { | |
| 525 operator = "=="; | |
| 526 negate = true; | |
| 527 } | |
| 528 if (!isBinaryOperator(operator) && !isMinusOperator(operator)) { | |
| 529 return buildCompileTimeError("Not an operator: '$operator'.", | |
| 530 token.charOffset); | |
| 531 } else { | |
| 532 Expression result = makeBinary(a, new Name(operator), null, b); | |
| 533 if (isSuper) { | |
| 534 result = toSuperMethodInvocation(result); | |
| 535 } | |
| 536 return negate ? new Not(result) : result; | |
| 537 } | |
| 538 } | |
| 539 | |
| 540 void doLogicalExpression(Token token) { | |
| 541 Expression argument = popForValue(); | |
| 542 Expression receiver = popForValue(); | |
| 543 push(new LogicalExpression(receiver, token.stringValue, argument)); | |
| 544 } | |
| 545 | |
| 546 /// Handle `a ?? b`. | |
| 547 void doIfNull(Token token) { | |
| 548 Expression b = popForValue(); | |
| 549 Expression a = popForValue(); | |
| 550 VariableDeclaration variable = new VariableDeclaration.forValue(a); | |
| 551 push(makeLet(variable, | |
| 552 new ConditionalExpression(buildIsNull(new VariableGet(variable)), | |
| 553 b, new VariableGet(variable), const DynamicType()))); | |
| 554 } | |
| 555 | |
| 556 /// Handle `a?.b(...)`. | |
| 557 void doIfNotNull(Token token) { | |
| 558 IncompleteSend send = pop(); | |
| 559 push(send.withReceiver(pop(), isNullAware: true)); | |
| 560 } | |
| 561 | |
| 562 void doDotOrCascadeExpression(Token token) { | |
| 563 // TODO(ahe): Handle null-aware. | |
| 564 IncompleteSend send = pop(); | |
| 565 Object receiver = optional(".", token) ? pop() : popForValue(); | |
| 566 push(send.withReceiver(receiver)); | |
| 567 } | |
| 568 | |
| 569 Expression toSuperMethodInvocation(MethodInvocation node) { | |
| 570 Member target = lookupSuperMember(node.name); | |
| 571 bool isNoSuchMethod = target == null; | |
| 572 if (target is Procedure) { | |
| 573 if (!target.isAccessor) { | |
| 574 if (areArgumentsCompatible(target.function, node.arguments)) { | |
| 575 // TODO(ahe): Use [DirectMethodInvocation] when possible. | |
| 576 Expression result = new DirectMethodInvocation(new ThisExpression(), | |
| 577 target, node.arguments); | |
| 578 result = new SuperMethodInvocation(node.name, node.arguments, null); | |
| 579 return result; | |
| 580 } else { | |
| 581 isNoSuchMethod = true; | |
| 582 } | |
| 583 } | |
| 584 } | |
| 585 if (isNoSuchMethod) { | |
| 586 return throwNoSuchMethodError( | |
| 587 node.name.name, node.arguments, node.fileOffset, isSuper: true); | |
| 588 } | |
| 589 // TODO(ahe): Use [DirectPropertyGet] when possible. | |
| 590 Expression receiver = new DirectPropertyGet(new ThisExpression(), target); | |
| 591 receiver = new SuperPropertyGet(node.name, target); | |
| 592 return buildMethodInvocation(receiver, new Name("call"), node.arguments, | |
| 593 node.fileOffset); | |
| 594 } | |
| 595 | |
| 596 bool areArgumentsCompatible(FunctionNode function, Arguments arguments) { | |
| 597 // TODO(ahe): Implement this. | |
| 598 return true; | |
| 599 } | |
| 600 | |
| 601 Expression throwNoSuchMethodError(String name, Arguments arguments, | |
| 602 int charOffset, {bool isSuper: false, isGetter: false, isSetter: false}) { | |
| 603 return builder_accessors.throwNoSuchMethodError(name, arguments, uri, | |
| 604 charOffset, coreTypes, isSuper: isSuper, isGetter: isGetter, | |
| 605 isSetter: isSetter); | |
| 606 } | |
| 607 | |
| 608 MapLiteral buildMapLiteral(Map map) { | |
|
asgerf
2017/01/13 18:39:06
buildConstantStringMapLiteral?
The current name w
ahe
2017/01/16 08:32:09
It's not used anymore.
| |
| 609 List<MapEntry> entries = <MapEntry>[]; | |
| 610 map.forEach((key, value) { | |
| 611 entries.add( | |
| 612 new MapEntry(new StringLiteral("$key"), new StringLiteral("$value"))); | |
| 613 }); | |
| 614 return new MapLiteral(entries, isConst: true); | |
| 615 } | |
| 616 | |
| 617 Member lookupSuperMember(Name name, {bool isSetter: false}) { | |
| 618 Class superclass = classBuilder.cls.superclass; | |
| 619 return superclass == null | |
| 620 ? null | |
| 621 : hierarchy.getDispatchTarget(superclass, name, setter: isSetter); | |
| 622 } | |
| 623 | |
| 624 Constructor lookupConstructor(Name name, {bool isSuper}) { | |
| 625 Class cls = classBuilder.cls; | |
| 626 if (isSuper) { | |
| 627 cls = cls.superclass; | |
| 628 while (cls.isMixinApplication) { | |
| 629 cls = cls.superclass; | |
| 630 } | |
| 631 } | |
| 632 if (cls != null) { | |
| 633 for (Constructor constructor in cls.constructors) { | |
| 634 if (constructor.name == name) return constructor; | |
| 635 } | |
| 636 } | |
| 637 return null; | |
| 638 } | |
| 639 | |
| 640 void beginExpression(Token token) { | |
| 641 debugEvent("beginExpression"); | |
| 642 isFirstIdentifier = true; | |
| 643 } | |
| 644 | |
| 645 Builder computeSetter(Builder builder, Scope scope, String name) { | |
| 646 if (builder.isSetter) return builder; | |
| 647 if (builder.isGetter) return scope.lookupSetter(name); | |
| 648 return builder.isField ? (builder.isFinal ? null : builder) : null; | |
| 649 } | |
| 650 | |
| 651 void handleIdentifier(Token token) { | |
| 652 debugEvent("handleIdentifier"); | |
| 653 String name = token.value; | |
| 654 if (isFirstIdentifier) { | |
| 655 assert(!inInitializer || this.scope == enclosingScope || | |
| 656 this.scope.parent == enclosingScope); | |
| 657 // This deals with this kind of initializer: `C(a) : a = a;` | |
| 658 Scope scope = inInitializer ? enclosingScope : this.scope; | |
| 659 Builder builder = scope.lookup(name); | |
| 660 push(builderToFirstExpression(builder, name, token.charOffset)); | |
| 661 } else { | |
| 662 push(new Identifier(name)..fileOffset = token.charOffset); | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 builderToFirstExpression(Builder builder, String name, int charOffset, | |
| 667 {bool isPrefix: false}) { | |
| 668 if (builder == null || (!isInstanceContext && builder.isInstanceMember)) { | |
| 669 if (!isPrefix && identical(name, "dynamic") && builder == null) { | |
| 670 return new KernelInterfaceTypeBuilder(name, null); | |
| 671 } | |
| 672 Name n = new Name(name, library.library); | |
| 673 if (!isPrefix && isInstanceContext) { | |
| 674 assert(builder == null); | |
| 675 return new ThisPropertyAccessor(this, charOffset, n, null, null); | |
| 676 } else { | |
| 677 return new UnresolvedIdentifier(n) | |
| 678 ..fileOffset = charOffset; | |
| 679 } | |
| 680 } else if (builder.isTypeDeclaration) { | |
| 681 return builder; | |
| 682 } else if (builder.isLocal) { | |
| 683 return new VariableAccessor(this, charOffset, builder.target); | |
| 684 } else if (builder.isInstanceMember) { | |
| 685 return new ThisPropertyAccessor(this, charOffset, | |
| 686 new Name(name, library.library), null, null); | |
| 687 } else if (builder.isRegularMethod) { | |
| 688 assert(builder.isStatic || builder.isTopLevel); | |
| 689 return new StaticAccessor(this, charOffset, builder.target, null); | |
| 690 } else if (builder is PrefixBuilder) { | |
| 691 return builder; | |
| 692 } else if (builder is MixedAccessor) { | |
| 693 return new StaticAccessor(this, charOffset, builder.getter.target, | |
| 694 builder.setter.target); | |
| 695 } else { | |
| 696 if (builder is AccessErrorBuilder) { | |
| 697 AccessErrorBuilder error = builder; | |
| 698 builder = error.builder; | |
| 699 } | |
| 700 if (builder.target == null) { | |
| 701 return internalError("Unhandled: ${builder}"); | |
| 702 } | |
| 703 Member getter = builder.target.hasGetter ? builder.target : null; | |
| 704 Member setter = builder.target.hasSetter ? builder.target : null; | |
| 705 setter ??= computeSetter(builder, scope, name)?.target; | |
| 706 return | |
| 707 new StaticAccessor(this, charOffset, getter, setter); | |
| 708 } | |
| 709 } | |
| 710 | |
| 711 void handleQualified(Token period) { | |
| 712 debugEvent("Qualified"); | |
| 713 Identifier name = pop(); | |
| 714 var receiver = pop(); | |
| 715 push([receiver, name]); | |
| 716 } | |
| 717 | |
| 718 void beginLiteralString(Token token) { | |
| 719 debugEvent("beginLiteralString"); | |
| 720 push(token); | |
| 721 } | |
| 722 | |
| 723 void handleStringPart(Token token) { | |
| 724 debugEvent("StringPart"); | |
| 725 push(token); | |
| 726 } | |
| 727 | |
| 728 void endLiteralString(int interpolationCount) { | |
| 729 debugEvent("endLiteralString"); | |
| 730 if (interpolationCount == 0) { | |
| 731 Token token = pop(); | |
| 732 push(new StringLiteral(unescapeString(token.value))); | |
| 733 } else { | |
| 734 List parts = popList(1 + interpolationCount * 2); | |
| 735 Token first = parts.first; | |
| 736 Token last = parts.last; | |
| 737 Quote quote = analyzeQuote(first.value); | |
| 738 List<Expression> expressions = <Expression>[]; | |
| 739 expressions.add(new StringLiteral(unescapeFirstStringPart( | |
| 740 first.value, quote))); | |
| 741 for (int i = 1; i < parts.length - 1; i++) { | |
| 742 var part = parts[i]; | |
| 743 if (part is Token) { | |
| 744 expressions.add(new StringLiteral(unescape(part.value, quote))); | |
| 745 } else { | |
| 746 expressions.add(toValue(part)); | |
| 747 } | |
| 748 } | |
| 749 expressions.add( | |
| 750 new StringLiteral(unescapeLastStringPart(last.value, quote))); | |
| 751 push(new StringConcatenation(expressions)); | |
| 752 } | |
| 753 } | |
| 754 | |
| 755 void handleStringJuxtaposition(int literalCount) { | |
| 756 debugEvent("StringJuxtaposition"); | |
| 757 List<Expression> parts = popListForValue(literalCount); | |
| 758 List<Expression> expressions; | |
| 759 // Flatten string juxtapositions of string interpolation. | |
| 760 for (int i = 0; i < parts.length; i++) { | |
| 761 Expression part = parts[i]; | |
| 762 if (part is StringConcatenation) { | |
| 763 if (expressions == null) { | |
| 764 expressions = parts.sublist(0, i); | |
| 765 } | |
| 766 expressions.addAll(part.expressions); | |
| 767 } else { | |
| 768 if (expressions != null) { | |
| 769 expressions.add(part); | |
| 770 } | |
| 771 } | |
| 772 } | |
| 773 push(new StringConcatenation(expressions ?? parts)); | |
| 774 } | |
| 775 | |
| 776 void handleLiteralInt(Token token) { | |
| 777 debugEvent("LiteralInt"); | |
| 778 push(new IntLiteral(int.parse(token.value))); | |
| 779 } | |
| 780 | |
| 781 void endReturnStatement( | |
| 782 bool hasExpression, Token beginToken, Token endToken) { | |
| 783 debugEvent("ReturnStatement"); | |
| 784 Expression expression = hasExpression ? popForValue() : null; | |
| 785 if (expression != null && inConstructor) { | |
| 786 push(buildCompileTimeErrorStatement("Can't return from a constructor.", | |
| 787 beginToken.charOffset)); | |
| 788 } else { | |
| 789 push(new ReturnStatement(expression)); | |
| 790 } | |
| 791 } | |
| 792 | |
| 793 void endIfStatement(Token ifToken, Token elseToken) { | |
| 794 Statement elsePart = popStatementIfNotNull(elseToken); | |
| 795 Statement thenPart = popStatement(); | |
| 796 Expression condition = popForValue(); | |
| 797 push(new IfStatement(condition, thenPart, elsePart)); | |
| 798 } | |
| 799 | |
| 800 void endInitializer(Token assignmentOperator) { | |
| 801 debugEvent("Initializer"); | |
| 802 assert(assignmentOperator.stringValue == "="); | |
| 803 Expression initializer = popForValue(); | |
| 804 Identifier identifier = pop(); | |
| 805 push(new VariableDeclaration(identifier.name, initializer: initializer)); | |
| 806 } | |
| 807 | |
| 808 void endInitializedIdentifier() { | |
| 809 // TODO(ahe): Use [InitializedIdentifier] here? | |
| 810 debugEvent("InitializedIdentifier"); | |
| 811 TreeNode node = pop(); | |
| 812 VariableDeclaration variable; | |
| 813 if (node is VariableDeclaration) { | |
| 814 variable = node; | |
| 815 } else if (node is Identifier) { | |
| 816 variable = new VariableDeclaration(node.name); | |
| 817 } else { | |
| 818 internalError("unhandled identifier: ${node.runtimeType}"); | |
| 819 } | |
| 820 push(variable); | |
| 821 scope[variable.name] = new KernelVariableBuilder(variable); | |
| 822 } | |
| 823 | |
| 824 void endVariablesDeclaration(int count, Token endToken) { | |
| 825 debugEvent("VariablesDeclaration"); | |
| 826 List<VariableDeclaration> variables = popList(count); | |
| 827 DartType type = pop(); | |
| 828 int modifiers = Modifier.validate(pop()); | |
| 829 bool isConst = (modifiers & constMask) != 0; | |
| 830 bool isFinal = (modifiers & finalMask) != 0; | |
| 831 if (type != null || isConst || isFinal) { | |
| 832 type ??= const DynamicType(); | |
| 833 for (VariableDeclaration variable in variables) { | |
| 834 variable | |
| 835 ..type = type | |
| 836 ..isConst = isConst | |
| 837 ..isFinal = isFinal; | |
| 838 } | |
| 839 } | |
| 840 if (variables.length != 1) { | |
| 841 push(variables); | |
| 842 } else { | |
| 843 push(variables.single); | |
| 844 } | |
| 845 } | |
| 846 | |
| 847 void endBlock(int count, Token beginToken, Token endToken) { | |
| 848 debugEvent("Block"); | |
| 849 Block block = popBlock(count); | |
| 850 exitLocalScope(); | |
| 851 push(block); | |
| 852 } | |
| 853 | |
| 854 void handleAssignmentExpression(Token token) { | |
| 855 debugEvent("AssignmentExpression"); | |
| 856 Expression value = popForValue(); | |
| 857 var accessor = pop(); | |
| 858 if (accessor is TypeDeclarationBuilder) { | |
| 859 push(wrapInvalid( | |
| 860 new TypeLiteral(accessor.buildTypesWithBuiltArguments(null)))); | |
| 861 } else if (accessor is! BuilderAccessor) { | |
| 862 push(buildCompileTimeError("Can't assign to this.", token.charOffset)); | |
| 863 } else { | |
| 864 push(new DelayedAssignment(this, token.charOffset, accessor, value, | |
| 865 token.stringValue)); | |
| 866 } | |
| 867 } | |
| 868 | |
| 869 void enterLoop() { | |
| 870 if (peek() is LabelTarget) { | |
| 871 LabelTarget target = peek(); | |
| 872 enterBreakTarget(target.breakTarget); | |
| 873 enterContinueTarget(target.continueTarget); | |
| 874 } else{ | |
| 875 enterBreakTarget(); | |
| 876 enterContinueTarget(); | |
| 877 } | |
| 878 } | |
| 879 | |
| 880 void exitLoopOrSwitch(Statement statement) { | |
| 881 if (compileTimeErrorInLoopOrSwitch != null) { | |
| 882 push(compileTimeErrorInLoopOrSwitch); | |
| 883 compileTimeErrorInLoopOrSwitch = null; | |
| 884 } else { | |
| 885 push(statement); | |
| 886 } | |
| 887 } | |
| 888 | |
| 889 void endForStatement( | |
| 890 int updateExpressionCount, Token beginToken, Token endToken) { | |
| 891 debugEvent("ForStatement"); | |
| 892 Statement body = popStatement(); | |
| 893 List<Expression> updates = popListForEffect(updateExpressionCount); | |
| 894 Statement conditionStatement = popStatement(); | |
| 895 Expression condition = null; | |
| 896 if (conditionStatement is ExpressionStatement) { | |
| 897 condition = conditionStatement.expression; | |
| 898 } else { | |
| 899 assert(conditionStatement is EmptyStatement); | |
| 900 } | |
| 901 List<VariableDeclaration> variables = <VariableDeclaration>[]; | |
| 902 var variableOrExpression = pop(); | |
| 903 Statement begin; | |
| 904 if (variableOrExpression is BuilderAccessor) { | |
| 905 variableOrExpression = variableOrExpression.buildForEffect(); | |
| 906 } | |
| 907 if (variableOrExpression is VariableDeclaration) { | |
| 908 variables.add(variableOrExpression); | |
| 909 } else if (variableOrExpression is List) { | |
| 910 variables.addAll(variableOrExpression); | |
| 911 } else if (variableOrExpression == null) { | |
| 912 // Do nothing. | |
| 913 } else if (variableOrExpression is Expression) { | |
| 914 begin = new ExpressionStatement(variableOrExpression); | |
| 915 } else { | |
| 916 return internalError("Unhandled: ${variableOrExpression.runtimeType}"); | |
| 917 } | |
| 918 exitLocalScope(); | |
| 919 JumpTarget continueTarget = exitContinueTarget(); | |
| 920 JumpTarget breakTarget = exitBreakTarget(); | |
| 921 if (continueTarget.hasUsers) { | |
| 922 body = new LabeledStatement(body); | |
| 923 continueTarget.resolveContinues(body); | |
| 924 } | |
| 925 Statement result = new ForStatement(variables, condition, updates, body); | |
| 926 if (begin != null) { | |
| 927 result = new Block(<Statement>[begin, result]); | |
| 928 } | |
| 929 if (breakTarget.hasUsers) { | |
| 930 result = new LabeledStatement(result); | |
| 931 breakTarget.resolveBreaks(result); | |
| 932 } | |
| 933 exitLoopOrSwitch(result); | |
| 934 } | |
| 935 | |
| 936 void endAwaitExpression(Token beginToken, Token endToken) { | |
| 937 debugEvent("AwaitExpression"); | |
| 938 push(new AwaitExpression(popForValue())); | |
| 939 } | |
| 940 | |
| 941 void handleAsyncModifier(Token asyncToken, Token starToken) { | |
| 942 debugEvent("AsyncModifier"); | |
| 943 push(asyncMarkerFromTokens(asyncToken, starToken)); | |
| 944 } | |
| 945 | |
| 946 void handleLiteralList( | |
| 947 int count, Token beginToken, Token constKeyword, Token endToken) { | |
| 948 debugEvent("LiteralList"); | |
| 949 List<Expression> expressions = popListForValue(count); | |
| 950 List<DartType> typeArguments = pop(); | |
| 951 DartType typeArgument = const DynamicType(); | |
| 952 if (typeArguments != null) { | |
| 953 typeArgument = typeArguments.first; | |
| 954 if (typeArguments.length > 1) { | |
| 955 typeArgument = const DynamicType(); | |
| 956 warning("Too many type arguments on List literal.", | |
| 957 beginToken.charOffset); | |
| 958 } | |
| 959 } | |
| 960 push(new ListLiteral(expressions, typeArgument: typeArgument, | |
| 961 isConst: constKeyword != null)); | |
| 962 } | |
| 963 | |
| 964 void handleLiteralBool(Token token) { | |
| 965 debugEvent("LiteralBool"); | |
| 966 bool value = optional("true", token); | |
| 967 assert(value || optional("false", token)); | |
| 968 push(new BoolLiteral(value)); | |
| 969 } | |
| 970 | |
| 971 void handleLiteralDouble(Token token) { | |
| 972 debugEvent("LiteralDouble"); | |
| 973 push(new DoubleLiteral(double.parse(token.value))); | |
| 974 } | |
| 975 | |
| 976 void handleLiteralNull(Token token) { | |
| 977 debugEvent("LiteralNull"); | |
| 978 push(new NullLiteral()); | |
| 979 } | |
| 980 | |
| 981 void handleLiteralMap( | |
| 982 int count, Token beginToken, Token constKeyword, Token endToken) { | |
| 983 debugEvent("LiteralMap"); | |
| 984 List<MapEntry> entries = popList(count) ?? <MapEntry>[]; | |
| 985 List<DartType> typeArguments = pop(); | |
| 986 DartType keyType = const DynamicType(); | |
| 987 DartType valueType = const DynamicType(); | |
| 988 if (typeArguments != null) { | |
| 989 if (typeArguments.length != 2) { | |
| 990 keyType = const DynamicType(); | |
| 991 valueType = const DynamicType(); | |
| 992 warning("Map literal requires two type arguments.", | |
| 993 beginToken.charOffset); | |
| 994 } else { | |
| 995 keyType = typeArguments[0]; | |
| 996 valueType = typeArguments[0]; | |
|
asgerf
2017/01/13 18:39:06
Should be typeArguments[1]
ahe
2017/01/16 08:32:09
Done.
| |
| 997 } | |
| 998 } | |
| 999 push(new MapLiteral(entries, keyType: keyType, valueType: valueType, | |
| 1000 isConst: constKeyword != null)); | |
| 1001 } | |
| 1002 | |
| 1003 void endLiteralMapEntry(Token colon, Token endToken) { | |
| 1004 debugEvent("LiteralMapEntry"); | |
| 1005 Expression value = popForValue(); | |
| 1006 Expression key = popForValue(); | |
| 1007 push(new MapEntry(key, value)); | |
| 1008 } | |
| 1009 | |
| 1010 void beginLiteralSymbol(Token token) { | |
| 1011 isFirstIdentifier = false; | |
| 1012 } | |
| 1013 | |
| 1014 String symbolPartToString(name) { | |
| 1015 if (name is Identifier) { | |
| 1016 return name.name; | |
| 1017 } else if (name is Operator) { | |
| 1018 return name.name; | |
| 1019 } else { | |
| 1020 return internalError("Unhandled: ${name.runtimeType}"); | |
| 1021 } | |
| 1022 } | |
| 1023 | |
| 1024 void endLiteralSymbol(Token hashToken, int identifierCount) { | |
| 1025 debugEvent("LiteralSymbol"); | |
| 1026 String value; | |
| 1027 if (identifierCount == 1) { | |
| 1028 value = symbolPartToString(popForValue()); | |
| 1029 } else { | |
| 1030 List parts = popList(identifierCount); | |
| 1031 value = symbolPartToString(parts.first); | |
| 1032 for (int i = 1; i < parts.length; i++) { | |
| 1033 value += ".${symbolPartToString(parts[i])}"; | |
| 1034 } | |
| 1035 } | |
| 1036 push(new SymbolLiteral(value)); | |
| 1037 } | |
| 1038 | |
| 1039 DartType toKernelType(String name, List<DartType> arguments) { | |
| 1040 if (identical(name, "void")) return const VoidType(); | |
| 1041 if (identical(name, "dynamic")) return const DynamicType(); | |
| 1042 Builder builder = scope.lookup(name); | |
| 1043 if (builder is TypeDeclarationBuilder) { | |
| 1044 return builder.buildTypesWithBuiltArguments(arguments); | |
| 1045 } | |
| 1046 if (builder == null) { | |
| 1047 print("$uri: Type not found: $name"); | |
| 1048 } else { | |
| 1049 print("$uri: Not a type: $name"); | |
| 1050 } | |
| 1051 // TODO(ahe): Create an error somehow. | |
| 1052 return const DynamicType(); | |
| 1053 } | |
| 1054 | |
| 1055 void endType(Token beginToken, Token endToken) { | |
| 1056 // TODO(ahe): The scope is wrong for return types of generic functions. | |
| 1057 debugEvent("Type"); | |
| 1058 List<DartType> arguments = pop(); | |
| 1059 var name = pop(); | |
| 1060 if (name is List) { | |
| 1061 if (name.length != 2) { | |
| 1062 return internalError("Unexpected: $name.length"); | |
| 1063 } | |
| 1064 var prefix = name[0]; | |
| 1065 if (prefix is Identifier) { | |
| 1066 prefix = prefix.name; | |
| 1067 } | |
| 1068 var suffix = name[1]; | |
| 1069 if (suffix is Identifier) { | |
| 1070 suffix = suffix.name; | |
| 1071 } | |
| 1072 Builder builder; | |
| 1073 if (prefix is Builder) { | |
| 1074 builder = prefix; | |
| 1075 } else { | |
| 1076 builder = scope.lookup(prefix); | |
| 1077 } | |
| 1078 if (builder is PrefixBuilder) { | |
| 1079 name = builder.exports[suffix]; | |
| 1080 } else { | |
| 1081 return inputError( | |
| 1082 "Can't be used as a type: '${debugName(prefix, suffix)}'.", | |
| 1083 beginToken.charOffset); | |
| 1084 } | |
| 1085 } | |
| 1086 if (name is Identifier) { | |
| 1087 name = name.name; | |
| 1088 } | |
| 1089 if (name is BuilderAccessor) { | |
| 1090 warning("'${beginToken.value}' isn't a type.", beginToken.charOffset); | |
| 1091 push(const DynamicType()); | |
| 1092 } else if (name is UnresolvedIdentifier) { | |
| 1093 warning("'${name.name}' isn't a type.", beginToken.charOffset); | |
| 1094 push(const DynamicType()); | |
| 1095 } else if (name is TypeVariableBuilder) { | |
| 1096 push(name.buildTypesWithBuiltArguments(arguments)); | |
| 1097 } else if (name is TypeDeclarationBuilder) { | |
| 1098 push(name.buildTypesWithBuiltArguments(arguments)); | |
| 1099 } else if (name is TypeBuilder) { | |
| 1100 push(name.build()); | |
| 1101 } else { | |
| 1102 push(toKernelType(name, arguments)); | |
| 1103 } | |
| 1104 if (peek() is TypeParameterType) { | |
| 1105 TypeParameterType type = peek(); | |
| 1106 if (!isInstanceContext && type.parameter.parent is Class) { | |
| 1107 pop(); | |
| 1108 warning("Type variables can only be used in instance methods.", | |
| 1109 beginToken.charOffset); | |
| 1110 push(const DynamicType()); | |
| 1111 } | |
| 1112 } | |
| 1113 } | |
| 1114 | |
| 1115 void handleVoidKeyword(Token token) { | |
| 1116 debugEvent("VoidKeyword"); | |
| 1117 push(const VoidType()); | |
| 1118 } | |
| 1119 | |
| 1120 void handleAsOperator(Token operator, Token endToken) { | |
| 1121 debugEvent("AsOperator"); | |
| 1122 DartType type = pop(); | |
| 1123 Expression expression = popForValue(); | |
| 1124 push(new AsExpression(expression, type)); | |
| 1125 } | |
| 1126 | |
| 1127 void handleIsOperator(Token operator, Token not, Token endToken) { | |
| 1128 debugEvent("IsOperator"); | |
| 1129 DartType type = pop(); | |
| 1130 Expression expression = popForValue(); | |
| 1131 expression = new IsExpression(expression, type); | |
| 1132 if (not != null) { | |
| 1133 expression = new Not(expression); | |
| 1134 } | |
| 1135 push(expression); | |
| 1136 } | |
| 1137 | |
| 1138 void handleConditionalExpression(Token question, Token colon) { | |
| 1139 debugEvent("ConditionalExpression"); | |
| 1140 Expression elseExpression = popForValue(); | |
| 1141 Expression thenExpression = popForValue(); | |
| 1142 Expression condition = popForValue(); | |
| 1143 push(new ConditionalExpression( | |
| 1144 condition, thenExpression, elseExpression, const DynamicType())); | |
| 1145 } | |
| 1146 | |
| 1147 void endThrowExpression(Token throwToken, Token endToken) { | |
| 1148 debugEvent("ThrowExpression"); | |
| 1149 Expression expression = popForValue(); | |
| 1150 push(new Throw(expression)); | |
| 1151 } | |
| 1152 | |
| 1153 void endFormalParameter(Token thisKeyword) { | |
| 1154 debugEvent("FormalParameter"); | |
| 1155 if (thisKeyword != null) { | |
| 1156 if (!inConstructor) { | |
| 1157 return inputError("'this' parameters can only be used on constructors.", | |
| 1158 thisKeyword.charOffset); | |
| 1159 } | |
| 1160 } | |
| 1161 Identifier name = pop(); | |
| 1162 DartType type = pop(); | |
| 1163 pop(); // Modifiers. | |
| 1164 ignore(Unhandled.Metadata); | |
| 1165 VariableDeclaration variable; | |
| 1166 if (!inCatchClause && functionNestingLevel == 0) { | |
| 1167 var builder = formalParameterScope.lookup(name.name); | |
| 1168 if (builder == null) { | |
| 1169 return inputError("'${name.name}' isn't a field in this class.", | |
| 1170 name.fileOffset); | |
| 1171 } | |
| 1172 if (thisKeyword == null) { | |
| 1173 variable = builder.build(); | |
| 1174 variable.initializer = name.initializer; | |
| 1175 } else if (builder.isField && builder.parent == classBuilder) { | |
| 1176 FieldBuilder field = builder; | |
| 1177 if (type != null) { | |
| 1178 nit("Ignoring type on 'this' parameter '${name.name}'.", | |
| 1179 name.fileOffset); | |
| 1180 } | |
| 1181 type = field.target.type ?? const DynamicType(); | |
| 1182 variable = new VariableDeclaration(name.name, type: type, | |
| 1183 initializer: name.initializer); | |
| 1184 } else { | |
| 1185 return inputError("'${name.name}' isn't a field in this class.", | |
| 1186 name.fileOffset); | |
| 1187 } | |
| 1188 } else { | |
| 1189 variable = new VariableDeclaration(name.name, | |
| 1190 type: type ?? const DynamicType(), initializer: name.initializer); | |
| 1191 } | |
| 1192 push(variable); | |
| 1193 } | |
| 1194 | |
| 1195 void endOptionalFormalParameters( | |
| 1196 int count, Token beginToken, Token endToken) { | |
| 1197 debugEvent("OptionalFormalParameters"); | |
| 1198 FormalParameterType kind = optional("{", beginToken) | |
| 1199 ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | |
| 1200 push(new OptionalFormals(kind, popList(count))); | |
| 1201 } | |
| 1202 | |
| 1203 void beginFunctionTypedFormalParameter(Token token) { | |
| 1204 debugEvent("beginFunctionTypedFormalParameter"); | |
| 1205 functionNestingLevel++; | |
| 1206 } | |
| 1207 | |
| 1208 void handleFunctionTypedFormalParameter(Token token) { | |
| 1209 debugEvent("FunctionTypedFormalParameter"); | |
| 1210 if (inCatchClause || functionNestingLevel != 0) { | |
| 1211 exitLocalScope(); | |
| 1212 } | |
| 1213 FormalParameters formals = pop(); | |
| 1214 ignore(Unhandled.TypeVariables); | |
| 1215 Identifier name = pop(); | |
| 1216 DartType returnType = pop(); | |
| 1217 push(formals.toFunctionType(returnType)); | |
| 1218 push(name); | |
| 1219 functionNestingLevel--; | |
| 1220 } | |
| 1221 | |
| 1222 void handleValuedFormalParameter(Token equals, Token token) { | |
| 1223 debugEvent("ValuedFormalParameter"); | |
| 1224 Expression initializer = popForValue(); | |
| 1225 Identifier name = pop(); | |
| 1226 push(new InitializedIdentifier(name.name, initializer)); | |
| 1227 } | |
| 1228 | |
| 1229 void endFormalParameters(int count, Token beginToken, Token endToken) { | |
| 1230 debugEvent("FormalParameters"); | |
| 1231 OptionalFormals optional; | |
| 1232 if (count > 0 && peek() is OptionalFormals) { | |
| 1233 optional = pop(); | |
| 1234 count--; | |
| 1235 } | |
| 1236 FormalParameters formals = new FormalParameters( | |
| 1237 popList(count) ?? <VariableDeclaration>[], optional); | |
| 1238 push(formals); | |
| 1239 if (inCatchClause || functionNestingLevel != 0) { | |
| 1240 enterLocalScope(formals.computeFormalParameterScope(scope)); | |
| 1241 } | |
| 1242 } | |
| 1243 | |
| 1244 void beginCatchClause(Token token) { | |
| 1245 debugEvent("beginCatchClause"); | |
| 1246 inCatchClause = true; | |
| 1247 } | |
| 1248 | |
| 1249 void endCatchClause(Token token) { | |
| 1250 debugEvent("CatchClause"); | |
| 1251 inCatchClause = false; | |
| 1252 } | |
| 1253 | |
| 1254 void handleCatchBlock(Token onKeyword, Token catchKeyword) { | |
| 1255 debugEvent("CatchBlock"); | |
| 1256 Block body = pop(); | |
| 1257 if (catchKeyword != null) { | |
| 1258 exitLocalScope(); | |
| 1259 } | |
| 1260 FormalParameters catchParameters = popIfNotNull(catchKeyword); | |
| 1261 DartType type = popIfNotNull(onKeyword) ?? const DynamicType(); | |
| 1262 VariableDeclaration exception; | |
| 1263 VariableDeclaration stackTrace; | |
| 1264 if (catchParameters != null) { | |
| 1265 if (catchParameters.required.length > 0) { | |
| 1266 exception = catchParameters.required[0]; | |
| 1267 } | |
| 1268 if (catchParameters.required.length > 1) { | |
| 1269 stackTrace = catchParameters.required[1]; | |
| 1270 } | |
| 1271 if (catchParameters.required.length > 2 || | |
| 1272 catchParameters.optional != null) { | |
| 1273 body = new Block(<Statement>[new InvalidStatement()]); | |
| 1274 compileTimeErrorInTry ??= buildCompileTimeErrorStatement( | |
| 1275 "Invalid catch arguments.", catchKeyword.next.charOffset); | |
| 1276 } | |
| 1277 } | |
| 1278 push(new Catch(exception, body, guard: type, stackTrace: stackTrace)); | |
| 1279 } | |
| 1280 | |
| 1281 void endTryStatement( | |
| 1282 int catchCount, Token tryKeyword, Token finallyKeyword) { | |
| 1283 Statement finallyBlock = popStatementIfNotNull(finallyKeyword); | |
| 1284 List<Catch> catches = popList(catchCount); | |
| 1285 Statement tryBlock = popStatement(); | |
| 1286 if (compileTimeErrorInTry == null) { | |
| 1287 if (catches != null) { | |
| 1288 tryBlock = new TryCatch(tryBlock, catches); | |
| 1289 } | |
| 1290 if (finallyBlock != null) { | |
| 1291 tryBlock = new TryFinally(tryBlock, finallyBlock); | |
| 1292 } | |
| 1293 push(tryBlock); | |
| 1294 } else { | |
| 1295 push(compileTimeErrorInTry); | |
| 1296 compileTimeErrorInTry = null; | |
| 1297 } | |
| 1298 } | |
| 1299 | |
| 1300 void handleNoExpression(Token token) { | |
| 1301 debugEvent("NoExpression"); | |
| 1302 push(NullValue.Expression); | |
| 1303 } | |
| 1304 | |
| 1305 void handleIndexedExpression( | |
| 1306 Token openCurlyBracket, Token closeCurlyBracket) { | |
| 1307 debugEvent("IndexedExpression"); | |
| 1308 Expression index = popForValue(); | |
| 1309 Expression receiver = popForValue(); | |
| 1310 push(IndexAccessor.make(this, openCurlyBracket.charOffset, receiver, index, | |
| 1311 null, null)); | |
| 1312 } | |
| 1313 | |
| 1314 void handleUnaryPrefixExpression(Token token) { | |
| 1315 debugEvent("UnaryPrefixExpression"); | |
| 1316 Expression expression = popForValue(); | |
| 1317 if (optional("!", token)) { | |
| 1318 push(new Not(expression)); | |
| 1319 } else { | |
| 1320 String operator = token.stringValue; | |
| 1321 if (optional("-", token)) { | |
| 1322 operator = "unary-"; | |
| 1323 } | |
| 1324 push(buildMethodInvocation(expression, new Name(operator), | |
| 1325 new Arguments.empty(), token.charOffset)); | |
| 1326 } | |
| 1327 } | |
| 1328 | |
| 1329 Name incrementOperator(Token token) { | |
| 1330 if (optional("++", token)) return new Name("+"); | |
| 1331 if (optional("--", token)) return new Name("-"); | |
| 1332 return internalError("Unknown increment operator: ${token.value}"); | |
| 1333 } | |
| 1334 | |
| 1335 void handleUnaryPrefixAssignmentExpression(Token token) { | |
| 1336 debugEvent("UnaryPrefixAssignmentExpression"); | |
| 1337 var accessor = pop(); | |
| 1338 if (accessor is BuilderAccessor) { | |
| 1339 push(accessor.buildPrefixIncrement(incrementOperator(token))); | |
| 1340 } else { | |
| 1341 push(wrapInvalid(toValue(accessor))); | |
| 1342 } | |
| 1343 } | |
| 1344 | |
| 1345 void handleUnaryPostfixAssignmentExpression(Token token) { | |
| 1346 debugEvent("UnaryPostfixAssignmentExpression"); | |
| 1347 var accessor = pop(); | |
| 1348 if (accessor is BuilderAccessor) { | |
| 1349 push(new DelayedPostfixIncrement(this, token.charOffset, accessor, | |
| 1350 incrementOperator(token), null)); | |
| 1351 } else { | |
| 1352 push(wrapInvalid(toValue(accessor))); | |
| 1353 } | |
| 1354 } | |
| 1355 | |
| 1356 void endConstructorReference( | |
| 1357 Token start, Token periodBeforeName, Token endToken) { | |
| 1358 debugEvent("ConstructorReference"); | |
| 1359 // A constructor reference can contain up to three identifiers: | |
| 1360 // | |
| 1361 // a) type <type-arguments>? | |
| 1362 // b) type <type-arguments>? . name | |
| 1363 // c) prefix . type <type-arguments>? | |
| 1364 // d) prefix . type <type-arguments>? . name | |
| 1365 // | |
| 1366 // This isn't a legal constructor reference: | |
| 1367 // | |
| 1368 // type . name <type-arguments> | |
| 1369 // | |
| 1370 // But the parser can't tell this from type c) above. | |
| 1371 // | |
| 1372 // This method pops 2 (or 3 if periodBeforeName != null) values from the | |
| 1373 // stack and pushes 3 values: a type, a list of type arguments, and a name. | |
| 1374 // | |
| 1375 // If the constructor reference can be resolved, type is either a | |
| 1376 // ClassBuilder, or a ThisPropertyAccessor. Otherwise, it's an error that | |
| 1377 // should be handled later. | |
| 1378 Identifier suffix = popIfNotNull(periodBeforeName); | |
| 1379 Identifier identifier; | |
| 1380 List<DartType> typeArguments = pop(); | |
| 1381 var type = pop(); | |
| 1382 if (type is List) { | |
| 1383 var prefix = type[0]; | |
| 1384 identifier = type[1]; | |
| 1385 if (prefix is PrefixBuilder) { | |
| 1386 // TODO(ahe): Handle privacy in prefix.exports. | |
| 1387 type = builderToFirstExpression( | |
| 1388 prefix.exports[identifier.name], identifier.name, start.charOffset); | |
| 1389 identifier = null; | |
| 1390 } else if (prefix is ClassBuilder) { | |
| 1391 type = prefix; | |
| 1392 } else { | |
| 1393 type = new Identifier(start.value)..fileOffset = start.charOffset; | |
| 1394 } | |
| 1395 } | |
| 1396 String name; | |
| 1397 if (identifier != null && suffix != null) { | |
| 1398 name = "${identifier.name}.${suffix.name}"; | |
| 1399 } else if (identifier != null) { | |
| 1400 name = identifier.name; | |
| 1401 } else if (suffix != null) { | |
| 1402 name = suffix.name; | |
| 1403 } else { | |
| 1404 name = ""; | |
| 1405 } | |
| 1406 push(type); | |
| 1407 push(typeArguments ?? NullValue.TypeArguments); | |
| 1408 push(name); | |
| 1409 } | |
| 1410 | |
| 1411 Expression buildStaticInvocation(Member target, Arguments arguments, | |
| 1412 {bool isConst: false}) { | |
| 1413 List<TypeParameter> typeParameters = target.function.typeParameters; | |
| 1414 if (target is Constructor) { | |
| 1415 typeParameters = target.enclosingClass.typeParameters; | |
| 1416 } | |
| 1417 if (!addDefaultArguments(target.function, arguments, typeParameters)) { | |
| 1418 return throwNoSuchMethodError(target.name.name, arguments, -1); | |
| 1419 } | |
| 1420 if (target is Constructor) { | |
| 1421 return new ConstructorInvocation(target, arguments) | |
| 1422 ..isConst = isConst; | |
| 1423 } else { | |
| 1424 return new StaticInvocation(target, arguments) | |
| 1425 ..isConst = isConst; | |
| 1426 } | |
| 1427 } | |
| 1428 | |
| 1429 bool addDefaultArguments(FunctionNode function, Arguments arguments, | |
| 1430 List<TypeParameter> typeParameters) { | |
| 1431 bool missingInitializers = false; | |
| 1432 | |
| 1433 Expression defaultArgumentFrom(Expression expression) { | |
| 1434 if (expression == null) { | |
| 1435 missingInitializers = true; | |
| 1436 return null; | |
| 1437 } | |
| 1438 cloner ??= new CloneVisitor(); | |
| 1439 return cloner.clone(expression); | |
| 1440 } | |
| 1441 | |
| 1442 if (arguments.positional.length < function.requiredParameterCount || | |
| 1443 arguments.positional.length > function.positionalParameters.length) { | |
| 1444 return false; | |
| 1445 } | |
| 1446 for (int i = arguments.positional.length; i < function.positionalParameters. length; i++) { | |
| 1447 var expression = defaultArgumentFrom(function.positionalParameters[i].init ializer); | |
|
asgerf
2017/01/13 18:39:06
Long line
ahe
2017/01/16 08:32:09
Done.
| |
| 1448 expression?.parent = arguments; | |
| 1449 arguments.positional.add(expression); | |
| 1450 } | |
| 1451 Map<String, VariableDeclaration> names; | |
| 1452 if (function.namedParameters.isNotEmpty) { | |
| 1453 names = <String, VariableDeclaration>{}; | |
| 1454 for (VariableDeclaration parameter in function.namedParameters) { | |
| 1455 names[parameter.name] = parameter; | |
| 1456 } | |
| 1457 } | |
| 1458 if (arguments.named.isNotEmpty) { | |
| 1459 if (names == null) return false; | |
| 1460 for (NamedExpression argument in arguments.named) { | |
| 1461 VariableDeclaration parameter = names.remove(argument.name); | |
| 1462 if (parameter == null) { | |
| 1463 return false; | |
| 1464 } | |
| 1465 } | |
| 1466 } | |
| 1467 if (names != null) { | |
| 1468 for (String name in names.keys) { | |
| 1469 VariableDeclaration parameter = names[name]; | |
| 1470 arguments.named.add( | |
| 1471 new NamedExpression( | |
| 1472 name, defaultArgumentFrom(parameter.initializer)) | |
| 1473 ..parent = arguments); | |
| 1474 } | |
| 1475 } | |
| 1476 if (typeParameters.length != arguments.types.length) { | |
| 1477 arguments.types.clear(); | |
| 1478 for (int i = 0; i < typeParameters.length; i++) { | |
| 1479 arguments.types.add(const DynamicType()); | |
| 1480 } | |
| 1481 } | |
| 1482 | |
| 1483 if (missingInitializers) { | |
| 1484 library.addArgumentsWithMissingDefaultValues(arguments, function); | |
| 1485 } | |
| 1486 return true; | |
| 1487 } | |
| 1488 | |
| 1489 void handleNewExpression(Token token) { | |
| 1490 debugEvent("NewExpression"); | |
| 1491 Arguments arguments = pop(); | |
| 1492 String name = pop(); | |
| 1493 List typeArguments = pop(); | |
| 1494 var type = pop(); | |
| 1495 | |
| 1496 if (typeArguments != null) { | |
| 1497 assert(arguments.types.isEmpty); | |
| 1498 arguments.types.addAll(typeArguments); | |
| 1499 } | |
| 1500 | |
| 1501 String errorName; | |
| 1502 if (type is ClassBuilder) { | |
| 1503 Builder b = type.findConstructorOrFactory(name); | |
| 1504 Member target; | |
| 1505 if (b == null) { | |
| 1506 // Not found. Reported below. | |
| 1507 } else if (b.isConstructor) { | |
| 1508 if (type.cls.isAbstract) { | |
| 1509 // TODO(ahe): Generate abstract instantiation error. | |
| 1510 } else { | |
| 1511 target = b.target; | |
| 1512 } | |
| 1513 } else if (b.isFactory) { | |
| 1514 target = getRedirectionTarget(b.target); | |
| 1515 if (target == null) { | |
| 1516 push(buildCompileTimeError( | |
| 1517 "Cyclic definition of factory '${name}'.", | |
| 1518 token.charOffset)); | |
| 1519 return; | |
| 1520 } | |
| 1521 } | |
| 1522 if (target is Constructor || | |
| 1523 (target is Procedure && target.kind == ProcedureKind.Factory)) { | |
| 1524 push(buildStaticInvocation( | |
| 1525 target, arguments, isConst: optional("const", token))); | |
| 1526 return; | |
| 1527 } else { | |
| 1528 errorName = debugName(type.cls.name, name); | |
| 1529 } | |
| 1530 } else { | |
| 1531 errorName = debugName(getNodeName(type), name); | |
| 1532 } | |
| 1533 errorName ??= name; | |
| 1534 push(throwNoSuchMethodError(errorName, arguments, token.charOffset)); | |
| 1535 } | |
| 1536 | |
| 1537 void handleConstExpression(Token token) { | |
| 1538 debugEvent("ConstExpression"); | |
| 1539 handleNewExpression(token); | |
| 1540 } | |
| 1541 | |
| 1542 void endTypeArguments(int count, Token beginToken, Token endToken) { | |
| 1543 debugEvent("TypeArguments"); | |
| 1544 push(popList(count)); | |
| 1545 } | |
| 1546 | |
| 1547 void handleThisExpression(Token token) { | |
| 1548 debugEvent("ThisExpression"); | |
| 1549 if (isFirstIdentifier && isInstanceContext) { | |
| 1550 push(new ThisAccessor(this, token.charOffset, inInitializer)); | |
| 1551 } else { | |
| 1552 push(new IncompleteError( | |
| 1553 this, token.charOffset, "Expected identifier, but got 'this'.")); | |
| 1554 } | |
| 1555 } | |
| 1556 | |
| 1557 void handleSuperExpression(Token token) { | |
| 1558 debugEvent("SuperExpression"); | |
| 1559 if (isFirstIdentifier && isInstanceContext) { | |
| 1560 Member member = this.member.target; | |
| 1561 member.transformerFlags |= TransformerFlag.superCalls; | |
| 1562 push(new ThisAccessor(this, token.charOffset, inInitializer, | |
| 1563 isSuper: true)); | |
| 1564 } else { | |
| 1565 push(new IncompleteError( | |
| 1566 this, token.charOffset, "Expected identifier, but got 'super'.")); | |
| 1567 } | |
| 1568 } | |
| 1569 | |
| 1570 void handleNamedArgument(Token colon) { | |
| 1571 debugEvent("NamedArgument"); | |
| 1572 Expression value = popForValue(); | |
| 1573 Identifier identifier = pop(); | |
| 1574 push(new NamedExpression(identifier.name, value)); | |
| 1575 } | |
| 1576 | |
| 1577 void endFunctionName(Token token) { | |
| 1578 debugEvent("FunctionName"); | |
| 1579 Identifier name = pop(); | |
| 1580 VariableDeclaration variable = new VariableDeclaration( | |
| 1581 name.name, isFinal: true); | |
| 1582 push(new FunctionDeclaration(variable, | |
| 1583 new FunctionNode(new InvalidStatement()))); | |
| 1584 scope[variable.name] = new KernelVariableBuilder(variable); | |
| 1585 enterLocalScope(); | |
| 1586 } | |
| 1587 | |
| 1588 void beginFunction(Token token) { | |
| 1589 debugEvent("beginFunction"); | |
| 1590 functionNestingLevel++; | |
| 1591 } | |
| 1592 | |
| 1593 void beginUnnamedFunction(Token token) { | |
| 1594 debugEvent("beginUnnamedFunction"); | |
| 1595 functionNestingLevel++; | |
| 1596 } | |
| 1597 | |
| 1598 void endFunction(Token getOrSet, Token endToken) { | |
| 1599 debugEvent("Function"); | |
| 1600 Statement body = popStatement(); | |
| 1601 AsyncMarker asyncModifier = pop(); | |
| 1602 if (functionNestingLevel != 0) { | |
| 1603 exitLocalScope(); | |
| 1604 } | |
| 1605 FormalParameters formals = pop(); | |
| 1606 List typeParameters = pop(); | |
| 1607 push(formals.addToFunction(new FunctionNode(body, | |
| 1608 typeParameters: typeParameters, asyncMarker: asyncModifier))); | |
| 1609 functionNestingLevel--; | |
| 1610 } | |
| 1611 | |
| 1612 void endFunctionDeclaration(Token token) { | |
| 1613 debugEvent("FunctionDeclaration"); | |
| 1614 FunctionNode function = pop(); | |
| 1615 exitLocalScope(); | |
| 1616 FunctionDeclaration declaration = pop(); | |
| 1617 function.returnType = pop() ?? const DynamicType(); | |
| 1618 pop(); // Modifiers. | |
| 1619 declaration.function = function; | |
| 1620 function.parent = declaration; | |
| 1621 push(declaration); | |
| 1622 } | |
| 1623 | |
| 1624 void endUnnamedFunction(Token token) { | |
| 1625 debugEvent("UnnamedFunction"); | |
| 1626 Statement body = popStatement(); | |
| 1627 AsyncMarker asyncModifier = pop(); | |
| 1628 exitLocalScope(); | |
| 1629 FormalParameters formals = pop(); | |
| 1630 List typeParameters = pop(); | |
| 1631 FunctionNode function = formals.addToFunction(new FunctionNode(body, | |
| 1632 typeParameters: typeParameters, asyncMarker: asyncModifier)); | |
| 1633 push(new FunctionExpression(function)); | |
| 1634 functionNestingLevel--; | |
| 1635 } | |
| 1636 | |
| 1637 void endDoWhileStatement( | |
| 1638 Token doKeyword, Token whileKeyword, Token endToken) { | |
| 1639 debugEvent("DoWhileStatement"); | |
| 1640 Expression condition = popForValue(); | |
| 1641 Statement body = popStatement(); | |
| 1642 JumpTarget continueTarget = exitContinueTarget(); | |
| 1643 JumpTarget breakTarget = exitBreakTarget(); | |
| 1644 if (continueTarget.hasUsers) { | |
| 1645 body = new LabeledStatement(body); | |
| 1646 continueTarget.resolveContinues(body); | |
| 1647 } | |
| 1648 Statement result = new DoStatement(body, condition); | |
| 1649 if (breakTarget.hasUsers) { | |
| 1650 result = new LabeledStatement(result); | |
| 1651 breakTarget.resolveBreaks(result); | |
| 1652 } | |
| 1653 exitLoopOrSwitch(result); | |
| 1654 } | |
| 1655 | |
| 1656 void endForIn( | |
| 1657 Token awaitToken, Token forToken, Token inKeyword, Token endToken) { | |
| 1658 debugEvent("ForIn"); | |
| 1659 Statement body = popStatement(); | |
| 1660 Expression expression = popForValue(); | |
| 1661 var lvalue = pop(); | |
| 1662 exitLocalScope(); | |
| 1663 JumpTarget continueTarget = exitContinueTarget(); | |
| 1664 JumpTarget breakTarget = exitBreakTarget(); | |
| 1665 if (continueTarget.hasUsers) { | |
| 1666 body = new LabeledStatement(body); | |
| 1667 continueTarget.resolveContinues(body); | |
| 1668 } | |
| 1669 VariableDeclaration variable; | |
| 1670 if (lvalue is VariableDeclaration) { | |
| 1671 variable = lvalue; | |
| 1672 } else if (lvalue is BuilderAccessor) { | |
| 1673 /// We are in this case, where `lvalue` isn't a [VariableDeclaration]: | |
| 1674 /// | |
| 1675 /// for (lvalue in expression) body | |
| 1676 /// | |
| 1677 /// This is normalized to: | |
| 1678 /// | |
| 1679 /// for (final #t in expression) { | |
| 1680 /// element = #t; | |
|
asgerf
2017/01/13 18:39:06
element -> lvalue
There is no `element` mentioned
ahe
2017/01/16 08:32:09
Done.
| |
| 1681 /// body; | |
| 1682 /// } | |
| 1683 variable = new VariableDeclaration.forValue(null); | |
| 1684 body = combineStatements( | |
| 1685 new ExpressionStatement( | |
| 1686 lvalue.buildAssignment( | |
| 1687 new VariableGet(variable), voidContext: true)), | |
| 1688 body); | |
| 1689 } else { | |
| 1690 return inputError("Expected lvalue, but got ${lvalue}", | |
| 1691 forToken.next.next.charOffset); | |
|
asgerf
2017/01/13 18:39:06
Value return in a void method?
ahe
2017/01/16 08:32:09
Changed to throw.
| |
| 1692 } | |
| 1693 Statement result = new ForInStatement(variable, expression, body, | |
| 1694 isAsync: awaitToken != null); | |
| 1695 if (breakTarget.hasUsers) { | |
| 1696 result = new LabeledStatement(result); | |
| 1697 breakTarget.resolveBreaks(result); | |
| 1698 } | |
| 1699 exitLoopOrSwitch(result); | |
| 1700 } | |
| 1701 | |
| 1702 void handleLabel(Token token) { | |
| 1703 debugEvent("Label"); | |
| 1704 Identifier identifier = pop(); | |
| 1705 push(new Label(identifier.name)); | |
| 1706 } | |
| 1707 | |
| 1708 void beginLabeledStatement(Token token, int labelCount) { | |
| 1709 debugEvent("beginLabeledStatement"); | |
| 1710 List<Label> labels = popList(labelCount); | |
| 1711 enterLocalScope(); | |
| 1712 LabelTarget target = new LabelTarget(); | |
| 1713 for (Label label in labels) { | |
| 1714 scope[label.name] = target; | |
| 1715 } | |
| 1716 push(target); | |
| 1717 } | |
| 1718 | |
| 1719 void endLabeledStatement(int labelCount) { | |
| 1720 debugEvent("LabeledStatement"); | |
| 1721 Statement statement = popStatement(); | |
| 1722 LabelTarget target = pop(); | |
| 1723 exitLocalScope(); | |
| 1724 if (target.breakTarget.hasUsers) { | |
| 1725 if (statement is! LabeledStatement) { | |
| 1726 statement = new LabeledStatement(statement); | |
| 1727 } | |
| 1728 target.breakTarget.resolveBreaks(statement); | |
| 1729 } | |
| 1730 if (target.continueTarget.hasUsers) { | |
| 1731 if (statement is! LabeledStatement) { | |
| 1732 statement = new LabeledStatement(statement); | |
| 1733 } | |
| 1734 target.continueTarget.resolveContinues(statement); | |
| 1735 } | |
| 1736 push(statement); | |
| 1737 } | |
| 1738 | |
| 1739 void endRethrowStatement(Token throwToken, Token endToken) { | |
| 1740 debugEvent("RethrowStatement"); | |
| 1741 push(new ExpressionStatement(new Rethrow())); | |
| 1742 } | |
| 1743 | |
| 1744 void handleFinallyBlock(Token finallyKeyword) { | |
| 1745 debugEvent("FinallyBlock"); | |
| 1746 // Do nothing, handled by [endTryStatement]. | |
| 1747 } | |
| 1748 | |
| 1749 void endWhileStatement(Token whileKeyword, Token endToken) { | |
| 1750 debugEvent("WhileStatement"); | |
| 1751 Statement body = popStatement(); | |
| 1752 Expression condition = popForValue(); | |
| 1753 JumpTarget continueTarget = exitContinueTarget(); | |
| 1754 JumpTarget breakTarget = exitBreakTarget(); | |
| 1755 if (continueTarget.hasUsers) { | |
| 1756 body = new LabeledStatement(body); | |
| 1757 continueTarget.resolveContinues(body); | |
| 1758 } | |
| 1759 Statement result = new WhileStatement(condition, body); | |
| 1760 if (breakTarget.hasUsers) { | |
| 1761 result = new LabeledStatement(result); | |
| 1762 breakTarget.resolveBreaks(result); | |
| 1763 } | |
| 1764 exitLoopOrSwitch(result); | |
| 1765 } | |
| 1766 | |
| 1767 void handleEmptyStatement(Token token) { | |
| 1768 debugEvent("EmptyStatement"); | |
| 1769 push(new EmptyStatement()); | |
| 1770 } | |
| 1771 | |
| 1772 void handleAssertStatement( | |
| 1773 Token assertKeyword, Token commaToken, Token semicolonToken) { | |
| 1774 debugEvent("AssertStatement"); | |
| 1775 Expression message = popIfNotNull(commaToken); | |
| 1776 Expression condition = popForValue(); | |
| 1777 push(new AssertStatement(condition, message)); | |
| 1778 } | |
| 1779 | |
| 1780 void endYieldStatement(Token yieldToken, Token starToken, Token endToken) { | |
| 1781 debugEvent("YieldStatement"); | |
| 1782 push(new YieldStatement(popForValue(), isYieldStar: starToken != null)); | |
| 1783 } | |
| 1784 | |
| 1785 void beginSwitchBlock(Token token) { | |
| 1786 debugEvent("beginSwitchBlock"); | |
| 1787 enterLocalScope(); | |
| 1788 enterSwitchScope(); | |
| 1789 enterBreakTarget(); | |
| 1790 } | |
| 1791 | |
| 1792 void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) { | |
| 1793 debugEvent("beginSwitchCase"); | |
| 1794 List labelsAndExpressions = popList(labelCount + expressionCount); | |
| 1795 List<Label> labels = <Label>[]; | |
| 1796 List<Expression> expressions = <Expression>[]; | |
| 1797 if (labelsAndExpressions != null) { | |
| 1798 for (var labelOrExpression in labelsAndExpressions) { | |
| 1799 if (labelOrExpression is Label) { | |
| 1800 labels.add(labelOrExpression); | |
| 1801 } else { | |
| 1802 expressions.add(toValue(labelOrExpression)); | |
| 1803 } | |
| 1804 } | |
| 1805 } | |
| 1806 assert(scope == switchScope); | |
| 1807 for (Label label in labels) { | |
| 1808 Builder existing = scope.local[label.name]; | |
| 1809 if (existing == null) { | |
| 1810 scope[label.name] = createGotoTarget(); | |
| 1811 } else { | |
| 1812 // TODO(ahe): Should validate this is a goto target and not duplicated. | |
| 1813 } | |
| 1814 } | |
| 1815 push(expressions); | |
| 1816 push(labels); | |
| 1817 enterLocalScope(); | |
| 1818 } | |
| 1819 | |
| 1820 void handleSwitchCase( | |
| 1821 int labelCount, | |
| 1822 int expressionCount, | |
| 1823 Token defaultKeyword, | |
| 1824 int statementCount, | |
| 1825 Token firstToken, | |
| 1826 Token endToken) { | |
| 1827 debugEvent("SwitchCase"); | |
| 1828 Block block = popBlock(statementCount); | |
| 1829 exitLocalScope(); | |
| 1830 List<Label> labels = pop(); | |
| 1831 List<Expression> expressions = pop(); | |
| 1832 push(new SwitchCase(expressions, block, isDefault: defaultKeyword != null)); | |
| 1833 push(labels); | |
| 1834 } | |
| 1835 | |
| 1836 void endSwitchStatement(Token switchKeyword, Token endToken) { | |
| 1837 debugEvent("SwitchStatement"); | |
| 1838 // Do nothing. Handled by [endSwitchBlock]. | |
| 1839 } | |
| 1840 | |
| 1841 void endSwitchBlock(int caseCount, Token beginToken, Token endToken) { | |
| 1842 debugEvent("SwitchBlock"); | |
| 1843 List<SwitchCase> cases = | |
| 1844 new List<SwitchCase>.filled(caseCount, null, growable: true); | |
| 1845 for (int i = caseCount - 1; i >= 0; i--) { | |
| 1846 List<Label> labels = pop(); | |
| 1847 SwitchCase current = cases[i] = pop(); | |
| 1848 for (Label label in labels) { | |
| 1849 JumpTarget target = switchScope.lookup(label.name); | |
| 1850 if (target != null) { | |
| 1851 target.resolveGotos(current); | |
| 1852 } | |
| 1853 } | |
| 1854 // TODO(ahe): Validate that there's only one default and it's last. | |
| 1855 } | |
| 1856 JumpTarget target = exitBreakTarget(); | |
| 1857 exitSwitchScope(); | |
| 1858 exitLocalScope(); | |
| 1859 Expression expression = popForValue(); | |
| 1860 Statement result = new SwitchStatement(expression, cases); | |
| 1861 if (target.hasUsers) { | |
| 1862 result = new LabeledStatement(result); | |
| 1863 target.resolveBreaks(result); | |
| 1864 } | |
| 1865 exitLoopOrSwitch(result); | |
| 1866 } | |
| 1867 | |
| 1868 void handleCaseMatch(Token caseKeyword, Token colon) { | |
| 1869 debugEvent("CaseMatch"); | |
| 1870 // Do nothing. Handled by [handleSwitchCase]. | |
| 1871 } | |
| 1872 | |
| 1873 void handleBreakStatement( | |
| 1874 bool hasTarget, Token breakKeyword, Token endToken) { | |
| 1875 debugEvent("BreakStatement"); | |
| 1876 var target = breakTarget; | |
| 1877 String name; | |
| 1878 if (hasTarget) { | |
| 1879 Identifier identifier = pop(); | |
| 1880 name = identifier.name; | |
| 1881 target = scope.lookup(identifier.name); | |
| 1882 } | |
| 1883 if (target == null && name == null) { | |
| 1884 push(compileTimeErrorInLoopOrSwitch = | |
| 1885 buildCompileTimeErrorStatement( | |
| 1886 "No target of break.", breakKeyword.charOffset)); | |
| 1887 } else if (target == null || target is! JumpTarget | |
| 1888 || !target.isBreakTarget) { | |
| 1889 push(compileTimeErrorInLoopOrSwitch = | |
| 1890 buildCompileTimeErrorStatement("Can't break to '$name'.", | |
| 1891 breakKeyword.next.charOffset)); | |
| 1892 } else { | |
| 1893 BreakStatement statement = new BreakStatement(null); | |
| 1894 target.addBreak(statement); | |
| 1895 push(statement); | |
| 1896 } | |
| 1897 } | |
| 1898 | |
| 1899 void handleContinueStatement( | |
| 1900 bool hasTarget, Token continueKeyword, Token endToken) { | |
| 1901 debugEvent("ContinueStatement"); | |
| 1902 var target = continueTarget; | |
| 1903 String name; | |
| 1904 if (hasTarget) { | |
| 1905 Identifier identifier = pop(); | |
| 1906 name = identifier.name; | |
| 1907 target = scope.lookup(identifier.name); | |
| 1908 if (target != null && target is! JumpTarget) { | |
| 1909 push(compileTimeErrorInLoopOrSwitch = | |
| 1910 buildCompileTimeErrorStatement( | |
| 1911 "Target of continue must be a label.", | |
| 1912 continueKeyword.charOffset)); | |
| 1913 return; | |
| 1914 } | |
| 1915 if (target == null) { | |
| 1916 if (switchScope == null) { | |
| 1917 push(buildCompileTimeErrorStatement("Can't find label '$name'.", | |
| 1918 continueKeyword.next.charOffset)); | |
| 1919 return; | |
| 1920 } | |
| 1921 switchScope[identifier.name] = target = createGotoTarget(); | |
| 1922 } | |
| 1923 if (target.isGotoTarget) { | |
| 1924 ContinueSwitchStatement statement = new ContinueSwitchStatement(null); | |
| 1925 target.addGoto(statement); | |
| 1926 push(statement); | |
| 1927 return; | |
| 1928 } | |
| 1929 } | |
| 1930 if (target == null) { | |
| 1931 push(compileTimeErrorInLoopOrSwitch = | |
| 1932 buildCompileTimeErrorStatement("No target of continue.", | |
| 1933 continueKeyword.charOffset)); | |
| 1934 } else if (!target.isContinueTarget) { | |
| 1935 push(compileTimeErrorInLoopOrSwitch = | |
| 1936 buildCompileTimeErrorStatement("Can't continue at '$name'.", | |
| 1937 continueKeyword.next.charOffset)); | |
| 1938 } else { | |
| 1939 BreakStatement statement = new BreakStatement(null); | |
| 1940 target.addContinue(statement); | |
| 1941 push(statement); | |
| 1942 } | |
| 1943 } | |
| 1944 | |
| 1945 void endTypeVariable(Token token, Token extendsOrSuper) { | |
| 1946 logEvent("TypeVariable"); | |
| 1947 // TODO(ahe): Implement this when enabling generic method syntax. | |
| 1948 } | |
| 1949 | |
| 1950 void endTypeVariables(int count, Token beginToken, Token endToken) { | |
| 1951 logEvent("TypeVariables"); | |
| 1952 // TODO(ahe): Implement this when enabling generic method syntax. | |
| 1953 } | |
| 1954 | |
| 1955 void handleModifier(Token token) { | |
| 1956 debugEvent("Modifier"); | |
| 1957 // TODO(ahe): Copied from outline_builder.dart. | |
| 1958 push(new Modifier.fromString(token.stringValue)); | |
| 1959 } | |
| 1960 | |
| 1961 void handleModifiers(int count) { | |
| 1962 debugEvent("Modifiers"); | |
| 1963 // TODO(ahe): Copied from outline_builder.dart. | |
| 1964 push(popList(count) ?? NullValue.Modifiers); | |
| 1965 } | |
| 1966 | |
| 1967 void reportErrorHelper(Token token, ErrorKind kind, Map arguments) { | |
| 1968 super.reportErrorHelper(token, kind, arguments); | |
| 1969 if (!hasParserError) { | |
| 1970 print("$uri:${recoverableErrors.last}"); | |
| 1971 } | |
| 1972 hasParserError = true; | |
| 1973 } | |
| 1974 | |
| 1975 Token expectedExpression(Token token) { | |
| 1976 if (token is ErrorToken) { | |
| 1977 reportErrorToken(token); | |
| 1978 push(new Throw(new StringLiteral("${recoverableErrors.last}"))); | |
| 1979 do { | |
| 1980 token = token.next; | |
| 1981 } while (token is ErrorToken); | |
| 1982 return token; | |
| 1983 } else { | |
| 1984 push(new InvalidExpression()); | |
| 1985 return super.expectedExpression(token); | |
| 1986 } | |
| 1987 } | |
| 1988 | |
| 1989 Token expected(String string, Token token) { | |
| 1990 if (token is ErrorToken) { | |
| 1991 reportErrorToken(token); | |
| 1992 do { | |
| 1993 token = token.next; | |
| 1994 } while (token is ErrorToken); | |
| 1995 return token; | |
| 1996 } | |
| 1997 const List<String> trailing = const <String>[")", "}", ";", ","]; | |
| 1998 if (trailing.contains(token.stringValue) && trailing.contains(string)) { | |
| 1999 // We're just trying to get out an error. | |
| 2000 if (recoverableErrors.isNotEmpty) { | |
| 2001 reportError(token, ErrorKind.UNSPECIFIED, | |
| 2002 {"text": "Expected: '$string', but got '${token.value}'"}); | |
| 2003 } | |
| 2004 return token; | |
| 2005 } | |
| 2006 return super.expected(string, token); | |
| 2007 } | |
| 2008 | |
| 2009 void warning(error, [int charOffset = -1]) { | |
| 2010 String message = new InputError(uri, charOffset, error).format(); | |
| 2011 print(message); | |
| 2012 } | |
| 2013 | |
| 2014 void nit(error, [int charOffset = -1]) { | |
| 2015 if (!showNits) return; | |
| 2016 String message = new InputError(uri, charOffset, error).format(); | |
| 2017 print(message); | |
| 2018 } | |
| 2019 | |
| 2020 Expression buildCompileTimeError(error, [int charOffset = -1]) { | |
| 2021 String message = new InputError(uri, charOffset, error).format(); | |
| 2022 print(message); | |
| 2023 return new Throw(new StringLiteral(message)); | |
| 2024 } | |
| 2025 | |
| 2026 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { | |
| 2027 return new ExpressionStatement(buildCompileTimeError(error, charOffset)); | |
| 2028 } | |
| 2029 | |
| 2030 Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) { | |
| 2031 return new LocalInitializer( | |
| 2032 new VariableDeclaration.forValue( | |
| 2033 buildCompileTimeError(error, charOffset))); | |
| 2034 } | |
| 2035 | |
| 2036 | |
| 2037 Expression buildProblemExpression(Builder builder, String name) { | |
|
asgerf
2017/01/13 18:39:06
Where is this method used? It's not called in this
ahe
2017/01/16 08:32:09
It's used in builder_accessors.dart.
| |
| 2038 if (builder is AmbiguousBuilder) { | |
| 2039 return buildCompileTimeError("Duplicated named: '$name'."); | |
| 2040 } else if (builder is AccessErrorBuilder) { | |
| 2041 return buildCompileTimeError("Access error: '$name'."); | |
| 2042 } else { | |
| 2043 return internalError("Unhandled: ${builder.runtimeType}"); | |
| 2044 } | |
| 2045 } | |
| 2046 | |
| 2047 void handleOperator(Token token) { | |
| 2048 debugEvent("Operator"); | |
| 2049 push(new Operator(token.stringValue)..fileOffset = token.charOffset); | |
| 2050 } | |
| 2051 | |
| 2052 dynamic inputError(String message, [int charOffset = -1]) { | |
| 2053 return errors.inputError(uri, charOffset, message); | |
| 2054 } | |
| 2055 | |
| 2056 void debugEvent(String name) { | |
| 2057 // printEvent(name); | |
| 2058 } | |
| 2059 } | |
| 2060 | |
| 2061 class UnresolvedIdentifier extends InvalidExpression { | |
| 2062 final Name name; | |
| 2063 | |
| 2064 UnresolvedIdentifier(this.name); | |
| 2065 | |
| 2066 String toString() => "unresolved-identifier($name)"; | |
| 2067 } | |
| 2068 | |
| 2069 class Identifier extends InvalidExpression { | |
|
asgerf
2017/01/13 18:39:07
Do these need to be expressions at all? Can't they
ahe
2017/01/16 08:32:09
That's a good point. It's a bigger change due to s
| |
| 2070 final String name; | |
| 2071 | |
| 2072 Identifier(this.name); | |
| 2073 | |
| 2074 Expression get initializer => null; | |
| 2075 | |
| 2076 String toString() => "identifier($name)"; | |
| 2077 } | |
| 2078 | |
| 2079 class Operator extends InvalidExpression { | |
| 2080 final String name; | |
| 2081 | |
| 2082 Operator(this.name); | |
| 2083 | |
| 2084 String toString() => "operator($name)"; | |
| 2085 } | |
| 2086 | |
| 2087 class InitializedIdentifier extends Identifier { | |
| 2088 final Expression initializer; | |
| 2089 | |
| 2090 InitializedIdentifier(String name, this.initializer) | |
| 2091 : super(name); | |
| 2092 | |
| 2093 String toString() => "initialized-identifier($name, $initializer)"; | |
| 2094 } | |
| 2095 | |
| 2096 class Label extends InvalidExpression { | |
| 2097 String name; | |
| 2098 | |
| 2099 Label(this.name); | |
| 2100 | |
| 2101 String toString() => "label($name)"; | |
| 2102 } | |
| 2103 | |
| 2104 class CascadeReceiver extends Let { | |
| 2105 Let nextCascade; | |
| 2106 | |
| 2107 CascadeReceiver(VariableDeclaration variable) | |
| 2108 : super(variable, | |
| 2109 makeLet(new VariableDeclaration.forValue(new InvalidExpression()), | |
| 2110 new VariableGet(variable))) { | |
| 2111 nextCascade = body; | |
| 2112 } | |
| 2113 | |
| 2114 void extend() { | |
| 2115 assert(nextCascade.variable.initializer is! InvalidExpression); | |
| 2116 Let newCascade = makeLet( | |
| 2117 new VariableDeclaration.forValue(new InvalidExpression()), | |
| 2118 nextCascade.body); | |
| 2119 nextCascade.body = newCascade; | |
| 2120 newCascade.parent = nextCascade; | |
| 2121 nextCascade = newCascade; | |
| 2122 } | |
| 2123 | |
| 2124 void finalize(Expression expression) { | |
| 2125 assert(nextCascade.variable.initializer is InvalidExpression); | |
| 2126 nextCascade.variable.initializer = expression; | |
| 2127 expression.parent = nextCascade.variable; | |
| 2128 } | |
| 2129 } | |
| 2130 | |
| 2131 abstract class ContextAccessor extends BuilderAccessor { | |
| 2132 final BuilderHelper helper; | |
| 2133 | |
| 2134 final int charOffset; | |
| 2135 | |
| 2136 final BuilderAccessor accessor; | |
| 2137 | |
| 2138 ContextAccessor(this.helper, this.charOffset, this.accessor); | |
| 2139 | |
| 2140 String get plainNameForRead => internalError("Unsupported operation."); | |
| 2141 | |
| 2142 Expression doInvocation(int charOffset, Arguments arguments) { | |
| 2143 print("$uri:$charOffset: Internal error: Unhandled: ${runtimeType}"); | |
| 2144 return internalError("Unhandled: ${runtimeType}"); | |
| 2145 } | |
| 2146 | |
| 2147 Expression buildSimpleRead(); | |
| 2148 | |
| 2149 Expression buildForEffect(); | |
| 2150 | |
| 2151 Expression buildAssignment(Expression value, {bool voidContext: false}) { | |
| 2152 return internalError("not supported"); | |
| 2153 } | |
| 2154 | |
| 2155 Expression buildNullAwareAssignment(Expression value, DartType type, | |
| 2156 {bool voidContext: false}) { | |
| 2157 return internalError("not supported"); | |
| 2158 } | |
| 2159 | |
| 2160 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | |
| 2161 {bool voidContext: false, Procedure interfaceTarget}) { | |
| 2162 return internalError("not supported"); | |
| 2163 } | |
| 2164 | |
| 2165 Expression buildPrefixIncrement(Name binaryOperator, | |
| 2166 {bool voidContext: false, Procedure interfaceTarget}) { | |
| 2167 return internalError("not supported"); | |
| 2168 } | |
| 2169 | |
| 2170 Expression buildPostfixIncrement(Name binaryOperator, | |
| 2171 {bool voidContext: false, Procedure interfaceTarget}) { | |
| 2172 return internalError("not supported"); | |
| 2173 } | |
| 2174 | |
| 2175 makeInvalidRead() => internalError("not supported"); | |
| 2176 | |
| 2177 makeInvalidWrite(Expression value) => internalError("not supported"); | |
| 2178 } | |
| 2179 | |
| 2180 class DelayedAssignment extends ContextAccessor { | |
| 2181 final Expression value; | |
| 2182 | |
| 2183 final String assignmentOperator; | |
| 2184 | |
| 2185 DelayedAssignment(BuilderHelper helper, int charOffset, | |
| 2186 BuilderAccessor accessor, this.value, this.assignmentOperator) | |
| 2187 : super(helper, charOffset, accessor); | |
| 2188 | |
| 2189 Expression buildSimpleRead() { | |
| 2190 return handleAssignment(false); | |
| 2191 } | |
| 2192 | |
| 2193 Expression buildForEffect() { | |
| 2194 return handleAssignment(true); | |
| 2195 } | |
| 2196 | |
| 2197 Expression handleAssignment(bool voidContext) { | |
| 2198 if (identical("=", assignmentOperator)) { | |
| 2199 return accessor.buildAssignment(value, voidContext: voidContext); | |
| 2200 } else if (identical("+=", assignmentOperator)) { | |
| 2201 return accessor.buildCompoundAssignment( | |
| 2202 new Name("+"), value, voidContext: voidContext); | |
|
asgerf
2017/01/13 18:39:07
These Name objects can be shared (they are not AST
ahe
2017/01/16 08:32:09
Done.
| |
| 2203 } else if (identical("-=", assignmentOperator)) { | |
| 2204 return accessor.buildCompoundAssignment( | |
| 2205 new Name("-"), value, voidContext: voidContext); | |
| 2206 } else if (identical("*=", assignmentOperator)) { | |
| 2207 return accessor.buildCompoundAssignment( | |
| 2208 new Name("*"), value, voidContext: voidContext); | |
| 2209 } else if (identical("%=", assignmentOperator)) { | |
| 2210 return accessor.buildCompoundAssignment( | |
| 2211 new Name("%"), value, voidContext: voidContext); | |
| 2212 } else if (identical("&=", assignmentOperator)) { | |
| 2213 return accessor.buildCompoundAssignment( | |
| 2214 new Name("&"), value, voidContext: voidContext); | |
| 2215 } else if (identical("/=", assignmentOperator)) { | |
| 2216 return accessor.buildCompoundAssignment( | |
| 2217 new Name("/"), value, voidContext: voidContext); | |
| 2218 } else if (identical("<<=", assignmentOperator)) { | |
| 2219 return accessor.buildCompoundAssignment( | |
| 2220 new Name("<<"), value, voidContext: voidContext); | |
| 2221 } else if (identical(">>=", assignmentOperator)) { | |
| 2222 return accessor.buildCompoundAssignment( | |
| 2223 new Name(">>"), value, voidContext: voidContext); | |
| 2224 } else if (identical("??=", assignmentOperator)) { | |
| 2225 return accessor.buildNullAwareAssignment( | |
| 2226 value, const DynamicType(), voidContext: voidContext); | |
| 2227 } else if (identical("^=", assignmentOperator)) { | |
| 2228 return accessor.buildCompoundAssignment( | |
| 2229 new Name("^"), value, voidContext: voidContext); | |
| 2230 } else if (identical("|=", assignmentOperator)) { | |
| 2231 return accessor.buildCompoundAssignment( | |
| 2232 new Name("|"), value, voidContext: voidContext); | |
| 2233 } else if (identical("~/=", assignmentOperator)) { | |
| 2234 return accessor.buildCompoundAssignment( | |
| 2235 new Name("~/"), value, voidContext: voidContext); | |
| 2236 } else { | |
| 2237 return internalError("Unhandled: $assignmentOperator"); | |
| 2238 } | |
| 2239 } | |
| 2240 | |
| 2241 Initializer buildFieldInitializer( | |
| 2242 Map<String, FieldInitializer> initializers) { | |
| 2243 if (!identical("=", assignmentOperator) || | |
| 2244 !accessor.isThisPropertyAccessor) { | |
| 2245 return accessor.buildFieldInitializer(initializers); | |
| 2246 } | |
| 2247 String name = accessor.plainNameForRead; | |
| 2248 FieldInitializer initializer = initializers[name]; | |
| 2249 if (initializer != null && initializer.value == null) { | |
| 2250 initializers.remove(name); | |
| 2251 initializer.value = value | |
| 2252 ..parent = initializer; | |
| 2253 return initializer; | |
| 2254 } | |
| 2255 print("initializer = $initializer"); | |
| 2256 print("initializer.value = ${initializer?.value}"); | |
|
asgerf
2017/01/13 18:39:06
These prints should be removed
ahe
2017/01/16 08:32:09
Done.
| |
| 2257 return accessor.buildFieldInitializer(initializers); | |
| 2258 } | |
| 2259 } | |
| 2260 | |
| 2261 class DelayedPostfixIncrement extends ContextAccessor { | |
| 2262 final Name binaryOperator; | |
| 2263 | |
| 2264 final Procedure interfaceTarget; | |
| 2265 | |
| 2266 DelayedPostfixIncrement(BuilderHelper helper, int charOffset, | |
| 2267 BuilderAccessor accessor, this.binaryOperator, this.interfaceTarget) | |
| 2268 : super(helper, charOffset, accessor); | |
| 2269 | |
| 2270 Expression buildSimpleRead() { | |
| 2271 return accessor.buildPostfixIncrement(binaryOperator, voidContext: false, | |
| 2272 interfaceTarget: interfaceTarget); | |
| 2273 } | |
| 2274 | |
| 2275 Expression buildForEffect() { | |
| 2276 return accessor.buildPostfixIncrement(binaryOperator, voidContext: true, | |
| 2277 interfaceTarget: interfaceTarget); | |
| 2278 } | |
| 2279 } | |
| 2280 | |
| 2281 class JumpTarget extends Builder { | |
| 2282 final List<Statement> users = <Statement>[]; | |
| 2283 | |
| 2284 final JumpTargetKind kind; | |
| 2285 | |
| 2286 JumpTarget(this.kind); | |
| 2287 | |
| 2288 bool get isBreakTarget => kind == JumpTargetKind.Break; | |
| 2289 | |
| 2290 bool get isContinueTarget => kind == JumpTargetKind.Continue; | |
| 2291 | |
| 2292 bool get isGotoTarget => kind == JumpTargetKind.Goto; | |
| 2293 | |
| 2294 bool get hasUsers => users.isNotEmpty; | |
| 2295 | |
| 2296 void addBreak(BreakStatement statement) { | |
| 2297 assert(isBreakTarget); | |
| 2298 users.add(statement); | |
| 2299 } | |
| 2300 | |
| 2301 void addContinue(BreakStatement statement) { | |
| 2302 assert(isContinueTarget); | |
| 2303 users.add(statement); | |
| 2304 } | |
| 2305 | |
| 2306 void addGoto(ContinueSwitchStatement statement) { | |
| 2307 assert(isGotoTarget); | |
| 2308 users.add(statement); | |
| 2309 } | |
| 2310 | |
| 2311 void resolveBreaks(LabeledStatement target) { | |
| 2312 assert(isBreakTarget); | |
| 2313 for (BreakStatement user in users) { | |
| 2314 user.target = target; | |
| 2315 } | |
| 2316 users.clear(); | |
| 2317 } | |
| 2318 | |
| 2319 void resolveContinues(LabeledStatement target) { | |
| 2320 assert(isContinueTarget); | |
| 2321 for (BreakStatement user in users) { | |
| 2322 user.target = target; | |
| 2323 } | |
| 2324 users.clear(); | |
| 2325 } | |
| 2326 | |
| 2327 void resolveGotos(SwitchCase target) { | |
| 2328 assert(isGotoTarget); | |
| 2329 for (ContinueSwitchStatement user in users) { | |
| 2330 user.target = target; | |
| 2331 } | |
| 2332 users.clear(); | |
| 2333 } | |
| 2334 } | |
| 2335 | |
| 2336 class LabelTarget extends Builder implements JumpTarget { | |
| 2337 final JumpTarget breakTarget = new JumpTarget(JumpTargetKind.Break); | |
| 2338 | |
| 2339 final JumpTarget continueTarget = new JumpTarget(JumpTargetKind.Continue); | |
| 2340 | |
| 2341 LabelTarget(); | |
| 2342 | |
| 2343 bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers; | |
| 2344 | |
| 2345 List<Statement> get users => internalError("Unsupported operation."); | |
| 2346 | |
| 2347 JumpTargetKind get kind => internalError("Unsupported operation."); | |
| 2348 | |
| 2349 bool get isBreakTarget => true; | |
| 2350 | |
| 2351 bool get isContinueTarget => true; | |
| 2352 | |
| 2353 bool get isGotoTarget => false; | |
| 2354 | |
| 2355 void addBreak(BreakStatement statement) { | |
| 2356 breakTarget.addBreak(statement); | |
| 2357 } | |
| 2358 | |
| 2359 void addContinue(BreakStatement statement) { | |
| 2360 continueTarget.addContinue(statement); | |
| 2361 } | |
| 2362 | |
| 2363 void addGoto(ContinueSwitchStatement statement) { | |
| 2364 internalError("Unsupported operation."); | |
| 2365 } | |
| 2366 | |
| 2367 void resolveBreaks(LabeledStatement target) { | |
| 2368 breakTarget.resolveBreaks(target); | |
| 2369 } | |
| 2370 | |
| 2371 void resolveContinues(LabeledStatement target) { | |
| 2372 continueTarget.resolveContinues(target); | |
| 2373 } | |
| 2374 | |
| 2375 void resolveGotos(SwitchCase target) { | |
| 2376 internalError("Unsupported operation."); | |
| 2377 } | |
| 2378 } | |
| 2379 | |
| 2380 class OptionalFormals { | |
| 2381 final FormalParameterType kind; | |
| 2382 | |
| 2383 final List<VariableDeclaration> formals; | |
| 2384 | |
| 2385 OptionalFormals(this.kind, this.formals); | |
| 2386 } | |
| 2387 | |
| 2388 class FormalParameters { | |
| 2389 final List<VariableDeclaration> required; | |
| 2390 final OptionalFormals optional; | |
| 2391 | |
| 2392 FormalParameters(this.required, this.optional); | |
| 2393 | |
| 2394 FunctionNode addToFunction(FunctionNode function) { | |
| 2395 function.requiredParameterCount = required.length; | |
| 2396 function.positionalParameters.addAll(required); | |
| 2397 if (optional != null) { | |
| 2398 if (optional.kind.isPositional) { | |
| 2399 function.positionalParameters.addAll(optional.formals); | |
| 2400 } else { | |
| 2401 function.namedParameters.addAll(optional.formals); | |
| 2402 setParents(function.namedParameters, function); | |
| 2403 } | |
| 2404 } | |
| 2405 setParents(function.positionalParameters, function); | |
| 2406 return function; | |
| 2407 } | |
| 2408 | |
| 2409 FunctionType toFunctionType(DartType returnType) { | |
| 2410 returnType ??= const DynamicType(); | |
| 2411 int requiredParameterCount = required.length; | |
| 2412 List<DartType> positionalParameters = <DartType>[]; | |
| 2413 List<NamedType> namedParameters = const <NamedType>[]; | |
| 2414 for (VariableDeclaration parameter in required) { | |
| 2415 positionalParameters.add(parameter.type); | |
| 2416 } | |
| 2417 if (optional != null) { | |
| 2418 if (optional.kind.isPositional) { | |
| 2419 for (VariableDeclaration parameter in optional.formals) { | |
| 2420 positionalParameters.add(parameter.type); | |
| 2421 } | |
| 2422 } else { | |
| 2423 namedParameters = <NamedType>[]; | |
| 2424 for (VariableDeclaration parameter in optional.formals) { | |
| 2425 namedParameters.add(new NamedType(parameter.name, parameter.type)); | |
| 2426 } | |
| 2427 namedParameters.sort(); | |
| 2428 } | |
| 2429 } | |
| 2430 return new FunctionType(positionalParameters, returnType, | |
| 2431 namedParameters: namedParameters, | |
| 2432 requiredParameterCount: requiredParameterCount); | |
| 2433 } | |
| 2434 | |
| 2435 Scope computeFormalParameterScope(Scope parent) { | |
| 2436 if (required.length == 0 && optional == null) return parent; | |
| 2437 Map<String, Builder> local = <String, Builder>{}; | |
| 2438 for (VariableDeclaration parameter in required) { | |
| 2439 local[parameter.name] = new KernelVariableBuilder(parameter); | |
| 2440 } | |
| 2441 if (optional != null) { | |
| 2442 for (VariableDeclaration parameter in optional.formals) { | |
| 2443 local[parameter.name] = new KernelVariableBuilder(parameter); | |
| 2444 } | |
| 2445 } | |
| 2446 return new Scope(local, parent, isModifiable: false); | |
| 2447 } | |
| 2448 } | |
| 2449 | |
| 2450 /// Returns a block like this: | |
| 2451 /// | |
| 2452 /// { | |
| 2453 /// statement; | |
| 2454 /// body; | |
| 2455 /// } | |
| 2456 /// | |
| 2457 /// If [body] is a [Block], it's returned with [statement] prepended to it. | |
| 2458 Block combineStatements(Statement statement, Statement body) { | |
| 2459 if (body is Block) { | |
| 2460 body.statements.insert(0, statement); | |
| 2461 statement.parent = body; | |
| 2462 return body; | |
| 2463 } else { | |
| 2464 return new Block(<Statement>[statement, body]); | |
| 2465 } | |
| 2466 } | |
| 2467 | |
| 2468 String debugName(String className, String name, [String prefix]) { | |
| 2469 String result = name.isEmpty ? className : "$className.$name"; | |
| 2470 return prefix == null ? result : "$prefix.result"; | |
| 2471 } | |
| 2472 | |
| 2473 String getNodeName(Object node) { | |
| 2474 if (node is Identifier) { | |
| 2475 return node.name; | |
| 2476 } else if (node is UnresolvedIdentifier) { | |
| 2477 return node.name.name; | |
| 2478 } else if (node is TypeDeclarationBuilder) { | |
| 2479 return node.name; | |
| 2480 } else if (node is PrefixBuilder) { | |
| 2481 return node.name; | |
| 2482 } else if (node is ThisPropertyAccessor) { | |
| 2483 return node.name.name; | |
| 2484 } else { | |
| 2485 return internalError("Unhandled: ${node.runtimeType}"); | |
| 2486 } | |
| 2487 } | |
| OLD | NEW |