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 part of scanner; | |
6 | |
7 class ClassElementParser extends PartialParser { | |
8 ClassElementParser(Listener listener) : super(listener); | |
9 | |
10 Token parseClassBody(Token token) => fullParseClassBody(token); | |
11 } | |
12 | |
13 class PartialClassElement extends ClassElementX with PartialElement { | |
14 ClassNode cachedNode; | |
15 | |
16 PartialClassElement(String name, | |
17 Token beginToken, | |
18 Token endToken, | |
19 Element enclosing, | |
20 int id) | |
21 : super(name, enclosing, id, STATE_NOT_STARTED) { | |
22 this.beginToken = beginToken; | |
23 this.endToken = endToken; | |
24 } | |
25 | |
26 void set supertypeLoadState(int state) { | |
27 assert(state == supertypeLoadState + 1); | |
28 assert(state <= STATE_DONE); | |
29 super.supertypeLoadState = state; | |
30 } | |
31 | |
32 void set resolutionState(int state) { | |
33 assert(state == resolutionState + 1); | |
34 assert(state <= STATE_DONE); | |
35 super.resolutionState = state; | |
36 } | |
37 | |
38 bool get hasNode => cachedNode != null; | |
39 | |
40 ClassNode get node { | |
41 assert(invariant(this, cachedNode != null, | |
42 message: "Node has not been computed for $this.")); | |
43 return cachedNode; | |
44 } | |
45 | |
46 ClassNode parseNode(Compiler compiler) { | |
47 if (cachedNode != null) return cachedNode; | |
48 compiler.withCurrentElement(this, () { | |
49 compiler.parser.measure(() { | |
50 MemberListener listener = new MemberListener(compiler, this); | |
51 Parser parser = new ClassElementParser(listener); | |
52 Token token = parser.parseTopLevelDeclaration(beginToken); | |
53 assert(identical(token, endToken.next)); | |
54 cachedNode = listener.popNode(); | |
55 assert(invariant(beginToken, listener.nodes.isEmpty, | |
56 message: "Non-empty listener stack: ${listener.nodes}")); | |
57 }); | |
58 compiler.patchParser.measure(() { | |
59 if (isPatched) { | |
60 // TODO(lrn): Perhaps extract functionality so it doesn't | |
61 // need compiler. | |
62 compiler.patchParser.parsePatchClassNode(patch); | |
63 } | |
64 }); | |
65 }); | |
66 return cachedNode; | |
67 } | |
68 | |
69 Token get position => beginToken; | |
70 | |
71 // TODO(johnniwinther): Ensure that modifiers are always available. | |
72 Modifiers get modifiers => | |
73 cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY; | |
74 | |
75 accept(ElementVisitor visitor) => visitor.visitClassElement(this); | |
76 } | |
77 | |
78 class MemberListener extends NodeListener { | |
79 final ClassElement enclosingElement; | |
80 | |
81 MemberListener(DiagnosticListener listener, | |
82 Element enclosingElement) | |
83 : this.enclosingElement = enclosingElement, | |
84 super(listener, enclosingElement.compilationUnit); | |
85 | |
86 bool isConstructorName(Node nameNode) { | |
87 if (enclosingElement == null || | |
88 enclosingElement.kind != ElementKind.CLASS) { | |
89 return false; | |
90 } | |
91 String name; | |
92 if (nameNode.asIdentifier() != null) { | |
93 name = nameNode.asIdentifier().source; | |
94 } else { | |
95 Send send = nameNode.asSend(); | |
96 name = send.receiver.asIdentifier().source; | |
97 } | |
98 return enclosingElement.name == name; | |
99 } | |
100 | |
101 // TODO(johnniwinther): Remove this method. | |
102 String getMethodNameHack(Node methodName) { | |
103 Send send = methodName.asSend(); | |
104 if (send == null) { | |
105 if (isConstructorName(methodName)) return ''; | |
106 return methodName.asIdentifier().source; | |
107 } | |
108 Identifier receiver = send.receiver.asIdentifier(); | |
109 Identifier selector = send.selector.asIdentifier(); | |
110 Operator operator = selector.asOperator(); | |
111 if (operator != null) { | |
112 assert(identical(receiver.source, 'operator')); | |
113 // TODO(ahe): It is a hack to compare to ')', but it beats | |
114 // parsing the node. | |
115 bool isUnary = identical(operator.token.next.next.stringValue, ')'); | |
116 return Elements.constructOperatorName(operator.source, isUnary); | |
117 } else { | |
118 if (receiver == null || receiver.source != enclosingElement.name) { | |
119 listener.reportError(send.receiver, | |
120 MessageKind.INVALID_CONSTRUCTOR_NAME, | |
121 {'name': enclosingElement.name}); | |
122 } | |
123 return selector.source; | |
124 } | |
125 } | |
126 | |
127 void endMethod(Token getOrSet, Token beginToken, Token endToken) { | |
128 super.endMethod(getOrSet, beginToken, endToken); | |
129 FunctionExpression method = popNode(); | |
130 pushNode(null); | |
131 bool isConstructor = isConstructorName(method.name); | |
132 String name = getMethodNameHack(method.name); | |
133 Element memberElement; | |
134 if (isConstructor) { | |
135 if (getOrSet != null) { | |
136 recoverableError(getOrSet, 'illegal modifier'); | |
137 } | |
138 memberElement = new PartialConstructorElement( | |
139 name, beginToken, endToken, | |
140 ElementKind.GENERATIVE_CONSTRUCTOR, | |
141 method.modifiers, | |
142 enclosingElement); | |
143 } else { | |
144 ElementKind kind = ElementKind.FUNCTION; | |
145 if (getOrSet != null) { | |
146 kind = (identical(getOrSet.stringValue, 'get')) | |
147 ? ElementKind.GETTER : ElementKind.SETTER; | |
148 } | |
149 memberElement = | |
150 new PartialFunctionElement(name, beginToken, getOrSet, endToken, | |
151 kind, method.modifiers, enclosingElement, | |
152 !method.hasBody()); | |
153 } | |
154 addMember(memberElement); | |
155 } | |
156 | |
157 void endFactoryMethod(Token beginToken, Token endToken) { | |
158 super.endFactoryMethod(beginToken, endToken); | |
159 FunctionExpression method = popNode(); | |
160 pushNode(null); | |
161 String name = getMethodNameHack(method.name); | |
162 Identifier singleIdentifierName = method.name.asIdentifier(); | |
163 if (singleIdentifierName != null && singleIdentifierName.source == name) { | |
164 if (name != enclosingElement.name) { | |
165 listener.reportError(singleIdentifierName, | |
166 MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME, | |
167 {'name': enclosingElement.name}); | |
168 } | |
169 } | |
170 ElementKind kind = ElementKind.FUNCTION; | |
171 Element memberElement = new PartialConstructorElement( | |
172 name, beginToken, endToken, | |
173 ElementKind.FUNCTION, | |
174 method.modifiers, | |
175 enclosingElement); | |
176 addMember(memberElement); | |
177 } | |
178 | |
179 void endFields(int count, Token beginToken, Token endToken) { | |
180 bool hasParseError = memberErrors.head; | |
181 super.endFields(count, beginToken, endToken); | |
182 VariableDefinitions variableDefinitions = popNode(); | |
183 Modifiers modifiers = variableDefinitions.modifiers; | |
184 pushNode(null); | |
185 void buildFieldElement(Identifier name, VariableList fields) { | |
186 Element element = | |
187 new FieldElementX(name, enclosingElement, fields); | |
188 addMember(element); | |
189 } | |
190 buildFieldElements(modifiers, variableDefinitions.definitions, | |
191 enclosingElement, | |
192 buildFieldElement, beginToken, endToken, | |
193 hasParseError); | |
194 } | |
195 | |
196 void endInitializer(Token assignmentOperator) { | |
197 pushNode(null); // Super expects an expression, but | |
198 // ClassElementParser just skips expressions. | |
199 super.endInitializer(assignmentOperator); | |
200 } | |
201 | |
202 void endInitializers(int count, Token beginToken, Token endToken) { | |
203 pushNode(null); | |
204 } | |
205 | |
206 void addMember(Element memberElement) { | |
207 for (Link link = metadata; !link.isEmpty; link = link.tail) { | |
208 memberElement.addMetadata(link.head); | |
209 } | |
210 metadata = const Link<MetadataAnnotation>(); | |
211 enclosingElement.addMember(memberElement, listener); | |
212 } | |
213 | |
214 void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { | |
215 popNode(); // Discard arguments. | |
216 if (periodBeforeName != null) { | |
217 popNode(); // Discard name. | |
218 } | |
219 popNode(); // Discard node (Send or Identifier). | |
220 pushMetadata(new PartialMetadataAnnotation(beginToken, endToken)); | |
221 } | |
222 } | |
OLD | NEW |