OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, 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('elements'); | |
6 | |
7 #import('../tree/tree.dart'); | |
8 #import('../scanner/scannerlib.dart'); | |
9 #import('../leg.dart'); // TODO(karlklose): we only need type. | |
10 #import('../util/util.dart'); | |
11 | |
12 class ElementCategory { | |
13 /** | |
14 * Represents things that we don't expect to find when looking in a | |
15 * scope. | |
16 */ | |
17 static final int NONE = 0; | |
18 | |
19 /** Field, parameter, or variable. */ | |
20 static final int VARIABLE = 1; | |
21 | |
22 /** Function, method, or foreign function. */ | |
23 static final int FUNCTION = 2; | |
24 | |
25 static final int CLASS = 4; | |
26 | |
27 static final int PREFIX = 8; | |
28 | |
29 /** Constructor or factory. */ | |
30 static final int FACTORY = 16; | |
31 | |
32 static final int ALIAS = 32; | |
33 | |
34 static final int SUPER = 64; | |
35 | |
36 /** Type variable */ | |
37 static final int TYPE_VARIABLE = 128; | |
38 | |
39 static final int IMPLIES_TYPE = CLASS | ALIAS | TYPE_VARIABLE; | |
40 | |
41 static final int IS_EXTENDABLE = CLASS | ALIAS; | |
42 } | |
43 | |
44 class ElementKind { | |
45 final String id; | |
46 final int category; | |
47 | |
48 const ElementKind(String this.id, this.category); | |
49 | |
50 static final ElementKind VARIABLE = | |
51 const ElementKind('variable', ElementCategory.VARIABLE); | |
52 static final ElementKind PARAMETER = | |
53 const ElementKind('parameter', ElementCategory.VARIABLE); | |
54 // Parameters in constructors that directly initialize fields. For example: | |
55 // [:A(this.field):]. | |
56 static final ElementKind FIELD_PARAMETER = | |
57 const ElementKind('field_parameter', ElementCategory.VARIABLE); | |
58 static final ElementKind FUNCTION = | |
59 const ElementKind('function', ElementCategory.FUNCTION); | |
60 static final ElementKind CLASS = | |
61 const ElementKind('class', ElementCategory.CLASS); | |
62 static final ElementKind FOREIGN = | |
63 const ElementKind('foreign', ElementCategory.FUNCTION); | |
64 static final ElementKind GENERATIVE_CONSTRUCTOR = | |
65 const ElementKind('generative_constructor', ElementCategory.FACTORY); | |
66 static final ElementKind FIELD = | |
67 const ElementKind('field', ElementCategory.VARIABLE); | |
68 static final ElementKind VARIABLE_LIST = | |
69 const ElementKind('variable_list', ElementCategory.NONE); | |
70 static final ElementKind FIELD_LIST = | |
71 const ElementKind('field_list', ElementCategory.NONE); | |
72 static final ElementKind GENERATIVE_CONSTRUCTOR_BODY = | |
73 const ElementKind('generative_constructor_body', ElementCategory.NONE); | |
74 static final ElementKind COMPILATION_UNIT = | |
75 const ElementKind('compilation_unit', ElementCategory.NONE); | |
76 static final ElementKind GETTER = | |
77 const ElementKind('getter', ElementCategory.NONE); | |
78 static final ElementKind SETTER = | |
79 const ElementKind('setter', ElementCategory.NONE); | |
80 static final ElementKind TYPE_VARIABLE = | |
81 const ElementKind('type_variable', ElementCategory.TYPE_VARIABLE); | |
82 static final ElementKind ABSTRACT_FIELD = | |
83 const ElementKind('abstract_field', ElementCategory.VARIABLE); | |
84 static final ElementKind LIBRARY = | |
85 const ElementKind('library', ElementCategory.NONE); | |
86 static final ElementKind PREFIX = | |
87 const ElementKind('prefix', ElementCategory.PREFIX); | |
88 static final ElementKind TYPEDEF = | |
89 const ElementKind('typedef', ElementCategory.ALIAS); | |
90 | |
91 static final ElementKind STATEMENT = | |
92 const ElementKind('statement', ElementCategory.NONE); | |
93 static final ElementKind LABEL = | |
94 const ElementKind('label', ElementCategory.NONE); | |
95 | |
96 toString() => id; | |
97 } | |
98 | |
99 class Element implements Hashable { | |
100 final SourceString name; | |
101 final ElementKind kind; | |
102 final Element enclosingElement; | |
103 Modifiers get modifiers() => null; | |
104 | |
105 Node parseNode(DiagnosticListener listener) { | |
106 listener.cancel("Internal Error: $this.parseNode", token: position()); | |
107 } | |
108 | |
109 Type computeType(Compiler compiler) { | |
110 compiler.internalError("$this.computeType.", token: position()); | |
111 } | |
112 | |
113 bool isFunction() => kind === ElementKind.FUNCTION; | |
114 bool isMember() => | |
115 enclosingElement !== null && enclosingElement.kind === ElementKind.CLASS; | |
116 bool isInstanceMember() => false; | |
117 bool isFactoryConstructor() => modifiers !== null && modifiers.isFactory(); | |
118 bool isGenerativeConstructor() => kind === ElementKind.GENERATIVE_CONSTRUCTOR; | |
119 bool isCompilationUnit() { | |
120 return kind === ElementKind.COMPILATION_UNIT || | |
121 kind === ElementKind.LIBRARY; | |
122 } | |
123 bool isClass() => kind === ElementKind.CLASS; | |
124 bool isVariable() => kind === ElementKind.VARIABLE; | |
125 bool isParameter() => kind === ElementKind.PARAMETER; | |
126 bool isStatement() => kind === ElementKind.STATEMENT; | |
127 bool isTypedef() => kind === ElementKind.TYPEDEF; | |
128 bool isTypeVariable() => kind === ElementKind.TYPE_VARIABLE; | |
129 bool isGetter() => kind === ElementKind.GETTER; | |
130 bool isSetter() => kind === ElementKind.SETTER; | |
131 bool impliesType() => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; | |
132 bool isExtendable() => (kind.category & ElementCategory.IS_EXTENDABLE) != 0; | |
133 | |
134 bool isAssignable() { | |
135 if (modifiers != null && modifiers.isFinal()) return false; | |
136 if (isFunction() || isGenerativeConstructor()) return false; | |
137 return true; | |
138 } | |
139 | |
140 Token position() => null; | |
141 | |
142 Token findMyName(Token token) { | |
143 for (Token t = token; t !== EOF_TOKEN; t = t.next) { | |
144 if (t.value == name) return t; | |
145 } | |
146 return token; | |
147 } | |
148 | |
149 Element(this.name, this.kind, this.enclosingElement) { | |
150 assert(getLibrary() !== null); | |
151 } | |
152 | |
153 // TODO(kasperl): This is a very bad hash code for the element and | |
154 // there's no reason why two elements with the same name should have | |
155 // the same hash code. Replace this with a simple id in the element? | |
156 int hashCode() => name.hashCode(); | |
157 | |
158 CompilationUnitElement getCompilationUnit() { | |
159 Element element = this; | |
160 while (element !== null && !element.isCompilationUnit()) { | |
161 element = element.enclosingElement; | |
162 } | |
163 return element; | |
164 } | |
165 | |
166 LibraryElement getLibrary() { | |
167 Element element = this; | |
168 while (element.kind !== ElementKind.LIBRARY) { | |
169 element = element.enclosingElement; | |
170 } | |
171 return element; | |
172 } | |
173 | |
174 ClassElement getEnclosingClass() { | |
175 for (Element e = this; e !== null; e = e.enclosingElement) { | |
176 if (e.kind === ElementKind.CLASS) return e; | |
177 } | |
178 return null; | |
179 } | |
180 | |
181 toString() => '$kind(${name.slowToString()})'; | |
182 | |
183 bool _isNative = false; | |
184 void setNative() => _isNative = true; | |
185 bool isNative() => _isNative; | |
186 } | |
187 | |
188 class ContainerElement extends Element { | |
189 ContainerElement(name, kind, enclosingElement) : | |
190 super(name, kind, enclosingElement); | |
191 | |
192 abstract void addMember(Element element, DiagnosticListener listener); | |
193 | |
194 void addGetterOrSetter(Element element, | |
195 Element existing, | |
196 DiagnosticListener listener) { | |
197 void reportError(Element other) { | |
198 listener.cancel('duplicate definition of ${element.name.slowToString()}', | |
199 element: element); | |
200 listener.cancel('existing definition', element: other); | |
201 } | |
202 | |
203 if (existing != null) { | |
204 if (existing.kind !== ElementKind.ABSTRACT_FIELD) { | |
205 reportError(existing); | |
206 } else { | |
207 AbstractFieldElement field = existing; | |
208 if (element.kind == ElementKind.GETTER) { | |
209 if (field.getter != null && field.getter != element) { | |
210 reportError(field.getter); | |
211 } | |
212 field.getter = element; | |
213 } else { | |
214 if (field.setter != null && field.setter != element) { | |
215 reportError(field.setter); | |
216 } | |
217 field.setter = element; | |
218 } | |
219 } | |
220 } else { | |
221 AbstractFieldElement field = new AbstractFieldElement(element.name, this); | |
222 addMember(field, listener); | |
223 if (element.kind == ElementKind.GETTER) { | |
224 field.getter = element; | |
225 } else { | |
226 field.setter = element; | |
227 } | |
228 } | |
229 } | |
230 } | |
231 | |
232 class CompilationUnitElement extends ContainerElement { | |
233 final Script script; | |
234 Link<Element> topLevelElements = const EmptyLink<Element>(); | |
235 | |
236 CompilationUnitElement(Script script, Element enclosing) | |
237 : this.script = script, | |
238 super(new SourceString(script.name), | |
239 ElementKind.COMPILATION_UNIT, | |
240 enclosing); | |
241 | |
242 CompilationUnitElement.library(Script script) | |
243 : this.script = script, | |
244 super(new SourceString(script.name), ElementKind.LIBRARY, null); | |
245 | |
246 void addMember(Element element, DiagnosticListener listener) { | |
247 LibraryElement library = enclosingElement; | |
248 library.addMember(element, listener); | |
249 topLevelElements = topLevelElements.prepend(element); | |
250 } | |
251 | |
252 void define(Element element, DiagnosticListener listener) { | |
253 LibraryElement library = enclosingElement; | |
254 library.define(element, listener); | |
255 } | |
256 | |
257 void addTag(ScriptTag tag, DiagnosticListener listener) { | |
258 listener.cancel("script tags not allowed here", node: tag); | |
259 } | |
260 } | |
261 | |
262 class LibraryElement extends CompilationUnitElement { | |
263 // TODO(ahe): Library element should not be a subclass of | |
264 // CompilationUnitElement. | |
265 | |
266 Link<CompilationUnitElement> compilationUnits = | |
267 const EmptyLink<CompilationUnitElement>(); | |
268 Link<ScriptTag> tags = const EmptyLink<ScriptTag>(); | |
269 ScriptTag libraryTag; | |
270 Map<SourceString, Element> elements; | |
271 bool canUseNative = false; | |
272 | |
273 LibraryElement(Script script) | |
274 : elements = new Map<SourceString, Element>(), | |
275 super.library(script); | |
276 | |
277 void addCompilationUnit(CompilationUnitElement element) { | |
278 compilationUnits = compilationUnits.prepend(element); | |
279 } | |
280 | |
281 void addTag(ScriptTag tag, DiagnosticListener listener) { | |
282 tags = tags.prepend(tag); | |
283 } | |
284 | |
285 void addMember(Element element, DiagnosticListener listener) { | |
286 topLevelElements = topLevelElements.prepend(element); | |
287 define(element, listener); | |
288 } | |
289 | |
290 void define(Element element, DiagnosticListener listener) { | |
291 if (element.kind == ElementKind.GETTER | |
292 || element.kind == ElementKind.SETTER) { | |
293 addGetterOrSetter(element, elements[element.name], listener); | |
294 } else { | |
295 Element existing = elements.putIfAbsent(element.name, () => element); | |
296 if (existing !== element) { | |
297 listener.cancel('duplicate definition', token: element.position()); | |
298 listener.cancel('existing definition', token: existing.position()); | |
299 } | |
300 } | |
301 } | |
302 | |
303 Element find(SourceString elementName) { | |
304 return elements[elementName]; | |
305 } | |
306 | |
307 void forEachExport(f(Element element)) { | |
308 elements.forEach((SourceString _, Element e) { | |
309 if (this === e.getLibrary() | |
310 && e.kind !== ElementKind.PREFIX | |
311 && e.kind !== ElementKind.FOREIGN) { | |
312 if (!e.name.isPrivate()) f(e); | |
313 } | |
314 }); | |
315 } | |
316 | |
317 bool hasLibraryName() => libraryTag !== null; | |
318 } | |
319 | |
320 class PrefixElement extends Element { | |
321 Map<SourceString, Element> imported; | |
322 Token firstPosition; | |
323 | |
324 PrefixElement(SourceString prefix, Element enclosing, this.firstPosition) | |
325 : imported = new Map<SourceString, Element>(), | |
326 super(prefix, ElementKind.PREFIX, enclosing); | |
327 | |
328 lookupLocalMember(SourceString memberName) => imported[memberName]; | |
329 | |
330 Type computeType(Compiler compiler) => compiler.types.dynamicType; | |
331 | |
332 Token position() => firstPosition; | |
333 } | |
334 | |
335 class TypedefElement extends Element { | |
336 Token token; | |
337 TypedefElement(SourceString name, Element enclosing, this.token) | |
338 : super(name, ElementKind.TYPEDEF, enclosing); | |
339 | |
340 position() => findMyName(token); | |
341 } | |
342 | |
343 class VariableElement extends Element { | |
344 final VariableListElement variables; | |
345 Expression cachedNode; // The send or the identifier in the variables list. | |
346 | |
347 Modifiers get modifiers() => variables.modifiers; | |
348 | |
349 VariableElement(SourceString name, | |
350 VariableListElement this.variables, | |
351 ElementKind kind, | |
352 Element enclosing, | |
353 [Node node]) | |
354 : super(name, kind, enclosing), cachedNode = node; | |
355 | |
356 Node parseNode(DiagnosticListener listener) { | |
357 if (cachedNode !== null) return cachedNode; | |
358 VariableDefinitions definitions = variables.parseNode(listener); | |
359 for (Link<Node> link = definitions.definitions.nodes; | |
360 !link.isEmpty(); link = link.tail) { | |
361 Expression initializedIdentifier = link.head; | |
362 Identifier identifier = initializedIdentifier.asIdentifier(); | |
363 if (identifier === null) { | |
364 identifier = initializedIdentifier.asSendSet().selector.asIdentifier(); | |
365 } | |
366 if (name === identifier.source) { | |
367 cachedNode = initializedIdentifier; | |
368 return cachedNode; | |
369 } | |
370 } | |
371 listener.cancel('internal error: could not find $name', node: variables); | |
372 } | |
373 | |
374 Type computeType(Compiler compiler) { | |
375 return variables.computeType(compiler); | |
376 } | |
377 | |
378 Type get type() => variables.type; | |
379 | |
380 bool isInstanceMember() { | |
381 return isMember() && !modifiers.isStatic(); | |
382 } | |
383 | |
384 // Note: cachedNode.getBeginToken() will not be correct in all | |
385 // cases, for example, for function typed parameters. | |
386 Token position() => findMyName(variables.position()); | |
387 } | |
388 | |
389 /** | |
390 * Parameters in constructors that directly initialize fields. For example: | |
391 * [:A(this.field):]. | |
392 */ | |
393 class FieldParameterElement extends VariableElement { | |
394 VariableElement fieldElement; | |
395 | |
396 FieldParameterElement(SourceString name, | |
397 this.fieldElement, | |
398 VariableListElement variables, | |
399 Element enclosing, | |
400 Node node) | |
401 : super(name, variables, ElementKind.FIELD_PARAMETER, enclosing, node); | |
402 } | |
403 | |
404 // This element represents a list of variable or field declaration. | |
405 // It contains the node, and the type. A [VariableElement] always | |
406 // references its [VariableListElement]. It forwards its | |
407 // [computeType] and [parseNode] methods to this element. | |
408 class VariableListElement extends Element { | |
409 VariableDefinitions cachedNode; | |
410 Type type; | |
411 final Modifiers modifiers; | |
412 | |
413 VariableListElement(ElementKind kind, | |
414 Modifiers this.modifiers, | |
415 Element enclosing) | |
416 : super(null, kind, enclosing); | |
417 | |
418 VariableListElement.node(VariableDefinitions node, | |
419 ElementKind kind, | |
420 Element enclosing) | |
421 : super(null, kind, enclosing), | |
422 this.cachedNode = node, | |
423 this.modifiers = node.modifiers; | |
424 | |
425 VariableDefinitions parseNode(DiagnosticListener listener) { | |
426 return cachedNode; | |
427 } | |
428 | |
429 Type computeType(Compiler compiler) { | |
430 if (type != null) return type; | |
431 type = getType(parseNode(compiler).type, compiler, getLibrary()); | |
432 return type; | |
433 } | |
434 | |
435 Token position() => cachedNode.getBeginToken(); | |
436 } | |
437 | |
438 class ForeignElement extends Element { | |
439 ForeignElement(SourceString name, ContainerElement enclosingElement) | |
440 : super(name, ElementKind.FOREIGN, enclosingElement); | |
441 | |
442 Type computeType(Compiler compiler) { | |
443 return compiler.types.dynamicType; | |
444 } | |
445 | |
446 parseNode(DiagnosticListener listener) { | |
447 throw "internal error: ForeignElement has no node"; | |
448 } | |
449 } | |
450 | |
451 class AbstractFieldElement extends Element { | |
452 FunctionElement getter; | |
453 FunctionElement setter; | |
454 Modifiers modifiers; | |
455 | |
456 AbstractFieldElement(SourceString name, Element enclosing) | |
457 : super(name, ElementKind.ABSTRACT_FIELD, enclosing), | |
458 modifiers = new Modifiers.empty(); | |
459 | |
460 Type computeType(Compiler compiler) { | |
461 throw "internal error: AbstractFieldElement has no type"; | |
462 } | |
463 | |
464 Node parseNode(DiagnosticListener listener) { | |
465 throw "internal error: AbstractFieldElement has no node"; | |
466 } | |
467 | |
468 position() { | |
469 // The getter and setter may be defined in two different | |
470 // compilation units. However, we know that one of them is | |
471 // non-null and defined in the same compilation unit as the | |
472 // abstract element. | |
473 // | |
474 // We need to make sure that the position returned is relative to | |
475 // the compilation unit of the abstract element. | |
476 if (getter !== null && getter.enclosingElement === enclosingElement) { | |
477 return getter.position(); | |
478 } else if (setter != null) { | |
479 // TODO(ahe): checking for null should not be necessary. | |
480 return setter.position(); | |
481 } | |
482 } | |
483 } | |
484 | |
485 /** DEPRECATED. */ | |
486 Type getType(TypeAnnotation typeAnnotation, | |
487 Compiler compiler, | |
488 LibraryElement library) { | |
489 // TODO(karlklose,ngeoffray): This method should be removed and the | |
490 // information should be computed by the resolver. | |
491 | |
492 if (typeAnnotation == null || typeAnnotation.typeName == null) { | |
493 return compiler.types.dynamicType; | |
494 } | |
495 Identifier identifier = typeAnnotation.typeName.asIdentifier(); | |
496 if (identifier === null) { | |
497 compiler.reportWarning(typeAnnotation.typeName, | |
498 'library prefixes not handled'); | |
499 return compiler.types.dynamicType; | |
500 } | |
501 SourceString name = identifier.source; | |
502 Element element = library.find(name); | |
503 if (element !== null) { | |
504 if (element.isTypedef()) { | |
505 // TODO(ngeoffray): This is a hack to help us get support for the | |
506 // DOM library. | |
507 // TODO(ngeoffray): The list of types for the argument is wrong. | |
508 return new FunctionType(compiler.types.dynamicType, | |
509 const EmptyLink<Type>(), | |
510 element); | |
511 } | |
512 if (element.isClass()) { | |
513 // TODO(karlklose): substitute type parameters. | |
514 return element.computeType(compiler); | |
515 } | |
516 } | |
517 Type type = compiler.types.lookup(name); | |
518 if (type === null) { | |
519 type = compiler.types.dynamicType; | |
520 } | |
521 return type; | |
522 } | |
523 | |
524 class FunctionParameters { | |
525 Link<Element> requiredParameters; | |
526 Link<Element> optionalParameters; | |
527 int requiredParameterCount; | |
528 int optionalParameterCount; | |
529 FunctionParameters(this.requiredParameters, | |
530 this.optionalParameters, | |
531 this.requiredParameterCount, | |
532 this.optionalParameterCount); | |
533 | |
534 void forEachParameter(void function(Element parameter)) { | |
535 for (Link<Element> link = requiredParameters; | |
536 !link.isEmpty(); | |
537 link = link.tail) { | |
538 function(link.head); | |
539 } | |
540 for (Link<Element> link = optionalParameters; | |
541 !link.isEmpty(); | |
542 link = link.tail) { | |
543 function(link.head); | |
544 } | |
545 } | |
546 | |
547 int get parameterCount() => requiredParameterCount + optionalParameterCount; | |
548 } | |
549 | |
550 class FunctionElement extends Element { | |
551 FunctionExpression cachedNode; | |
552 Type type; | |
553 final Modifiers modifiers; | |
554 | |
555 FunctionParameters functionParameters; | |
556 | |
557 /** | |
558 * If this is an interface constructor, [defaultImplementation] will | |
559 * changed by the resolver to point to the default | |
560 * implementation. Otherwise, [:defaultImplementation === this:]. | |
561 */ | |
562 FunctionElement defaultImplementation; | |
563 | |
564 FunctionElement(SourceString name, | |
565 ElementKind kind, | |
566 Modifiers modifiers, | |
567 Element enclosing) | |
568 : this.tooMuchOverloading(name, null, kind, modifiers, enclosing, null); | |
569 | |
570 FunctionElement.node(SourceString name, | |
571 FunctionExpression node, | |
572 ElementKind kind, | |
573 Modifiers modifiers, | |
574 Element enclosing) | |
575 : this.tooMuchOverloading(name, node, kind, modifiers, enclosing, null); | |
576 | |
577 FunctionElement.from(SourceString name, | |
578 FunctionElement other, | |
579 Element enclosing) | |
580 : this.tooMuchOverloading(name, other.cachedNode, other.kind, | |
581 other.modifiers, enclosing, | |
582 other.functionParameters); | |
583 | |
584 FunctionElement.tooMuchOverloading(SourceString name, | |
585 FunctionExpression this.cachedNode, | |
586 ElementKind kind, | |
587 Modifiers this.modifiers, | |
588 Element enclosing, | |
589 FunctionParameters this.functionParameters) | |
590 : super(name, kind, enclosing) | |
591 { | |
592 defaultImplementation = this; | |
593 } | |
594 | |
595 bool isInstanceMember() { | |
596 return isMember() | |
597 && kind != ElementKind.GENERATIVE_CONSTRUCTOR | |
598 && !modifiers.isFactory() | |
599 && !modifiers.isStatic(); | |
600 } | |
601 | |
602 FunctionParameters computeParameters(Compiler compiler) { | |
603 if (functionParameters !== null) return functionParameters; | |
604 functionParameters = compiler.resolveSignature(this); | |
605 return functionParameters; | |
606 } | |
607 | |
608 int requiredParameterCount(Compiler compiler) { | |
609 return computeParameters(compiler).requiredParameterCount; | |
610 } | |
611 | |
612 int optionalParameterCount(Compiler compiler) { | |
613 return computeParameters(compiler).optionalParameterCount; | |
614 } | |
615 | |
616 int parameterCount(Compiler compiler) { | |
617 return computeParameters(compiler).parameterCount; | |
618 } | |
619 | |
620 FunctionType computeType(Compiler compiler) { | |
621 if (type != null) return type; | |
622 FunctionParameters parameters = computeParameters(compiler); | |
623 Types types = compiler.types; | |
624 FunctionExpression node = | |
625 compiler.parser.measure(() => parseNode(compiler)); | |
626 Type returnType = getType(node.returnType, compiler, getLibrary()); | |
627 if (returnType === null) returnType = types.dynamicType; | |
628 | |
629 LinkBuilder<Type> parameterTypes = new LinkBuilder<Type>(); | |
630 for (Link<Element> link = parameters.requiredParameters; | |
631 !link.isEmpty(); | |
632 link = link.tail) { | |
633 parameterTypes.addLast(link.head.computeType(compiler)); | |
634 } | |
635 type = new FunctionType(returnType, parameterTypes.toLink(), this); | |
636 return type; | |
637 } | |
638 | |
639 Node parseNode(DiagnosticListener listener) => cachedNode; | |
640 | |
641 Token position() => cachedNode.getBeginToken(); | |
642 } | |
643 | |
644 class ConstructorBodyElement extends FunctionElement { | |
645 FunctionElement constructor; | |
646 | |
647 ConstructorBodyElement(FunctionElement constructor) | |
648 : this.constructor = constructor, | |
649 super(constructor.name, | |
650 ElementKind.GENERATIVE_CONSTRUCTOR_BODY, | |
651 null, | |
652 constructor.enclosingElement) { | |
653 functionParameters = constructor.functionParameters; | |
654 } | |
655 | |
656 bool isInstanceMember() => true; | |
657 | |
658 FunctionType computeType(Compiler compiler) { unreachable(); } | |
659 | |
660 Node parseNode(DiagnosticListener listener) { | |
661 if (cachedNode !== null) return cachedNode; | |
662 cachedNode = constructor.parseNode(listener); | |
663 assert(cachedNode !== null); | |
664 return cachedNode; | |
665 } | |
666 | |
667 Token position() => constructor.position(); | |
668 } | |
669 | |
670 class SynthesizedConstructorElement extends FunctionElement { | |
671 SynthesizedConstructorElement(Element enclosing) | |
672 : super(enclosing.name, ElementKind.GENERATIVE_CONSTRUCTOR, | |
673 null, enclosing); | |
674 | |
675 Token position() => enclosingElement.position(); | |
676 } | |
677 | |
678 class ClassElement extends ContainerElement { | |
679 Type type; | |
680 Type supertype; | |
681 Type defaultClass; | |
682 Link<Element> members = const EmptyLink<Element>(); | |
683 Map<SourceString, Element> localMembers; | |
684 Map<SourceString, Element> constructors; | |
685 Link<Type> interfaces = const EmptyLink<Type>(); | |
686 Map<SourceString, TypeVariableElement> typeParameters; | |
687 bool isResolved = false; | |
688 bool isBeingResolved = false; | |
689 // backendMembers are members that have been added by the backend to simplify | |
690 // compilation. They don't have any user-side counter-part. | |
691 Link<Element> backendMembers = const EmptyLink<Element>(); | |
692 | |
693 Link<Type> allSupertypes; | |
694 | |
695 ClassElement(SourceString name, CompilationUnitElement enclosing) | |
696 : localMembers = new Map<SourceString, Element>(), | |
697 constructors = new Map<SourceString, Element>(), | |
698 typeParameters = new Map<SourceString, TypeVariableElement>(), | |
699 super(name, ElementKind.CLASS, enclosing); | |
700 | |
701 void addMember(Element element, DiagnosticListener listener) { | |
702 members = members.prepend(element); | |
703 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR || | |
704 element.modifiers.isFactory()) { | |
705 constructors[element.name] = element; | |
706 } else if (element.kind == ElementKind.GETTER | |
707 || element.kind == ElementKind.SETTER) { | |
708 addGetterOrSetter(element, localMembers[element.name], listener); | |
709 } else { | |
710 localMembers[element.name] = element; | |
711 } | |
712 } | |
713 | |
714 Type computeType(compiler) { | |
715 if (type === null) { | |
716 type = new SimpleType(name, this); | |
717 } | |
718 return type; | |
719 } | |
720 | |
721 ClassElement ensureResolved(Compiler compiler) { | |
722 if (!isResolved && !isBeingResolved) { | |
723 isBeingResolved = true; | |
724 compiler.resolveType(this); | |
725 isBeingResolved = false; | |
726 isResolved = true; | |
727 } | |
728 return this; | |
729 } | |
730 | |
731 Element lookupTypeParameter(SourceString parameterName) { | |
732 Element result = typeParameters[parameterName]; | |
733 return result; | |
734 } | |
735 | |
736 Element lookupLocalMember(SourceString memberName) { | |
737 return localMembers[memberName]; | |
738 } | |
739 | |
740 Element lookupSuperMember(SourceString memberName) { | |
741 for (ClassElement s = superclass; s != null; s = s.superclass) { | |
742 Element e = s.lookupLocalMember(memberName); | |
743 if (e !== null) { | |
744 if (!memberName.isPrivate() || getLibrary() === e.getLibrary()) { | |
745 return e; | |
746 } | |
747 } | |
748 } | |
749 return null; | |
750 } | |
751 | |
752 Element lookupConstructor(SourceString className, | |
753 [SourceString constructorName = | |
754 const SourceString(''), | |
755 Element noMatch(Element)]) { | |
756 // TODO(karlklose): have a map from class names to a map of constructors | |
757 // instead of creating the name here? | |
758 SourceString normalizedName; | |
759 if (constructorName !== const SourceString('')) { | |
760 normalizedName = Elements.constructConstructorName(className, | |
761 constructorName); | |
762 } else { | |
763 normalizedName = className; | |
764 } | |
765 Element result = constructors[normalizedName]; | |
766 if (result === null && noMatch !== null) { | |
767 result = noMatch(lookupLocalMember(constructorName)); | |
768 } | |
769 return result; | |
770 } | |
771 | |
772 /** | |
773 * Returns the super class, if any. | |
774 * | |
775 * The returned element may not be resolved yet. | |
776 */ | |
777 ClassElement get superclass() { | |
778 assert(isResolved); | |
779 return supertype === null ? null : supertype.element; | |
780 } | |
781 | |
782 bool isInterface() => false; | |
783 bool isNative() => nativeName != null; | |
784 SourceString nativeName; | |
785 } | |
786 | |
787 class Elements { | |
788 static bool isLocal(Element element) { | |
789 return ((element !== null) | |
790 && !element.isInstanceMember() | |
791 && !isStaticOrTopLevelField(element) | |
792 && !isStaticOrTopLevelFunction(element) | |
793 && (element.kind === ElementKind.VARIABLE || | |
794 element.kind === ElementKind.PARAMETER || | |
795 element.kind === ElementKind.FUNCTION)); | |
796 } | |
797 | |
798 static bool isInstanceField(Element element) { | |
799 return (element !== null) | |
800 && element.isInstanceMember() | |
801 && (element.kind === ElementKind.FIELD | |
802 || element.kind === ElementKind.GETTER | |
803 || element.kind === ElementKind.SETTER); | |
804 } | |
805 | |
806 static bool isStaticOrTopLevel(Element element) { | |
807 return (element != null) | |
808 && !element.isInstanceMember() | |
809 && element.enclosingElement !== null | |
810 && (element.enclosingElement.kind == ElementKind.CLASS || | |
811 element.enclosingElement.kind == ElementKind.COMPILATION_UNIT || | |
812 element.enclosingElement.kind == ElementKind.LIBRARY); | |
813 } | |
814 | |
815 static bool isStaticOrTopLevelField(Element element) { | |
816 return isStaticOrTopLevel(element) | |
817 && (element.kind === ElementKind.FIELD | |
818 || element.kind === ElementKind.GETTER | |
819 || element.kind === ElementKind.SETTER); | |
820 } | |
821 | |
822 static bool isStaticOrTopLevelFunction(Element element) { | |
823 return isStaticOrTopLevel(element) | |
824 && (element.kind === ElementKind.FUNCTION); | |
825 } | |
826 | |
827 static bool isInstanceMethod(Element element) { | |
828 return (element != null) | |
829 && element.isInstanceMember() | |
830 && (element.kind === ElementKind.FUNCTION); | |
831 } | |
832 | |
833 static bool isInstanceSend(Send send, TreeElements elements) { | |
834 Element element = elements[send]; | |
835 if (element === null) return !isClosureSend(send, elements); | |
836 return isInstanceMethod(element) || isInstanceField(element); | |
837 } | |
838 | |
839 static bool isClosureSend(Send send, TreeElements elements) { | |
840 if (send.isPropertyAccess) return false; | |
841 if (send.receiver !== null) return false; | |
842 Element element = elements[send]; | |
843 // (o)() or foo()(). | |
844 if (element === null && send.selector.asIdentifier() === null) return true; | |
845 if (element === null) return false; | |
846 // foo() with foo a local or a parameter. | |
847 return isLocal(element); | |
848 } | |
849 | |
850 static SourceString constructConstructorName(SourceString receiver, | |
851 SourceString selector) { | |
852 String r = receiver.slowToString(); | |
853 String s = selector.slowToString(); | |
854 return new SourceString('$r\$$s'); | |
855 } | |
856 | |
857 static SourceString constructOperatorName(SourceString receiver, | |
858 SourceString selector, | |
859 [bool isPrefix = false]) { | |
860 String str = selector.stringValue; | |
861 if (str === '==' || str === '!=') return Namer.OPERATOR_EQUALS; | |
862 | |
863 if (str === '~') str = 'not'; | |
864 else if (str === 'negate' || (str === '-' && isPrefix)) str = 'negate'; | |
865 else if (str === '[]') str = 'index'; | |
866 else if (str === '[]=') str = 'indexSet'; | |
867 else if (str === '*' || str === '*=') str = 'mul'; | |
868 else if (str === '/' || str === '/=') str = 'div'; | |
869 else if (str === '%' || str === '%=') str = 'mod'; | |
870 else if (str === '~/' || str === '~/=') str = 'tdiv'; | |
871 else if (str === '+' || str === '+=') str = 'add'; | |
872 else if (str === '-' || str === '-=') str = 'sub'; | |
873 else if (str === '<<' || str === '<<=') str = 'shl'; | |
874 else if (str === '>>' || str === '>>=') str = 'shr'; | |
875 else if (str === '>=') str = 'ge'; | |
876 else if (str === '>') str = 'gt'; | |
877 else if (str === '<=') str = 'le'; | |
878 else if (str === '<') str = 'lt'; | |
879 else if (str === '&' || str === '&=') str = 'and'; | |
880 else if (str === '^' || str === '^=') str = 'xor'; | |
881 else if (str === '|' || str === '|=') str = 'or'; | |
882 else { | |
883 throw new Exception('Unhandled selector: ${selector.slowToString()}'); | |
884 } | |
885 return new SourceString('$receiver\$$str'); | |
886 } | |
887 | |
888 static bool isStringSupertype(Element element, Compiler compiler) { | |
889 LibraryElement coreLibrary = compiler.coreLibrary; | |
890 return (element == coreLibrary.find(const SourceString('Comparable'))) | |
891 || (element == coreLibrary.find(const SourceString('Hashable'))) | |
892 || (element == coreLibrary.find(const SourceString('Pattern'))); | |
893 } | |
894 | |
895 static bool isListSupertype(Element element, Compiler compiler) { | |
896 LibraryElement coreLibrary = compiler.coreLibrary; | |
897 return (element == coreLibrary.find(const SourceString('Collection'))) | |
898 || (element == coreLibrary.find(const SourceString('Iterable'))); | |
899 } | |
900 } | |
901 | |
902 | |
903 class LabelElement extends Element { | |
904 final Identifier label; | |
905 final String labelName; | |
906 final TargetElement target; | |
907 bool isBreakTarget = false; | |
908 bool isContinueTarget = false; | |
909 LabelElement(Identifier label, this.labelName, this.target, | |
910 Element enclosingElement) | |
911 : this.label = label, | |
912 super(label.source, ElementKind.LABEL, enclosingElement); | |
913 | |
914 void setBreakTarget() { | |
915 isBreakTarget = true; | |
916 target.isBreakTarget = true; | |
917 } | |
918 void setContinueTarget() { | |
919 isContinueTarget = true; | |
920 target.isContinueTarget = true; | |
921 } | |
922 | |
923 bool get isTarget() => isBreakTarget || isContinueTarget; | |
924 Node parseNode(DiagnosticListener l) => label; | |
925 | |
926 Token position() => label.token; | |
927 String toString() => "${labelName}:"; | |
928 } | |
929 | |
930 // Represents a reference to a statement, either a label or the | |
931 // default target of a break or continue. | |
932 class TargetElement extends Element { | |
933 // TODO(lrn): StatementElement is not just referencing statements anymore. | |
934 final Node statement; | |
935 final int nestingLevel; | |
936 Link<LabelElement> labels = const EmptyLink<LabelElement>(); | |
937 bool isBreakTarget = false; | |
938 bool isContinueTarget = false; | |
939 | |
940 TargetElement(this.statement, this.nestingLevel, Element enclosingElement) | |
941 : super(const SourceString(""), ElementKind.STATEMENT, enclosingElement); | |
942 bool get isTarget() => isBreakTarget || isContinueTarget; | |
943 | |
944 LabelElement addLabel(Identifier label, String labelName) { | |
945 LabelElement result = new LabelElement(label, labelName, this, | |
946 enclosingElement); | |
947 labels = labels.prepend(result); | |
948 return result; | |
949 } | |
950 | |
951 Node parseNode(DiagnosticListener l) => statement; | |
952 | |
953 bool get isSwitch() => statement is SwitchStatement; | |
954 | |
955 Token position() => statement.getBeginToken(); | |
956 String toString() => statement.toString(); | |
957 } | |
958 | |
959 class TypeVariableElement extends Element { | |
960 final Node node; | |
961 Type bound; | |
962 Type type; | |
963 TypeVariableElement(name, Element enclosing, this.node, this.type, | |
964 [this.bound]) | |
965 : super(name, ElementKind.TYPE_VARIABLE, enclosing); | |
966 Type computeType(compiler) => type; | |
967 Node parseNode(compiler) => node; | |
968 toString() => "${enclosingElement.toString()}.${name.slowToString()}"; | |
969 } | |
OLD | NEW |