Index: pkg/fasta/lib/src/source/stack_listener.dart |
diff --git a/pkg/fasta/lib/src/source/stack_listener.dart b/pkg/fasta/lib/src/source/stack_listener.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..310d7e6f0fb316a51078c3ab47eb094edb15460c |
--- /dev/null |
+++ b/pkg/fasta/lib/src/source/stack_listener.dart |
@@ -0,0 +1,214 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library fasta.stack_listener; |
+ |
+import 'dart:collection' show |
+ Queue; |
+ |
+import 'package:dart_parser/src/listener.dart' show |
+ Listener; |
+ |
+import 'package:dart_scanner/src/token.dart' show |
+ BeginGroupToken, |
+ Token; |
+ |
+import 'package:kernel/ast.dart' show |
+ AsyncMarker; |
+ |
+import '../errors.dart' show |
+ inputError, |
+ internalError; |
+ |
+import '../quote.dart' show |
+ unescapeString; |
+ |
+enum NullValue { |
+ Arguments, |
+ Block, |
+ BreakTarget, |
+ CascadeReceiver, |
+ Combinators, |
+ ContinueTarget, |
+ Expression, |
+ FormalParameters, |
+ FunctionBody, |
+ IdentifierList, |
+ Initializers, |
+ Metadata, |
+ Modifiers, |
+ SwitchScope, |
+ Type, |
+ TypeArguments, |
+ TypeList, |
+ TypeVariable, |
+ TypeVariables, |
+} |
+ |
+abstract class StackListener extends Listener { |
+ final Queue<Object> stack = new Queue<Object>(); |
+ |
+ Uri get uri; |
+ |
+ // TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart |
+ // and ast_builder.dart. |
+ void finishFunction(formals, AsyncMarker asyncModifier, body) { |
+ return internalError("Unsupported operation"); |
+ } |
+ |
+ // TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart |
+ // and ast_builder.dart. |
+ void exitLocalScope() => internalError("Unsupported operation"); |
+ |
+ // TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart |
+ // and ast_builder.dart. |
+ void prepareInitializers() => internalError("Unsupported operation"); |
+ |
+ void push(Object node) { |
+ if (node == null) internalError("null not allowed."); |
+ stack.addLast(node); |
+ } |
+ |
+ Object peek() { |
+ Object node = stack.last; |
+ return node is NullValue ? null : node; |
+ } |
+ |
+ Object pop() { |
+ Object node = stack.removeLast(); |
+ return node is NullValue ? null : node; |
+ } |
+ |
+ Object popIfNotNull(Object value) { |
+ return value == null ? null : pop(); |
+ } |
+ |
+ List popList(int n) { |
+ if (n == 0) return null; |
+ List list = new List.filled(n, null, growable: true); |
+ for (int i = n - 1; i >= 0; i--) { |
+ list[i] = pop(); |
Johnni Winther
2017/01/19 11:45:10
Convert NullValue to `null` to match semantics of
ahe
2017/01/19 11:52:15
I'd rather not. It would make it harder to type th
|
+ } |
+ return list; |
+ } |
+ |
+ void debugEvent(String name) { |
+ // printEvent(name); |
+ } |
+ |
+ void printEvent(String name) { |
+ for (Object o in stack) { |
+ String s = " $o"; |
+ int index = s.indexOf("\n"); |
+ if (index != -1) { |
+ s = s.substring(0, index) + "..."; |
+ } |
+ print(s); |
+ } |
+ print(name); |
+ } |
+ |
+ void logEvent(String name) { |
+ print(" ${stack.join('\n ')}"); |
+ internalError("Unhandled event: $name in $runtimeType $uri."); |
+ } |
+ |
+ void handleIdentifier(Token token) { |
+ debugEvent("handleIdentifier"); |
+ push(token.value); |
+ } |
+ |
+ void endConstructorInitializer(Token token) { |
+ debugEvent("ConstructorInitializer"); |
+ } |
+ |
+ void checkEmpty() { |
+ if (stack.isNotEmpty) { |
+ internalError("${runtimeType}: Stack not empty $uri:\n" |
+ " ${stack.join('\n ')}"); |
+ } |
+ if (recoverableErrors.isNotEmpty) { |
+ // TODO(ahe): Handle recoverable errors better. |
+ inputError(uri, recoverableErrors.first.token.charOffset, |
+ recoverableErrors); |
+ } |
+ } |
+ |
+ void endTopLevelDeclaration(Token token) { |
+ debugEvent("TopLevelDeclaration"); |
+ checkEmpty(); |
+ } |
+ |
+ void endCompilationUnit(int count, Token token) { |
+ debugEvent("CompilationUnit"); |
+ checkEmpty(); |
+ } |
+ |
+ void handleNoTypeArguments(Token token) { |
+ debugEvent("NoTypeArguments"); |
+ push(NullValue.TypeArguments); |
+ } |
+ |
+ void handleNoTypeVariables(Token token) { |
+ debugEvent("NoTypeVariables"); |
+ push(NullValue.TypeVariables); |
+ } |
+ |
+ void handleNoType(Token token) { |
+ debugEvent("NoType"); |
+ push(NullValue.Type); |
+ } |
+ |
+ void handleNoFormalParameters(Token token) { |
+ debugEvent("NoFormalParameters"); |
+ push(NullValue.FormalParameters); |
+ } |
+ |
+ void handleNoArguments(Token token) { |
+ debugEvent("NoArguments"); |
+ push(NullValue.Arguments); |
+ } |
+ |
+ void handleNoFunctionBody(Token token) { |
+ debugEvent("NoFunctionBody"); |
+ push(NullValue.FunctionBody); |
+ } |
+ |
+ void handleNoInitializers() { |
+ debugEvent("NoInitializers"); |
+ push(NullValue.Initializers); |
+ } |
+ |
+ void handleParenthesizedExpression(BeginGroupToken token) { |
+ debugEvent("ParenthesizedExpression"); |
+ } |
+ |
+ void beginLiteralString(Token token) { |
+ debugEvent("beginLiteralString"); |
+ push(token); |
+ } |
+ |
+ void endLiteralString(int interpolationCount) { |
+ debugEvent("endLiteralString"); |
+ if (interpolationCount == 0) { |
+ Token token = pop(); |
+ push(unescapeString(token.value)); |
+ } else { |
+ internalError("String interpolation not implemented."); |
+ } |
+ } |
+ |
+ void handleStringJuxtaposition(int literalCount) { |
+ debugEvent("StringJuxtaposition"); |
+ push(popList(literalCount).join("")); |
+ } |
+ |
+ void endCatchClause(Token token) { |
+ debugEvent("CatchClause"); |
+ } |
+ |
+ void error(String message, Token token) { |
+ inputError(uri, token.charOffset, message); |
+ } |
+} |