Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * An event generating parser of Dart programs. This parser expects | 6 * An event generating parser of Dart programs. This parser expects |
| 7 * all tokens in a linked list. | 7 * all tokens in a linked list. |
| 8 */ | 8 */ |
| 9 class Parser<L extends Listener> { | 9 class PartialParser<L extends Listener> { |
| 10 final L listener; | 10 final L listener; |
| 11 Function beginTypeArguments; | |
|
kasperl
2011/11/10 06:37:34
I think these function fields deserve a comment. W
ahe
2011/11/10 07:59:46
I'll wrap these in a class and clean it up. After
| |
| 12 Function parseTypeFunction; | |
| 13 Function endTypeArguments; | |
| 14 Function handleNoTypeArguments; | |
| 11 | 15 |
| 12 Parser(L this.listener); | 16 Function beginTypeVariables; |
| 17 Function parseTypeVariableFunction; | |
| 18 Function endTypeVariables; | |
| 19 Function handleNoTypeVariables; | |
| 20 | |
| 21 PartialParser(L this.listener) { | |
| 22 beginTypeArguments = listener.beginTypeArguments; | |
| 23 parseTypeFunction = parseType; | |
| 24 endTypeArguments = listener.endTypeArguments; | |
| 25 handleNoTypeArguments = listener.handleNoTypeArguments; | |
| 26 | |
| 27 beginTypeVariables = listener.beginTypeVariables; | |
| 28 parseTypeVariableFunction = parseTypeVariable; | |
| 29 endTypeVariables = listener.endTypeVariables; | |
| 30 handleNoTypeVariables = listener.handleNoTypeVariables; | |
| 31 } | |
| 13 | 32 |
| 14 // TODO(ahe): Rename this method. It is too subtle compared to token.next. | 33 // TODO(ahe): Rename this method. It is too subtle compared to token.next. |
| 15 Token next(Token token) => checkEof(token.next); | 34 Token next(Token token) => checkEof(token.next); |
| 16 | 35 |
| 17 Token checkEof(Token token) { | 36 Token checkEof(Token token) { |
| 18 if (token.kind === EOF_TOKEN) { | 37 if (token.kind === EOF_TOKEN) { |
| 19 listener.unexpectedEof(); | 38 listener.unexpectedEof(); |
| 20 throw 'Unexpected EOF'; | 39 throw 'Unexpected EOF'; |
| 21 } | 40 } |
| 22 return token; | 41 return token; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 token = next(token); | 181 token = next(token); |
| 163 } while (token !== null); | 182 } while (token !== null); |
| 164 throw 'Internal error: unreachable code'; | 183 throw 'Internal error: unreachable code'; |
| 165 } | 184 } |
| 166 | 185 |
| 167 Token parseClass(Token token) { | 186 Token parseClass(Token token) { |
| 168 Token begin = token; | 187 Token begin = token; |
| 169 listener.beginClass(token); | 188 listener.beginClass(token); |
| 170 token = parseIdentifier(next(token)); | 189 token = parseIdentifier(next(token)); |
| 171 token = parseTypeVariablesOpt(token); | 190 token = parseTypeVariablesOpt(token); |
| 172 token = parseSuperclassClauseOpt(token); | 191 Token extendsKeyword; |
| 173 token = parseImplementsOpt(token); | 192 if (optional('extends', token)) { |
| 193 extendsKeyword = token; | |
| 194 token = parseType(next(token)); | |
| 195 } else { | |
| 196 extendsKeyword = null; | |
| 197 listener.handleNoType(token); | |
|
ngeoffray
2011/11/10 08:27:42
Should that be handleNoSuperType instead?
ahe
2011/11/10 13:37:23
Not necessarily. I could change it if someone has
| |
| 198 } | |
| 199 Token implementsKeyword; | |
| 200 int interfacesCount = 0; | |
| 201 if (optional('implements', token)) { | |
| 202 do { | |
| 203 token = parseType(next(token)); | |
| 204 ++interfacesCount; | |
| 205 } while (optional(',', token)); | |
| 206 } | |
| 174 token = parseNativeClassClauseOpt(token); | 207 token = parseNativeClassClauseOpt(token); |
| 175 token = parseClassBody(token); | 208 token = parseClassBody(token); |
| 176 listener.endClass(begin, token); | 209 listener.endClass(interfacesCount, begin, extendsKeyword, implementsKeyword, |
| 210 token); | |
| 177 return token.next; | 211 return token.next; |
| 178 } | 212 } |
| 179 | 213 |
| 180 Token parseNativeClassClauseOpt(Token token) { | 214 Token parseNativeClassClauseOpt(Token token) { |
| 181 if (optional('native', token)) { | 215 if (optional('native', token)) { |
| 182 return parseString(next(token)); | 216 return parseString(next(token)); |
| 183 } | 217 } |
| 184 return token; | 218 return token; |
| 185 } | 219 } |
| 186 | 220 |
| 187 Token parseString(Token token) { | 221 Token parseString(Token token) { |
| 188 if (token.kind === STRING_TOKEN) { | 222 if (token.kind === STRING_TOKEN) { |
| 189 return next(token); | 223 return next(token); |
| 190 } else { | 224 } else { |
| 191 return listener.expected('string', token); | 225 return listener.expected('string', token); |
| 192 } | 226 } |
| 193 } | 227 } |
| 194 | 228 |
| 195 Token parseIdentifier(Token token) { | 229 Token parseIdentifier(Token token) { |
| 196 if (isIdentifier(token)) { | 230 if (isIdentifier(token)) { |
| 197 listener.handleIdentifier(token); | 231 listener.handleIdentifier(token); |
| 198 } else { | 232 } else { |
| 199 listener.expectedIdentifier(token); | 233 listener.expectedIdentifier(token); |
| 200 } | 234 } |
| 201 return next(token); | 235 return next(token); |
| 202 } | 236 } |
| 203 | 237 |
| 204 Token parseTypeVariablesOpt(Token token) { | |
| 205 if (!optional('<', token)) { | |
| 206 listener.handleNoTypeVariables(token); | |
| 207 return token; | |
| 208 } | |
| 209 return parseTypeVariables(token); | |
| 210 } | |
| 211 | |
| 212 Token parseTypeVariables(Token token) { | |
| 213 expect('<', token); | |
| 214 listener.beginTypeVariables(token); | |
| 215 do { | |
| 216 token = parseTypeVariable(next(token)); | |
| 217 } while (optional(',', token)); | |
| 218 listener.endTypeVariables(token); | |
| 219 return expect('>', token); | |
| 220 } | |
| 221 | |
| 222 Token expect(String string, Token token) { | 238 Token expect(String string, Token token) { |
| 223 if (string !== token.stringValue) { | 239 if (string !== token.stringValue) { |
| 224 return listener.expected(string, token); | 240 return listener.expected(string, token); |
| 225 } | 241 } |
| 226 return token.next; | 242 return token.next; |
| 227 } | 243 } |
| 228 | 244 |
| 229 Token parseTypeVariable(Token token) { | 245 Token parseTypeVariable(Token token) { |
| 230 listener.beginTypeVariable(token); | 246 listener.beginTypeVariable(token); |
| 231 token = parseIdentifier(token); | 247 token = parseIdentifier(token); |
| 232 token = parseSuperclassClauseOpt(token); | 248 if (optional('extends', token)) { |
| 249 token = parseType(next(token)); | |
| 250 } else { | |
| 251 listener.handleNoType(token); | |
| 252 } | |
| 233 listener.endTypeVariable(token); | 253 listener.endTypeVariable(token); |
| 234 return token; | 254 return token; |
| 235 } | 255 } |
| 236 | 256 |
| 237 bool optional(String value, Token token) => value === token.stringValue; | 257 bool optional(String value, Token token) => value === token.stringValue; |
| 238 | 258 |
| 239 Token parseSuperclassClauseOpt(Token token) { | |
| 240 if (optional('extends', token)) { | |
| 241 return parseType(next(token)); | |
| 242 } | |
| 243 return token; | |
| 244 } | |
| 245 | |
| 246 Token parseType(Token token) { | 259 Token parseType(Token token) { |
| 247 // TODO(ahe): Rename this method to parseTypeOrVar? | 260 // TODO(ahe): Rename this method to parseTypeOrVar? |
| 248 if (isIdentifier(token)) { | 261 if (isIdentifier(token)) { |
| 249 token = parseIdentifier(token); | 262 token = parseIdentifier(token); |
| 250 while (optional('.', token)) { | 263 while (optional('.', token)) { |
| 251 // TODO(ahe): Validate that there are at most two identifiers. | 264 // TODO(ahe): Validate that there are at most two identifiers. |
| 252 token = parseIdentifier(next(token)); | 265 token = parseIdentifier(next(token)); |
| 253 } | 266 } |
| 254 } else if (optional('var', token)) { | 267 } else if (optional('var', token)) { |
| 255 listener.handleVarKeyword(token); | 268 listener.handleVarKeyword(token); |
| 256 listener.endType(token); | 269 listener.endType(token); |
| 257 return next(token); | 270 return next(token); |
| 258 } else { | 271 } else { |
| 259 token = listener.expectedType(token); | 272 token = listener.expectedType(token); |
| 260 } | 273 } |
| 261 token = parseTypeArgumentsOpt(token); | 274 token = parseTypeArgumentsOpt(token); |
| 262 listener.endType(token); | 275 listener.endType(token); |
| 263 return token; | 276 return token; |
| 264 } | 277 } |
| 265 | 278 |
| 266 Token parseTypeArgumentsOpt(Token token) { | 279 Token parseTypeArgumentsOpt(Token token) { |
| 280 return parseStuff(token, beginTypeArguments, parseTypeFunction, | |
| 281 endTypeArguments, handleNoTypeArguments); | |
| 282 } | |
| 283 | |
| 284 Token parseTypeVariablesOpt(Token token) { | |
| 285 return parseStuff(token, beginTypeVariables, parseTypeVariableFunction, | |
| 286 endTypeVariables, handleNoTypeVariables); | |
| 287 } | |
| 288 | |
| 289 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | |
|
kasperl
2011/11/10 06:37:34
It would be nice with a more saying name for this.
ahe
2011/11/10 13:37:23
Added TODO.
| |
| 290 Function endStuff, Function handleNoStuff) { | |
| 267 if (optional('<', token)) { | 291 if (optional('<', token)) { |
| 268 listener.beginTypeArguments(next(token)); | 292 Token begin = token; |
| 293 beginStuff(begin); | |
| 294 int count = 0; | |
| 269 do { | 295 do { |
| 270 token = parseType(next(token)); | 296 token = stuffParser(next(token)); |
| 297 ++count; | |
| 271 } while (optional(',', token)); | 298 } while (optional(',', token)); |
| 299 endStuff(count, begin, token); | |
| 272 return expect('>', token); | 300 return expect('>', token); |
| 273 } | 301 } |
| 302 handleNoStuff(token); | |
| 274 return token; | 303 return token; |
| 275 } | 304 } |
| 276 | 305 |
| 277 Token parseImplementsOpt(Token token) { | |
| 278 if (optional('implements', token)) { | |
| 279 do { | |
| 280 token = parseType(next(token)); | |
| 281 } while (optional(',', token)); | |
| 282 } | |
| 283 return token; | |
| 284 } | |
| 285 | |
| 286 Token parseClassBody(Token token) => skipBlock(token); | 306 Token parseClassBody(Token token) => skipBlock(token); |
| 287 | 307 |
| 288 Token parseTopLevelMember(Token token) { | 308 Token parseTopLevelMember(Token token) { |
| 289 Token start = token; | 309 Token start = token; |
| 290 listener.beginTopLevelMember(token); | 310 listener.beginTopLevelMember(token); |
| 291 Token previous = token; | 311 Token previous = token; |
| 292 LOOP: while (token !== null) { | 312 LOOP: while (token !== null) { |
| 293 final kind = token.kind; | 313 final kind = token.kind; |
| 294 switch (true) { | 314 switch (true) { |
| 295 case kind === LBRACE_TOKEN: | 315 case kind === LBRACE_TOKEN: |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 while (token !== null && | 361 while (token !== null && |
| 342 token.kind !== LPAREN_TOKEN && | 362 token.kind !== LPAREN_TOKEN && |
| 343 token.kind !== RPAREN_TOKEN) { | 363 token.kind !== RPAREN_TOKEN) { |
| 344 token = next(token); | 364 token = next(token); |
| 345 } | 365 } |
| 346 token = expect(')', token); | 366 token = expect(')', token); |
| 347 return expect(';', token); | 367 return expect(';', token); |
| 348 } | 368 } |
| 349 } | 369 } |
| 350 | 370 |
| 351 class BodyParser extends Parser/* <BodyListener> Frog bug #320 */ { | 371 class Parser extends PartialParser/* <NodeListener> Frog bug #320 */ { |
| 352 BodyParser(BodyListener listener) : super(listener); | 372 Parser(NodeListener listener) : super(listener); |
| 353 | 373 |
| 354 Token parseFunction(Token token) { | 374 Token parseFunction(Token token) { |
| 355 listener.beginFunction(token); | 375 listener.beginFunction(token); |
| 356 token = parseReturnTypeOpt(token); | 376 token = parseReturnTypeOpt(token); |
| 357 listener.beginFunctionName(token); | 377 listener.beginFunctionName(token); |
| 358 token = parseIdentifier(token); | 378 token = parseIdentifier(token); |
| 359 listener.endFunctionName(token); | 379 listener.endFunctionName(token); |
| 360 token = parseFormalParameters(token); | 380 token = parseFormalParameters(token); |
| 361 return parseFunctionBody(token); | 381 return parseFunctionBody(token); |
| 362 } | 382 } |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 705 if (optional(';', token)) { | 725 if (optional(';', token)) { |
| 706 listener.endRethrowStatement(throwToken, token); | 726 listener.endRethrowStatement(throwToken, token); |
| 707 return token.next; | 727 return token.next; |
| 708 } else { | 728 } else { |
| 709 token = parseExpression(token); | 729 token = parseExpression(token); |
| 710 listener.endThrowStatement(throwToken, token); | 730 listener.endThrowStatement(throwToken, token); |
| 711 return expectSemicolon(token); | 731 return expectSemicolon(token); |
| 712 } | 732 } |
| 713 } | 733 } |
| 714 } | 734 } |
| OLD | NEW |