| 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 |