| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dart2js.ir_nodes_sexpr; | |
| 6 | |
| 7 import '../constants/values.dart'; | |
| 8 import '../universe/call_structure.dart' show CallStructure; | |
| 9 import '../util/util.dart'; | |
| 10 import 'cps_ir_nodes.dart'; | |
| 11 | |
| 12 /// A [Decorator] is a function used by [SExpressionStringifier] to augment the | |
| 13 /// output produced for a node or reference. It can be provided to the | |
| 14 /// constructor. | |
| 15 typedef String Decorator(node, String s); | |
| 16 | |
| 17 /// Generate a Lisp-like S-expression representation of an IR node as a string. | |
| 18 class SExpressionStringifier extends Indentation implements Visitor<String> { | |
| 19 final _Namer namer = new _Namer(); | |
| 20 | |
| 21 String newValueName(Primitive node) => namer.nameValue(node); | |
| 22 String newContinuationName(Continuation node) => namer.nameContinuation(node); | |
| 23 Decorator decorator; | |
| 24 | |
| 25 SExpressionStringifier([this.decorator]) { | |
| 26 if (this.decorator == null) { | |
| 27 this.decorator = (node, String s) => s; | |
| 28 } | |
| 29 } | |
| 30 | |
| 31 /// Create a stringifier with an extra layer of decoration. | |
| 32 SExpressionStringifier withDecorator(Decorator subDecorator) { | |
| 33 return new SExpressionStringifier((node, String s) { | |
| 34 return subDecorator(node, decorator(node, s)); | |
| 35 }); | |
| 36 } | |
| 37 | |
| 38 /// Create a stringifier that displays type information. | |
| 39 SExpressionStringifier withTypes() => withDecorator(typeDecorator); | |
| 40 | |
| 41 /// Creates a stringifier that adds annotations from a map; | |
| 42 /// see [Node.debugString]. | |
| 43 SExpressionStringifier withAnnotations(Map annotations) { | |
| 44 return withDecorator(decoratorFromMap(annotations)); | |
| 45 } | |
| 46 | |
| 47 static Decorator decoratorFromMap(Map annotations) { | |
| 48 Map<Node, String> nodeMap = {}; | |
| 49 for (var key in annotations.keys) { | |
| 50 if (key is Node) { | |
| 51 nodeMap[key] = '${annotations[key]}'; | |
| 52 } else { | |
| 53 String text = key; | |
| 54 Node node = annotations[key]; | |
| 55 if (nodeMap.containsKey(node)) { | |
| 56 // In case two annotations belong to the same node, | |
| 57 // put both annotations on that node. | |
| 58 nodeMap[node] += ' $text'; | |
| 59 } else { | |
| 60 nodeMap[node] = text; | |
| 61 } | |
| 62 } | |
| 63 } | |
| 64 return (node, string) { | |
| 65 String text = nodeMap[node]; | |
| 66 if (text != null) return '***$string*** $text'; | |
| 67 return string; | |
| 68 }; | |
| 69 } | |
| 70 | |
| 71 static String typeDecorator(node, String string) { | |
| 72 return node is Variable ? '$string:${node.type}' : string; | |
| 73 } | |
| 74 | |
| 75 String access(Reference<Definition> r) { | |
| 76 if (r == null) return '**** NULL ****'; | |
| 77 return decorator(r, namer.getName(r.definition)); | |
| 78 } | |
| 79 | |
| 80 String optionalAccess(Reference<Definition> reference) { | |
| 81 return reference == null ? '()' : '(${access(reference)})'; | |
| 82 } | |
| 83 | |
| 84 String visitParameter(Parameter node) { | |
| 85 return namer.nameParameter(node); | |
| 86 } | |
| 87 | |
| 88 String visitMutableVariable(MutableVariable node) { | |
| 89 return namer.nameMutableVariable(node); | |
| 90 } | |
| 91 | |
| 92 /// Main entry point for creating a [String] from a [Node]. All recursive | |
| 93 /// calls must go through this method. | |
| 94 String visit(Node node) { | |
| 95 if (node == null) return '**** NULL ****'; | |
| 96 String s = node.accept(this); | |
| 97 return decorator(node, s); | |
| 98 } | |
| 99 | |
| 100 String formatOptionalParameter(Parameter parameter) { | |
| 101 return parameter == null ? '()' : '(${visit(parameter)})'; | |
| 102 } | |
| 103 | |
| 104 String visitFunctionDefinition(FunctionDefinition node) { | |
| 105 String name = node.element.name; | |
| 106 String interceptorParameter = | |
| 107 formatOptionalParameter(node.interceptorParameter); | |
| 108 String thisParameter = formatOptionalParameter(node.receiverParameter); | |
| 109 String parameters = node.parameters.map(visit).join(' '); | |
| 110 namer.setReturnContinuation(node.returnContinuation); | |
| 111 String body = indentBlock(() => visit(node.body)); | |
| 112 return '$indentation' | |
| 113 '(FunctionDefinition $name $interceptorParameter $thisParameter ' | |
| 114 '($parameters) return\n' | |
| 115 '$body)'; | |
| 116 } | |
| 117 | |
| 118 String visitLetPrim(LetPrim node) { | |
| 119 String name = newValueName(node.primitive); | |
| 120 String value = visit(node.primitive); | |
| 121 String bindings = '($name $value)'; | |
| 122 String skip = ' ' * '(LetPrim ('.length; | |
| 123 while (node.body is LetPrim) { | |
| 124 node = node.body; | |
| 125 name = newValueName(node.primitive); | |
| 126 value = visit(node.primitive); | |
| 127 String binding = decorator(node, '($name $value)'); | |
| 128 bindings += '\n${indentation}$skip$binding'; | |
| 129 } | |
| 130 String body = indentBlock(() => visit(node.body)); | |
| 131 return '$indentation(LetPrim ($bindings)\n$body)'; | |
| 132 } | |
| 133 | |
| 134 bool isBranchTarget(Continuation cont) { | |
| 135 return cont.hasExactlyOneUse && cont.firstRef.parent is Branch; | |
| 136 } | |
| 137 | |
| 138 String visitLetCont(LetCont node) { | |
| 139 String conts; | |
| 140 bool first = true; | |
| 141 String skip = ' ' * '(LetCont ('.length; | |
| 142 for (Continuation continuation in node.continuations) { | |
| 143 // Branch continuations will be printed at their use site. | |
| 144 if (isBranchTarget(continuation)) continue; | |
| 145 if (first) { | |
| 146 first = false; | |
| 147 conts = visit(continuation); | |
| 148 } else { | |
| 149 // Each subsequent line is indented additional spaces to align it | |
| 150 // with the previous continuation. | |
| 151 conts += '\n${indentation}$skip${visit(continuation)}'; | |
| 152 } | |
| 153 } | |
| 154 // If there were no continuations printed, just print the body. | |
| 155 if (first) return visit(node.body); | |
| 156 | |
| 157 String body = indentBlock(() => visit(node.body)); | |
| 158 return '$indentation(LetCont ($conts)\n$body)'; | |
| 159 } | |
| 160 | |
| 161 String visitLetHandler(LetHandler node) { | |
| 162 // There are no explicit references to the handler, so we leave it | |
| 163 // anonymous in the printed representation. | |
| 164 String parameters = node.handler.parameters | |
| 165 .map((p) => '${decorator(p, newValueName(p))}') | |
| 166 .join(' '); | |
| 167 String handlerBody = | |
| 168 indentBlock(() => indentBlock(() => visit(node.handler.body))); | |
| 169 String body = indentBlock(() => visit(node.body)); | |
| 170 return '$indentation(LetHandler (($parameters)\n$handlerBody)\n$body)'; | |
| 171 } | |
| 172 | |
| 173 String visitLetMutable(LetMutable node) { | |
| 174 String name = visit(node.variable); | |
| 175 String value = access(node.valueRef); | |
| 176 String body = indentBlock(() => visit(node.body)); | |
| 177 return '$indentation(LetMutable ($name $value)\n$body)'; | |
| 178 } | |
| 179 | |
| 180 String formatArguments( | |
| 181 CallStructure call, List<Reference<Primitive>> arguments, | |
| 182 [CallingConvention callingConvention = CallingConvention.Normal]) { | |
| 183 int positionalArgumentCount = call.positionalArgumentCount; | |
| 184 List<String> args = | |
| 185 arguments.take(positionalArgumentCount).map(access).toList(); | |
| 186 List<String> argumentNames = call.getOrderedNamedArguments(); | |
| 187 for (int i = 0; i < argumentNames.length; ++i) { | |
| 188 String name = argumentNames[i]; | |
| 189 String arg = access(arguments[positionalArgumentCount + i]); | |
| 190 args.add("($name: $arg)"); | |
| 191 } | |
| 192 // Constructors can have type parameter after the named arguments. | |
| 193 args.addAll(arguments | |
| 194 .skip(positionalArgumentCount + argumentNames.length) | |
| 195 .map(access)); | |
| 196 return '(${args.join(' ')})'; | |
| 197 } | |
| 198 | |
| 199 String visitInvokeStatic(InvokeStatic node) { | |
| 200 String name = node.target.name; | |
| 201 String args = | |
| 202 formatArguments(node.selector.callStructure, node.argumentRefs); | |
| 203 return '(InvokeStatic $name $args)'; | |
| 204 } | |
| 205 | |
| 206 String visitInvokeMethod(InvokeMethod node) { | |
| 207 String name = node.selector.name; | |
| 208 String interceptor = optionalAccess(node.interceptorRef); | |
| 209 String receiver = access(node.receiverRef); | |
| 210 String arguments = formatArguments( | |
| 211 node.selector.callStructure, node.argumentRefs, node.callingConvention); | |
| 212 return '(InvokeMethod $interceptor $receiver $name $arguments)'; | |
| 213 } | |
| 214 | |
| 215 String visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 216 String interceptor = optionalAccess(node.interceptorRef); | |
| 217 String receiver = access(node.receiverRef); | |
| 218 String name = node.selector.name; | |
| 219 String arguments = formatArguments( | |
| 220 node.selector.callStructure, node.argumentRefs, node.callingConvention); | |
| 221 return '(InvokeMethodDirectly $interceptor $receiver $name $arguments)'; | |
| 222 } | |
| 223 | |
| 224 String visitInvokeConstructor(InvokeConstructor node) { | |
| 225 // TODO(karlklose): for illegal nodes constructed for tests or unresolved | |
| 226 // constructor calls in the DartBackend, we get an element with no enclosing | |
| 227 // class. Clean this up by introducing a name field to the node and | |
| 228 // removing [ErroneousElement]s from the IR. | |
| 229 String name = node.dartType != null | |
| 230 ? node.dartType.toString() | |
| 231 : node.target.enclosingClass.name; | |
| 232 if (!node.target.name.isEmpty) { | |
| 233 name = '${name}.${node.target.name}'; | |
| 234 } | |
| 235 String args = | |
| 236 formatArguments(node.selector.callStructure, node.argumentRefs); | |
| 237 return '(InvokeConstructor $name $args)'; | |
| 238 } | |
| 239 | |
| 240 String visitInvokeContinuation(InvokeContinuation node) { | |
| 241 String name = access(node.continuationRef); | |
| 242 if (node.isRecursive) name = 'rec $name'; | |
| 243 String args = node.argumentRefs == null | |
| 244 ? '**** NULL ****' | |
| 245 : node.argumentRefs.map(access).join(' '); | |
| 246 String escaping = node.isEscapingTry ? ' escape' : ''; | |
| 247 return '$indentation(InvokeContinuation $name ($args)$escaping)'; | |
| 248 } | |
| 249 | |
| 250 String visitThrow(Throw node) { | |
| 251 String value = access(node.valueRef); | |
| 252 return '$indentation(Throw $value)'; | |
| 253 } | |
| 254 | |
| 255 String visitRethrow(Rethrow node) { | |
| 256 return '$indentation(Rethrow)'; | |
| 257 } | |
| 258 | |
| 259 String visitBranch(Branch node) { | |
| 260 String condition = access(node.conditionRef); | |
| 261 assert(isBranchTarget(node.trueContinuation)); | |
| 262 assert(isBranchTarget(node.falseContinuation)); | |
| 263 String trueCont = indentBlock(() => visit(node.trueContinuation)); | |
| 264 String falseCont = indentBlock(() => visit(node.falseContinuation)); | |
| 265 String strict = node.isStrictCheck ? 'Strict' : 'NonStrict'; | |
| 266 return '$indentation(Branch $strict $condition\n$trueCont\n$falseCont)'; | |
| 267 } | |
| 268 | |
| 269 String visitUnreachable(Unreachable node) { | |
| 270 return '$indentation(Unreachable)'; | |
| 271 } | |
| 272 | |
| 273 String visitConstant(Constant node) { | |
| 274 String value = node.value.accept(new ConstantStringifier(), null); | |
| 275 return '(Constant $value)'; | |
| 276 } | |
| 277 | |
| 278 String visitContinuation(Continuation node) { | |
| 279 if (isBranchTarget(node)) { | |
| 280 assert(node.parameters.isEmpty); | |
| 281 assert(!node.isRecursive); | |
| 282 return indentBlock(() => visit(node.body)); | |
| 283 } | |
| 284 String name = newContinuationName(node); | |
| 285 if (node.isRecursive) name = 'rec $name'; | |
| 286 // TODO(karlklose): this should be changed to `.map(visit).join(' ')` | |
| 287 // and should recurse to [visit]. Currently we can't do that, because | |
| 288 // the unstringifier_test produces [LetConts] with dummy arguments on | |
| 289 // them. | |
| 290 String parameters = node.parameters | |
| 291 .map((p) => '${decorator(p, newValueName(p))}') | |
| 292 .join(' '); | |
| 293 String body = indentBlock(() => indentBlock(() => visit(node.body))); | |
| 294 return '($name ($parameters)\n$body)'; | |
| 295 } | |
| 296 | |
| 297 String visitGetMutable(GetMutable node) { | |
| 298 return '(GetMutable ${access(node.variableRef)})'; | |
| 299 } | |
| 300 | |
| 301 String visitSetMutable(SetMutable node) { | |
| 302 String value = access(node.valueRef); | |
| 303 return '(SetMutable ${access(node.variableRef)} $value)'; | |
| 304 } | |
| 305 | |
| 306 String visitTypeCast(TypeCast node) { | |
| 307 String value = access(node.valueRef); | |
| 308 String typeArguments = node.typeArgumentRefs.map(access).join(' '); | |
| 309 return '(TypeCast $value ${node.dartType} ($typeArguments))'; | |
| 310 } | |
| 311 | |
| 312 String visitTypeTest(TypeTest node) { | |
| 313 String value = access(node.valueRef); | |
| 314 String typeArguments = node.typeArgumentRefs.map(access).join(' '); | |
| 315 return '(TypeTest $value ${node.dartType} ($typeArguments))'; | |
| 316 } | |
| 317 | |
| 318 String visitTypeTestViaFlag(TypeTestViaFlag node) { | |
| 319 String interceptor = access(node.interceptorRef); | |
| 320 return '(TypeTestViaFlag $interceptor ${node.dartType})'; | |
| 321 } | |
| 322 | |
| 323 String visitLiteralList(LiteralList node) { | |
| 324 String values = node.valueRefs.map(access).join(' '); | |
| 325 return '(LiteralList ($values))'; | |
| 326 } | |
| 327 | |
| 328 String visitSetField(SetField node) { | |
| 329 String object = access(node.objectRef); | |
| 330 String field = node.field.name; | |
| 331 String value = access(node.valueRef); | |
| 332 return '(SetField $object $field $value)'; | |
| 333 } | |
| 334 | |
| 335 String visitGetField(GetField node) { | |
| 336 String object = access(node.objectRef); | |
| 337 String field = node.field.name; | |
| 338 return '(GetField $object $field)'; | |
| 339 } | |
| 340 | |
| 341 String visitGetStatic(GetStatic node) { | |
| 342 String element = node.element.name; | |
| 343 return '(GetStatic $element)'; | |
| 344 } | |
| 345 | |
| 346 String visitSetStatic(SetStatic node) { | |
| 347 String element = node.element.name; | |
| 348 String value = access(node.valueRef); | |
| 349 return '(SetStatic $element $value)'; | |
| 350 } | |
| 351 | |
| 352 String visitGetLazyStatic(GetLazyStatic node) { | |
| 353 String element = node.element.name; | |
| 354 return '(GetLazyStatic $element)'; | |
| 355 } | |
| 356 | |
| 357 String visitCreateBox(CreateBox node) { | |
| 358 return '(CreateBox)'; | |
| 359 } | |
| 360 | |
| 361 String visitCreateInstance(CreateInstance node) { | |
| 362 String className = node.classElement.name; | |
| 363 String arguments = node.argumentRefs.map(access).join(' '); | |
| 364 String typeInformation = optionalAccess(node.typeInformationRef); | |
| 365 return '(CreateInstance $className ($arguments) ($typeInformation))'; | |
| 366 } | |
| 367 | |
| 368 String visitInterceptor(Interceptor node) { | |
| 369 return '(Interceptor ${access(node.inputRef)})'; | |
| 370 } | |
| 371 | |
| 372 String visitReifyRuntimeType(ReifyRuntimeType node) { | |
| 373 return '(ReifyRuntimeType ${access(node.valueRef)})'; | |
| 374 } | |
| 375 | |
| 376 String visitReadTypeVariable(ReadTypeVariable node) { | |
| 377 return '(ReadTypeVariable ${access(node.targetRef)}.${node.variable})'; | |
| 378 } | |
| 379 | |
| 380 String visitTypeExpression(TypeExpression node) { | |
| 381 String args = node.argumentRefs.map(access).join(' '); | |
| 382 return '(TypeExpression ${node.kindAsString} ${node.dartType} ($args))'; | |
| 383 } | |
| 384 | |
| 385 String visitCreateInvocationMirror(CreateInvocationMirror node) { | |
| 386 String selector = node.selector.name; | |
| 387 String args = node.argumentRefs.map(access).join(' '); | |
| 388 return '(CreateInvocationMirror $selector ($args))'; | |
| 389 } | |
| 390 | |
| 391 String visitApplyBuiltinOperator(ApplyBuiltinOperator node) { | |
| 392 String operator = node.operator.toString(); | |
| 393 String args = node.argumentRefs.map(access).join(' '); | |
| 394 return '(ApplyBuiltinOperator $operator ($args))'; | |
| 395 } | |
| 396 | |
| 397 String visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | |
| 398 String method = node.method.toString(); | |
| 399 String receiver = access(node.receiverRef); | |
| 400 String args = node.argumentRefs.map(access).join(' '); | |
| 401 return '(ApplyBuiltinMethod $method $receiver ($args))'; | |
| 402 } | |
| 403 | |
| 404 String visitForeignCode(ForeignCode node) { | |
| 405 String arguments = node.argumentRefs.map(access).join(' '); | |
| 406 return '(JS "${node.codeTemplate.source}" ($arguments))'; | |
| 407 } | |
| 408 | |
| 409 String visitGetLength(GetLength node) { | |
| 410 String object = access(node.objectRef); | |
| 411 return '(GetLength $object)'; | |
| 412 } | |
| 413 | |
| 414 String visitGetIndex(GetIndex node) { | |
| 415 String object = access(node.objectRef); | |
| 416 String index = access(node.indexRef); | |
| 417 return '(GetIndex $object $index)'; | |
| 418 } | |
| 419 | |
| 420 String visitSetIndex(SetIndex node) { | |
| 421 String object = access(node.objectRef); | |
| 422 String index = access(node.indexRef); | |
| 423 String value = access(node.valueRef); | |
| 424 return '(SetIndex $object $index $value)'; | |
| 425 } | |
| 426 | |
| 427 @override | |
| 428 String visitAwait(Await node) { | |
| 429 String value = access(node.inputRef); | |
| 430 return '(Await $value)'; | |
| 431 } | |
| 432 | |
| 433 @override | |
| 434 String visitYield(Yield node) { | |
| 435 String value = access(node.inputRef); | |
| 436 return '(Yield $value)'; | |
| 437 } | |
| 438 | |
| 439 String visitRefinement(Refinement node) { | |
| 440 String value = access(node.value); | |
| 441 return '(Refinement $value ${node.type})'; | |
| 442 } | |
| 443 | |
| 444 String visitBoundsCheck(BoundsCheck node) { | |
| 445 String object = access(node.objectRef); | |
| 446 String index = optionalAccess(node.indexRef); | |
| 447 String length = optionalAccess(node.lengthRef); | |
| 448 return '(BoundsCheck $object $index $length ${node.checkString})'; | |
| 449 } | |
| 450 | |
| 451 String visitReceiverCheck(ReceiverCheck node) { | |
| 452 String value = access(node.valueRef); | |
| 453 String condition = optionalAccess(node.conditionRef); | |
| 454 return '(ReceiverCheck $value ${node.selector} $condition ' | |
| 455 '${node.flagString}))'; | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 class ConstantStringifier extends ConstantValueVisitor<String, Null> { | |
| 460 // Some of these methods are unimplemented because we haven't had a need | |
| 461 // to print such constants. When printing is implemented, the corresponding | |
| 462 // parsing support should be added to SExpressionUnstringifier.parseConstant | |
| 463 // in the dart2js tests (currently in the file | |
| 464 // tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart). | |
| 465 | |
| 466 String _failWith(ConstantValue constant) { | |
| 467 throw 'Stringification not supported for ${constant.toStructuredText()}'; | |
| 468 } | |
| 469 | |
| 470 String visitFunction(FunctionConstantValue constant, _) { | |
| 471 return '(Function "${constant.toDartText()}")'; | |
| 472 } | |
| 473 | |
| 474 String visitNull(NullConstantValue constant, _) { | |
| 475 return '(Null)'; | |
| 476 } | |
| 477 | |
| 478 String visitNonConstant(NonConstantValue constant, _) { | |
| 479 return '(NonConstant)'; | |
| 480 } | |
| 481 | |
| 482 String visitInt(IntConstantValue constant, _) { | |
| 483 return '(Int ${constant.toDartText()})'; | |
| 484 } | |
| 485 | |
| 486 String visitDouble(DoubleConstantValue constant, _) { | |
| 487 return '(Double ${constant.toDartText()})'; | |
| 488 } | |
| 489 | |
| 490 String visitBool(BoolConstantValue constant, _) { | |
| 491 return '(Bool ${constant.toDartText()})'; | |
| 492 } | |
| 493 | |
| 494 String visitString(StringConstantValue constant, _) { | |
| 495 return '(String ${constant.toDartText()})'; | |
| 496 } | |
| 497 | |
| 498 String visitList(ListConstantValue constant, _) { | |
| 499 String entries = | |
| 500 constant.entries.map((entry) => entry.accept(this, _)).join(' '); | |
| 501 return '(List $entries)'; | |
| 502 } | |
| 503 | |
| 504 String visitMap(MapConstantValue constant, _) { | |
| 505 List<String> elements = <String>[]; | |
| 506 for (int i = 0; i < constant.keys.length; ++i) { | |
| 507 ConstantValue key = constant.keys[i]; | |
| 508 ConstantValue value = constant.values[i]; | |
| 509 elements.add('(${key.accept(this, _)} . ${value.accept(this, _)})'); | |
| 510 } | |
| 511 return '(Map (${elements.join(' ')}))'; | |
| 512 } | |
| 513 | |
| 514 String visitConstructed(ConstructedConstantValue constant, _) { | |
| 515 return '(Constructed "${constant.toDartText()}")'; | |
| 516 } | |
| 517 | |
| 518 String visitType(TypeConstantValue constant, _) { | |
| 519 return '(Type "${constant.representedType}")'; | |
| 520 } | |
| 521 | |
| 522 String visitInterceptor(InterceptorConstantValue constant, _) { | |
| 523 return '(Interceptor "${constant.toDartText()}")'; | |
| 524 } | |
| 525 | |
| 526 String visitSynthetic(SyntheticConstantValue constant, _) { | |
| 527 return '(Synthetic "${constant.toDartText()}")'; | |
| 528 } | |
| 529 | |
| 530 String visitDeferred(DeferredConstantValue constant, _) { | |
| 531 return _failWith(constant); | |
| 532 } | |
| 533 } | |
| 534 | |
| 535 class _Namer { | |
| 536 final Map<Node, String> _names = <Node, String>{}; | |
| 537 int _valueCounter = 0; | |
| 538 int _continuationCounter = 0; | |
| 539 | |
| 540 // TODO(sra): Make the methods not assert and print something indicating an | |
| 541 // error, so printer can be used to inspect broken terms. | |
| 542 | |
| 543 String nameParameter(Parameter parameter) { | |
| 544 assert(!_names.containsKey(parameter)); | |
| 545 String name = | |
| 546 parameter.hint != null ? parameter.hint.name : nameValue(parameter); | |
| 547 return _names[parameter] = name; | |
| 548 } | |
| 549 | |
| 550 String nameMutableVariable(MutableVariable variable) { | |
| 551 assert(!_names.containsKey(variable)); | |
| 552 return _names[variable] = variable.hint.name; | |
| 553 } | |
| 554 | |
| 555 String nameContinuation(Continuation node) { | |
| 556 assert(!_names.containsKey(node)); | |
| 557 return _names[node] = 'k${_continuationCounter++}'; | |
| 558 } | |
| 559 | |
| 560 String nameValue(Primitive node) { | |
| 561 assert(!_names.containsKey(node)); | |
| 562 return _names[node] = 'v${_valueCounter++}'; | |
| 563 } | |
| 564 | |
| 565 void setReturnContinuation(Continuation node) { | |
| 566 assert(!_names.containsKey(node) || _names[node] == 'return'); | |
| 567 _names[node] = 'return'; | |
| 568 } | |
| 569 | |
| 570 String getName(Node node) { | |
| 571 if (!_names.containsKey(node)) return 'MISSING_NAME'; | |
| 572 return _names[node]; | |
| 573 } | |
| 574 } | |
| OLD | NEW |