| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, 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 /** | |
| 6 * Assigns JavaScript identifiers to Dart variables, class-names and members. | |
| 7 */ | |
| 8 class Namer { | |
| 9 final Compiler compiler; | |
| 10 | |
| 11 static final CLOSURE_INVOCATION_NAME = const SourceString('\$call'); | |
| 12 static final OPERATOR_EQUALS = const SourceString('operator\$eq'); | |
| 13 | |
| 14 static Set<String> _jsReserved = null; | |
| 15 Set<String> get jsReserved() { | |
| 16 if (_jsReserved === null) { | |
| 17 _jsReserved = new Set<String>(); | |
| 18 _jsReserved.addAll(JsNames.javaScriptKeywords); | |
| 19 _jsReserved.addAll(JsNames.reservedPropertySymbols); | |
| 20 } | |
| 21 return _jsReserved; | |
| 22 } | |
| 23 | |
| 24 Map<Element, String> globals; | |
| 25 Map<String, int> usedGlobals; | |
| 26 | |
| 27 Namer(this.compiler) | |
| 28 : globals = new Map<Element, String>(), | |
| 29 usedGlobals = new Map<String, int>(); | |
| 30 | |
| 31 final String CURRENT_ISOLATE = "\$"; | |
| 32 final String ISOLATE = "Isolate"; | |
| 33 | |
| 34 | |
| 35 String closureInvocationName(Selector selector) { | |
| 36 // TODO(floitsch): mangle, while not conflicting with instance names. | |
| 37 return instanceMethodInvocationName(null, CLOSURE_INVOCATION_NAME, | |
| 38 selector); | |
| 39 } | |
| 40 | |
| 41 String privateName(LibraryElement lib, SourceString name) { | |
| 42 if (name.isPrivate()) { | |
| 43 return '_${getName(lib)}${name.slowToString()}'; | |
| 44 } else { | |
| 45 return '${name.slowToString()}'; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 String instanceMethodName(LibraryElement lib, SourceString name, int arity) { | |
| 50 return '${privateName(lib, name)}\$$arity'; | |
| 51 } | |
| 52 | |
| 53 String instanceMethodInvocationName(LibraryElement lib, SourceString name, | |
| 54 Selector selector) { | |
| 55 // TODO(floitsch): mangle, while preserving uniqueness. | |
| 56 StringBuffer buffer = new StringBuffer(); | |
| 57 List<SourceString> names = selector.getOrderedNamedArguments(); | |
| 58 for (SourceString argumentName in names) { | |
| 59 buffer.add(@'$'); | |
| 60 argumentName.printOn(buffer); | |
| 61 } | |
| 62 return '${privateName(lib, name)}\$${selector.argumentCount}$buffer'; | |
| 63 } | |
| 64 | |
| 65 String instanceFieldName(LibraryElement lib, SourceString name) { | |
| 66 return privateName(lib, name); | |
| 67 } | |
| 68 | |
| 69 String setterName(LibraryElement lib, SourceString name) { | |
| 70 return 'set\$${privateName(lib, name)}'; | |
| 71 } | |
| 72 | |
| 73 String getterName(LibraryElement lib, SourceString name) { | |
| 74 return 'get\$${privateName(lib, name)}'; | |
| 75 } | |
| 76 | |
| 77 String getFreshGlobalName(String proposedName) { | |
| 78 int usedCount = usedGlobals[proposedName]; | |
| 79 if (usedCount === null) { | |
| 80 // No element with this name has been used before. | |
| 81 usedGlobals[proposedName] = 1; | |
| 82 return proposedName; | |
| 83 } else { | |
| 84 // Not the first time we see this name. Append a number to make it unique. | |
| 85 String name; | |
| 86 do { | |
| 87 usedCount++; | |
| 88 name = '$proposedName$usedCount'; | |
| 89 } while (usedGlobals[name] !== null); | |
| 90 usedGlobals[proposedName] = usedCount; | |
| 91 return name; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 /** | |
| 96 * Returns a preferred JS-id for the given top-level or static element. | |
| 97 * The returned id is guaranteed to be a valid JS-id. | |
| 98 */ | |
| 99 String _computeGuess(Element element) { | |
| 100 assert(!element.isInstanceMember()); | |
| 101 LibraryElement lib = element.getLibrary(); | |
| 102 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
| 103 FunctionElement functionElement = element; | |
| 104 return instanceMethodName(lib, element.name, | |
| 105 functionElement.parameterCount(compiler)); | |
| 106 } else { | |
| 107 // TODO(floitsch): deal with named constructors. | |
| 108 String name; | |
| 109 if (Elements.isStaticOrTopLevel(element)) { | |
| 110 name = element.name.slowToString(); | |
| 111 } else if (element.kind == ElementKind.GETTER) { | |
| 112 name = getterName(lib, element.name); | |
| 113 } else if (element.kind == ElementKind.SETTER) { | |
| 114 name = setterName(lib, element.name); | |
| 115 } else if (element.kind == ElementKind.FUNCTION) { | |
| 116 FunctionElement functionElement = element; | |
| 117 name = element.name.slowToString(); | |
| 118 name = '$name\$${functionElement.parameterCount(compiler)}'; | |
| 119 } else if (element.kind === ElementKind.LIBRARY) { | |
| 120 name = 'lib'; | |
| 121 } else { | |
| 122 name = element.name.slowToString(); | |
| 123 } | |
| 124 // Prefix the name with '$' if it is reserved. | |
| 125 return safeName(name); | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 String getBailoutName(Element element) { | |
| 130 return '${getName(element)}\$bailout'; | |
| 131 } | |
| 132 | |
| 133 /** | |
| 134 * Returns a preferred JS-id for the given element. The returned id is | |
| 135 * guaranteed to be a valid JS-id. Globals and static fields are furthermore | |
| 136 * guaranteed to be unique. | |
| 137 * | |
| 138 * For accessing statics consider calling | |
| 139 * [isolateAccess]/[isolateBailoutAccess] or [isolatePropertyAccess] instead. | |
| 140 */ | |
| 141 String getName(Element element) { | |
| 142 if (element.isInstanceMember()) { | |
| 143 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | |
| 144 ConstructorBodyElement bodyElement = element; | |
| 145 SourceString name = bodyElement.constructor.name; | |
| 146 return instanceMethodName(element.getLibrary(), | |
| 147 name, bodyElement.parameterCount(compiler)); | |
| 148 } else if (element.kind == ElementKind.FUNCTION) { | |
| 149 FunctionElement functionElement = element; | |
| 150 return instanceMethodName(element.getLibrary(), | |
| 151 element.name, | |
| 152 functionElement.parameterCount(compiler)); | |
| 153 } else if (element.kind == ElementKind.GETTER) { | |
| 154 return getterName(element.getLibrary(), element.name); | |
| 155 } else if (element.kind == ElementKind.SETTER) { | |
| 156 return setterName(element.getLibrary(), element.name); | |
| 157 } else { | |
| 158 return instanceFieldName(element.getLibrary(), element.name); | |
| 159 } | |
| 160 } else { | |
| 161 // Dealing with a top-level or static element. | |
| 162 String cached = globals[element]; | |
| 163 if (cached !== null) return cached; | |
| 164 | |
| 165 String guess = _computeGuess(element); | |
| 166 switch (element.kind) { | |
| 167 case ElementKind.VARIABLE: | |
| 168 case ElementKind.PARAMETER: | |
| 169 // The name is not guaranteed to be unique. | |
| 170 return guess; | |
| 171 | |
| 172 case ElementKind.GENERATIVE_CONSTRUCTOR: | |
| 173 case ElementKind.FUNCTION: | |
| 174 case ElementKind.CLASS: | |
| 175 case ElementKind.FIELD: | |
| 176 case ElementKind.GETTER: | |
| 177 case ElementKind.SETTER: | |
| 178 case ElementKind.TYPEDEF: | |
| 179 case ElementKind.LIBRARY: | |
| 180 String result = getFreshGlobalName(guess); | |
| 181 globals[element] = result; | |
| 182 return result; | |
| 183 | |
| 184 default: | |
| 185 compiler.internalError('getName for unknown kind: ${element.kind}', | |
| 186 node: element.parseNode(compiler)); | |
| 187 } | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 String isolateAccess(Element element) { | |
| 192 return "$CURRENT_ISOLATE.${getName(element)}"; | |
| 193 } | |
| 194 | |
| 195 String isolatePropertyAccess(Element element) { | |
| 196 return "$ISOLATE.prototype.${getName(element)}"; | |
| 197 } | |
| 198 | |
| 199 String isolateBailoutPropertyAccess(Element element) { | |
| 200 return '${isolatePropertyAccess(element)}\$bailout'; | |
| 201 } | |
| 202 | |
| 203 String isolateBailoutAccess(Element element) { | |
| 204 return '${isolateAccess(element)}\$bailout'; | |
| 205 } | |
| 206 | |
| 207 String operatorIs(Element element) { | |
| 208 return 'is\$${getName(element)}'; | |
| 209 } | |
| 210 | |
| 211 String safeName(String name) { | |
| 212 if (jsReserved.contains(name) || name.startsWith('\$')) { | |
| 213 name = "\$$name"; | |
| 214 assert(!jsReserved.contains(name)); | |
| 215 } | |
| 216 return name; | |
| 217 } | |
| 218 } | |
| OLD | NEW |