Index: pkg/analyzer/lib/src/summary/fasta/summary_builder.dart |
diff --git a/pkg/analyzer/lib/src/summary/fasta/summary_builder.dart b/pkg/analyzer/lib/src/summary/fasta/summary_builder.dart |
deleted file mode 100644 |
index 6425913c2dfb326d64cbc880578941205e5a9a29..0000000000000000000000000000000000000000 |
--- a/pkg/analyzer/lib/src/summary/fasta/summary_builder.dart |
+++ /dev/null |
@@ -1,1568 +0,0 @@ |
-// Copyright (c) 2017, 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. |
- |
-/// Logic to build unlinked summaries. |
-library summary.src.summary_builder; |
- |
-import 'package:front_end/src/fasta/parser.dart' |
- show |
- ClassMemberParser, |
- FormalParameterType, |
- IdentifierContext, |
- MemberKind, |
- Parser; |
- |
-import 'package:front_end/src/fasta/scanner.dart' show Token, scan; |
- |
-import 'package:front_end/src/fasta/scanner/token_constants.dart'; |
- |
-import 'expression_serializer.dart'; |
-import 'model.dart'; |
-import 'stack_listener.dart'; |
- |
-const _abstract_flag = 1 << 2; |
- |
-const _async_flag = 1; |
- |
-const _const_flag = 1 << 1; |
- |
-const _external_flag = 1 << 4; |
- |
-const _final_flag = 1; |
- |
-/// Maps modifier names to their bit-mask. |
-const _modifierFlag = const { |
- 'const': _const_flag, |
- 'abstract': _abstract_flag, |
- 'static': _static_flag, |
- 'external': _external_flag, |
- 'final': _final_flag, |
- 'var': _var_flag, |
-}; |
- |
-// bit-masks to encode modifiers as bits on an int. |
- |
-const _star_flag = 1 << 2; |
- |
-const _static_flag = 1 << 3; |
-const _sync_flag = 1 << 1; |
-const _var_flag = 0; |
- |
-/// Retrieve the operator from an assignment operator (e.g. + from +=). |
-/// Operators are encoded using the scanner token kind id. |
-int opForAssignOp(int kind) { |
- switch (kind) { |
- case AMPERSAND_EQ_TOKEN: |
- return AMPERSAND_TOKEN; |
- // TODO(paulberry): add support for &&= |
- // case AMPERSAND_AMPERSAND_EQ_TOKEN: return AMPERSAND_AMPERSAND_TOKEN; |
- case BAR_EQ_TOKEN: |
- return BAR_TOKEN; |
- // TODO(paulberry): add support for ||= |
- // case BAR_BAR_EQ_TOKEN: return BAR_BAR_TOKEN; |
- case CARET_EQ_TOKEN: |
- return CARET_TOKEN; |
- case GT_GT_EQ_TOKEN: |
- return GT_GT_TOKEN; |
- case LT_LT_EQ_TOKEN: |
- return LT_LT_TOKEN; |
- case MINUS_EQ_TOKEN: |
- return MINUS_TOKEN; |
- case PERCENT_EQ_TOKEN: |
- return PERCENT_TOKEN; |
- case PLUS_EQ_TOKEN: |
- return PLUS_TOKEN; |
- case QUESTION_QUESTION_EQ_TOKEN: |
- return QUESTION_QUESTION_TOKEN; |
- case SLASH_EQ_TOKEN: |
- return SLASH_TOKEN; |
- case STAR_EQ_TOKEN: |
- return STAR_TOKEN; |
- case TILDE_SLASH_EQ_TOKEN: |
- return TILDE_SLASH_TOKEN; |
- case PLUS_EQ_TOKEN: |
- return PLUS_TOKEN; |
- default: |
- throw "Unhandled kind $kind"; |
- } |
-} |
- |
-/// Create an unlinked summary given a null-terminated byte buffer with the |
-/// contents of a file. |
-UnlinkedUnit summarize(Uri uri, List<int> contents) { |
- var listener = new SummaryBuilder(uri); |
- var parser = new ClassMemberParser(listener); |
- parser.parseUnit(scan(contents).tokens); |
- return listener.topScope.unit; |
-} |
- |
-/// Builder for constant expressions. |
-/// |
-/// Any invalid subexpression is denoted with [Invalid]. |
-class ConstExpressionBuilder extends ExpressionListener { |
- final Uri uri; |
- Parser parser; |
- ConstExpressionBuilder(this.uri) { |
- parser = new Parser(this); |
- } |
- bool get forConst => true; |
- |
- void endArguments(int count, Token begin, Token end) { |
- debugEvent("Arguments"); |
- if (ignore) return; |
- push(popList(count) ?? const []); |
- } |
- |
- void handleAsOperator(Token op, Token next) { |
- debugEvent("As"); |
- if (ignore) return; |
- push(new As(pop(), pop())); |
- } |
- |
- void handleAssignmentExpression(Token operator) { |
- pop(); // lhs |
- pop(); // rhs |
- push(new Invalid(hint: "assign")); |
- } |
- |
- void handleIndexedExpression( |
- Token openSquareBracket, Token closeSquareBracket) { |
- debugEvent("Index"); |
- if (ignore) return; |
- pop(); // receiver |
- pop(); // index |
- push(new Invalid(hint: "index")); |
- } |
- |
- void handleNamedArgument(colon) { |
- debugEvent("NamedArg"); |
- if (ignore) return; |
- var value = pop(); |
- Ref name = pop(); |
- push(new NamedArg(name.name, value)); |
- } |
- |
- void endNewExpression(Token token) { |
- debugEvent("NewExpression"); |
- if (ignore) return; |
- pop(); // args |
- pop(); // ctor |
- push(new Invalid(hint: "new")); |
- } |
- |
- void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { |
- debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); |
- } |
- |
- void handleUnaryPostfixAssignmentExpression(Token operator) { |
- pop(); |
- push(new Invalid(hint: "postfixOp")); |
- } |
- |
- void handleUnaryPrefixAssignmentExpression(Token operator) { |
- pop(); |
- push(new Invalid(hint: "prefixOp")); |
- } |
- |
- void _endFunction() { |
- assert(_withinFunction >= 0); |
- push(new Invalid(hint: 'function')); |
- } |
- |
- // TODO(paulberry): is this needed? |
- //void _endCascade() { |
- // push(new Invalid(hint: 'cascades')); |
- //} |
- |
- void _unhandledSend() { |
- push(new Invalid(hint: "call")); |
- } |
-} |
- |
-// bit-masks to encode async modifiers as bits on an int. |
- |
-/// Parser listener to build simplified AST expressions. |
-/// |
-/// The parser produces different trees depending on whether it is used for |
-/// constants or initializers, so subclasses specialize the logic accordingly. |
-abstract class ExpressionListener extends StackListener { |
- // Underlying parser that invokes this listener. |
- static const _invariantCheckToken = "invariant check: starting a function"; |
- |
- int _withinFunction = 0; |
- |
- int _withinCascades = 0; |
- |
- /// Whether this listener is used to build const expressions. |
- bool get forConst => false; |
- |
- /// Whether to ignore the next reduction. Used to ignore nested expressions |
- /// that are either invalid (in constants) or unnecessary (for initializers). |
- bool get ignore => _withinFunction > 0 || _withinCascades > 0; |
- |
- Parser get parser; |
- |
- void beginCascade(Token token) { |
- _withinCascades++; |
- } |
- |
- void beginFunctionDeclaration(token) { |
- debugEvent("BeginFunctionDeclaration"); |
- _withinFunction++; |
- } |
- |
- void beginLiteralString(Token token) { |
- debugEvent("beginLiteralString"); |
- if (ignore) return; |
- push(new StringLiteral(token.lexeme)); |
- } |
- |
- void beginUnnamedFunction(token) { |
- debugEvent("BeginUnnamedFunction"); |
- var check = pop(); |
- assert(check == _invariantCheckToken); |
- _withinFunction++; |
- } |
- |
- UnlinkedExprBuilder computeExpression(Token token, Scope scope) { |
- debugStart(token); |
- parser.parseExpression(token); |
- debugEvent('---- END ---'); |
- Expression node = pop(); |
- checkEmpty(); |
- return new Serializer(scope, forConst).run(node); |
- } |
- |
- void debugEvent(String name) { |
- if (const bool.fromEnvironment('CDEBUG', defaultValue: false)) { |
- var s = stack.join(' :: '); |
- if (s == '') s = '<empty>'; |
- var bits = '$_withinFunction,$_withinCascades'; |
- var prefix = ignore ? "ignore $name on:" : "do $name on:"; |
- prefix = '$prefix${" " * (30 - prefix.length)}'; |
- print('$prefix $bits $s'); |
- } |
- } |
- |
- void debugStart(Token token) { |
- debugEvent('\n---- START: $runtimeType ---'); |
- if (const bool.fromEnvironment('CDEBUG', defaultValue: false)) { |
- _printExpression(token); |
- } |
- } |
- |
- void endCascade() { |
- _withinCascades--; |
- throw new UnimplementedError(); // TODO(paulberry): fix the code below. |
- // _endCascade(); |
- } |
- |
- void endConstructorReference( |
- Token start, Token periodBeforeName, Token endToken) { |
- debugEvent("ConstructorReference $start $periodBeforeName"); |
- Ref ctorName = popIfNotNull(periodBeforeName); |
- assert(ctorName?.prefix == null); |
- List<TypeRef> typeArgs = pop(); |
- Ref type = pop(); |
- push(new ConstructorName(new TypeRef(type, typeArgs), ctorName?.name)); |
- } |
- |
- void endFormalParameter(Token thisKeyword, Token nameToken, |
- FormalParameterType kind, MemberKind memberKind) { |
- debugEvent("FormalParameter"); |
- assert(ignore); |
- } |
- |
- void endFormalParameters( |
- int count, Token beginToken, Token endToken, MemberKind kind) { |
- debugEvent("FormalParameters"); |
- assert(ignore); |
- } |
- |
- void endBlockFunctionBody(int count, Token begin, Token end) { |
- debugEvent("BlockFunctionBody"); |
- assert(ignore); |
- } |
- |
- void endFunctionDeclaration(token) { |
- debugEvent("FunctionDeclaration"); |
- _withinFunction--; |
- if (ignore) return; |
- _endFunction(); |
- } |
- |
- void endFunctionName(Token beginToken, Token token) { |
- debugEvent("FunctionName"); |
- assert(ignore); |
- } |
- |
- void endLiteralMapEntry(colon, token) { |
- debugEvent('MapEntry'); |
- if (ignore) return; |
- var value = pop(); |
- var key = pop(); |
- push(new KeyValuePair(key, value)); |
- } |
- |
- void endLiteralString(int interpolationCount, Token endToken) { |
- debugEvent("endLiteralString"); |
- if (interpolationCount != 0) { |
- popList(2 * interpolationCount + 1); |
- push(new StringLiteral("<interpolate $interpolationCount>")); |
- } |
- } |
- |
- void endLiteralSymbol(token, int dots) { |
- debugEvent('LiteralSymbol'); |
- if (ignore) return; |
- push(new SymbolLiteral(popList(dots).join('.'))); |
- } |
- |
- void endReturnStatement(hasValue, Token begin, Token end) { |
- debugEvent("ReturnStatement"); |
- assert(ignore); |
- } |
- |
- // type-arguments are expected to be type references passed to constructors |
- // and generic methods, we need them to model instantiations. |
- void endSend(Token beginToken, Token endToken) { |
- debugEvent("EndSend"); |
- if (ignore) return; |
- List<Expression> args = pop(); |
- if (args != null) { |
- /* var typeArgs = */ pop(); |
- var receiver = pop(); |
- // TODO(sigmund): consider making identical a binary operator. |
- if (receiver is Ref && receiver.name == 'identical') { |
- assert(receiver.prefix == null); |
- assert(args.length == 2); |
- push(new Identical(args[0], args[1])); |
- return; |
- } |
- _unhandledSend(); |
- } |
- } |
- |
- void endThrowExpression(throwToken, token) { |
- debugEvent("Throw"); |
- assert(ignore); |
- } |
- |
- void endTypeArguments(int count, Token beginToken, Token endToken) { |
- debugEvent("TypeArguments"); |
- if (ignore) return; |
- push(popList(count) ?? const <TypeRef>[]); |
- } |
- |
- void endTypeList(int count) { |
- debugEvent("TypeList"); |
- push(popList(count) ?? const <TypeRef>[]); |
- } |
- |
- void endTypeVariable(Token token, Token extendsOrSuper) { |
- debugEvent("endTypeVariable"); |
- assert(ignore); |
- } |
- |
- void endTypeVariables(int count, Token beginToken, Token endToken) { |
- debugEvent("TypeVariables"); |
- assert(ignore); |
- } |
- |
- void endUnnamedFunction(Token beginToken, Token token) { |
- debugEvent("UnnamedFunction"); |
- _withinFunction--; |
- if (ignore) return; |
- _endFunction(); |
- } |
- |
- void handleAsyncModifier(Token asyncToken, Token starToken) { |
- debugEvent("AsyncModifier"); |
- assert(ignore); |
- } |
- |
- void handleBinaryExpression(Token operator) { |
- debugEvent("BinaryExpression"); |
- if (ignore) return; |
- Expression right = pop(); |
- Expression left = pop(); |
- var kind = operator.kind; |
- if (kind == PERIOD_TOKEN) { |
- if (left is Ref && |
- right is Ref && |
- right.prefix == null && |
- left.prefixDepth < 2) { |
- push(new Ref(right.name, left)); |
- return; |
- } |
- if (right is Ref) { |
- push(new Load(left, right.name)); |
- return; |
- } |
- } |
- push(new Binary(left, right, kind)); |
- } |
- |
- void handleConditionalExpression(Token question, Token colon) { |
- debugEvent("ConditionalExpression"); |
- if (ignore) return; |
- var falseBranch = pop(); |
- var trueBranch = pop(); |
- var cond = pop(); |
- push(new Conditional(cond, trueBranch, falseBranch)); |
- } |
- |
- @override |
- void endConstExpression(Token token) { |
- debugEvent("ConstExpression"); |
- if (ignore) return; |
- List args = pop(); |
- var constructorName = pop(); |
- var positional = args.where((a) => a is! NamedArg).toList(); |
- var named = args.where((a) => a is NamedArg).toList(); |
- push(new ConstCreation(constructorName, positional, named)); |
- } |
- |
- void handleIdentifier(Token token, IdentifierContext context) { |
- debugEvent("Identifier"); |
- if (ignore) return; |
- push(new Ref(token.lexeme)); |
- } |
- |
- void handleIsOperator(Token operator, Token not, Token endToken) { |
- debugEvent("Is"); |
- if (ignore) return; |
- push(new Is(pop(), pop())); |
- } |
- |
- void handleLiteralBool(Token token) { |
- debugEvent("LiteralBool"); |
- if (ignore) return; |
- push(new BoolLiteral(token.lexeme == 'true')); |
- } |
- |
- void handleLiteralDouble(Token token) { |
- debugEvent("LiteralDouble"); |
- if (ignore) return; |
- push(new DoubleLiteral(double.parse(token.lexeme))); |
- } |
- |
- void handleLiteralInt(Token token) { |
- debugEvent("LiteralInt"); |
- if (ignore) return; |
- push(new IntLiteral(int.parse(token.lexeme))); |
- } |
- |
- void handleLiteralList(count, begin, constKeyword, end) { |
- debugEvent("LiteralList"); |
- if (ignore) return; |
- var values = popList(count) ?? const <Expression>[]; |
- List<TypeRef> typeArguments = pop(); |
- var type = typeArguments?.single; |
- push(new ListLiteral(type, values, constKeyword != null)); |
- } |
- |
- void handleLiteralMap(count, begin, constKeyword, end) { |
- debugEvent('LiteralMap'); |
- if (ignore) return; |
- var values = popList(count) ?? const <KeyValuePair>[]; |
- var typeArgs = pop() ?? const <TypeRef>[]; |
- push(new MapLiteral(typeArgs, values, constKeyword != null)); |
- } |
- |
- void handleLiteralNull(Token token) { |
- debugEvent("LiteralNull"); |
- if (ignore) return; |
- push(new NullLiteral()); |
- } |
- |
- void handleModifier(Token token) { |
- debugEvent("Modifier"); |
- assert(ignore); |
- } |
- |
- // TODO(sigmund): remove |
- void handleModifiers(int count) { |
- debugEvent("Modifiers"); |
- assert(ignore); |
- } |
- |
- // type-variables are the declared parameters on declarations. |
- void handleNoArguments(Token token) { |
- debugEvent("NoArguments"); |
- if (ignore) return; |
- var typeArguments = pop(); |
- assert(typeArguments == null); |
- push(NullValue.Arguments); |
- } |
- |
- void handleNoFormalParameters(Token token, MemberKind kind) { |
- debugEvent("NoFormalParameters"); |
- assert(ignore); |
- } |
- |
- void handleNoFunctionBody(Token token) { |
- debugEvent("NoFunctionBody"); |
- assert(ignore); |
- } |
- |
- void handleNoInitializer() {} |
- |
- void handleNoInitializers() { |
- debugEvent("NoInitializers"); |
- assert(ignore); |
- } |
- |
- void handleNoType(Token token) { |
- debugEvent("NoType"); |
- if (ignore) return; |
- push(NullValue.Type); |
- } |
- |
- void handleNoTypeArguments(Token token) { |
- debugEvent("NoTypeArguments"); |
- if (ignore) return; |
- push(NullValue.TypeArguments); |
- } |
- |
- void handleNoTypeVariables(Token token) { |
- debugEvent("NoTypeVariables"); |
- if (ignore) return; |
- push(_invariantCheckToken); |
- } |
- |
- void handleQualified(period) { |
- debugEvent('Qualified'); |
- if (ignore) return; |
- Ref name = pop(); |
- Ref prefix = pop(); |
- assert(name.prefix == null); |
- assert(prefix.prefix == null); |
- push(new Ref(name.name, prefix)); |
- } |
- |
- void handleStringJuxtaposition(int count) { |
- debugEvent("StringJuxtaposition"); |
- if (ignore) return; |
- popList(count); |
- push(new StringLiteral('<juxtapose $count>')); |
- } |
- |
- void handleStringPart(token) { |
- debugEvent("handleStringPart"); |
- if (ignore) return; |
- push(new StringLiteral(token.lexeme)); |
- } |
- |
- void handleType(Token beginToken, Token endToken) { |
- debugEvent("Type"); |
- if (ignore) return; |
- List<TypeRef> arguments = pop(); |
- Ref name = pop(); |
- push(new TypeRef(name, arguments)); |
- } |
- |
- void handleUnaryPrefixExpression(Token operator) { |
- debugEvent("UnaryPrefix"); |
- if (ignore) return; |
- push(new Unary(pop(), operator.kind)); |
- } |
- |
- void handleVoidKeyword(Token token) { |
- debugEvent("VoidKeyword"); |
- assert(ignore); |
- } |
- |
- /// Overriden: the base class throws when something is not handled, we avoid |
- /// implementing a few handlers when we know we can ignore them. |
- @override |
- void logEvent(e) { |
- if (ignore) return; |
- super.logEvent(e); |
- } |
- |
- void push(Object o); |
- |
- // debug helpers |
- |
- void _endFunction(); |
- |
- void _printExpression(Token token) { |
- var current = token; |
- var end = new ClassMemberParser(this).skipExpression(current); |
- var str = new StringBuffer(); |
- while (current != end) { |
- if (!["(", ",", ")"].contains(current.lexeme)) str.write(' '); |
- str.write(current.lexeme); |
- current = current.next; |
- } |
- print('exp: $str'); |
- } |
- |
- void _unhandledSend(); |
-} |
- |
-/// Builder for initializer expressions. These expressions exclude any nested |
-/// expression that is not needed to infer strong mode types. |
-class InitializerBuilder extends ExpressionListener { |
- final Uri uri; |
- Parser parser; |
- |
- int _inArguments = 0; |
- |
- InitializerBuilder(this.uri) { |
- parser = new Parser(this); |
- } |
- |
- bool get ignore => super.ignore || _inArguments > 0; |
- |
- void beginArguments(Token token) { |
- // TODO(sigmund): determine if we can ignore arguments. |
- //_inArguments++; |
- } |
- |
- // Not necessary, but we don't use the value, so we can abstract it: |
- void endArguments(int count, Token begin, Token end) { |
- debugEvent("Arguments"); |
- //_inArguments--; |
- if (ignore) return; |
- push(popList(count) ?? const []); |
- //push([new Opaque(hint: "arguments")]); |
- } |
- |
- void handleAsOperator(Token op, Token next) { |
- debugEvent("As"); |
- if (ignore) return; |
- TypeRef type = pop(); |
- pop(); |
- push(new Opaque(type: type)); |
- } |
- |
- void handleAssignmentExpression(Token operator) { |
- debugEvent("Assign"); |
- if (ignore) return; |
- var left = pop(); |
- var right = pop(); |
- var kind = operator.kind; |
- if (kind == EQ_TOKEN) { |
- push(new OpaqueOp(right)); |
- } else { |
- push(new OpaqueOp(new Binary(left, right, opForAssignOp(kind)))); |
- } |
- } |
- |
- void handleIndexedExpression( |
- Token openSquareBracket, Token closeSquareBracket) { |
- debugEvent("Index"); |
- if (ignore) return; |
- pop(); |
- pop(); |
- push(new Opaque()); |
- } |
- |
- void handleIsOperator(Token operator, Token not, Token endToken) { |
- debugEvent("Is"); |
- if (ignore) return; |
- throw new UnimplementedError(); // TODO(paulberry): fix the code below. |
- // push(new Opaque(type: new TypeRef(new Ref('bool')))); |
- } |
- |
- void handleNamedArgument(colon) { |
- debugEvent("NamedArg"); |
- if (ignore) return; |
- pop(); |
- pop(); |
- push(NullValue.Arguments); |
- } |
- |
- void endNewExpression(Token token) { |
- debugEvent("NewExpression"); |
- if (ignore) return; |
- pop(); // args |
- /* var ctor = */ pop(); // ctor |
- throw new UnimplementedError(); // TODO(paulberry): fix the code below. |
- // push(new Opaque(type: ctor.type, hint: "new")); |
- } |
- |
- void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { |
- debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); |
- } |
- |
- void handleUnaryPostfixAssignmentExpression(Token operator) { |
- debugEvent("PostFix"); |
- if (ignore) return; |
- // the post-fix effect is not visible to the enclosing expression |
- push(new OpaqueOp(pop())); |
- } |
- |
- void handleUnaryPrefixAssignmentExpression(Token operator) { |
- debugEvent("Prefix"); |
- if (ignore) return; |
- var kind = operator.kind == PLUS_PLUS_TOKEN ? PLUS_TOKEN : MINUS_TOKEN; |
- push(new OpaqueOp(new Binary(pop(), new IntLiteral(1), kind))); |
- } |
- |
- void _endFunction() { |
- push(new Opaque(hint: "function")); |
- } |
- |
- // TODO(paulberry): is this needed? |
- //void _endCascade() { |
- // push(new OpaqueOp(pop(), hint: 'cascades')); |
- //} |
- |
- void _unhandledSend() { |
- push(new Opaque(hint: "call")); |
- } |
-} |
- |
-/// A listener of parser events that builds summary information as parsing |
-/// progresses. |
-class SummaryBuilder extends StackListener { |
- static int parsed = 0; |
- |
- static int total = 0; |
- |
- /// Whether 'dart:core' was imported explicitly by the current unit. |
- bool isDartCoreImported = false; |
- |
- /// Whether the current unit is part of 'dart:core'. |
- bool isCoreLibrary = false; |
- |
- /// Topmost scope. |
- TopScope topScope; |
- |
- /// Current scope where name references are resolved from. |
- Scope scope; |
- |
- /// Helper to build constant expressions. |
- final ConstExpressionBuilder constBuilder; |
- |
- /// Helper to build initializer expressions. |
- final InitializerBuilder initializerBuilder; |
- |
- /// Whether the current initializer has a type declared. |
- /// |
- /// Because initializers are only used for strong-mode inference, we can skip |
- /// parsing and building initializer expressions when a type is declared. |
- bool typeSeen = false; |
- |
- /// Whether we are currently in the context of a const expression. |
- bool inConstContext = false; |
- |
- /// Uri of the file currently being processed, used for error reporting only. |
- final Uri uri; |
- |
- /// Summaries preassign slots for computed information, this is the next |
- /// available slot. |
- int _slots = 0; |
- |
- UnlinkedParamKind _nextParamKind; |
- |
- SummaryBuilder(Uri uri) |
- : uri = uri, |
- constBuilder = new ConstExpressionBuilder(uri), |
- initializerBuilder = new InitializerBuilder(uri); |
- |
- /// Whether we need to parse the initializer of a declaration. |
- bool get needInitializer => !typeSeen || inConstContext; |
- |
- // Directives: imports, exports, parts |
- |
- /// Assign the next slot. |
- int assignSlot() => ++_slots; |
- |
- void beginClassDeclaration(Token beginToken, Token name) { |
- debugEvent("beginClass"); |
- var classScope = scope = new ClassScope(scope); |
- classScope.className = name.lexeme; |
- } |
- |
- void beginCompilationUnit(Token token) { |
- scope = topScope = new TopScope(); |
- } |
- |
- void beginEnum(Token token) { |
- debugEvent("beginEnum"); |
- scope = new EnumScope(scope); |
- } |
- |
- beginFieldInitializer(Token token) { |
- debugEvent("beginFieldInitializer"); |
- total++; |
- if (needInitializer) { |
- parsed++; |
- if (inConstContext) { |
- push(constBuilder.computeExpression(token.next, scope)); |
- } else { |
- push(initializerBuilder.computeExpression(token.next, scope)); |
- } |
- } |
- } |
- |
- void beginFormalParameters(Token token, MemberKind kind) { |
- _nextParamKind = UnlinkedParamKind.required; |
- } |
- |
- void beginFunctionTypeAlias(Token token) { |
- debugEvent('beginFunctionTypeAlias'); |
- // TODO: use a single scope |
- scope = new TypeParameterScope(scope); |
- } |
- |
- beginInitializer(Token token) { |
- // TODO(paulberry): Add support for this. |
- } |
- |
- void beginLiteralString(Token token) { |
- debugEvent("beginLiteralString"); |
- push(token.lexeme.substring(1, token.lexeme.length - 1)); |
- } |
- |
- void beginMember(Token token) { |
- typeSeen = false; |
- inConstContext = false; |
- } |
- |
- // classes, enums, mixins, and typedefs. |
- |
- void beginNamedMixinApplication(Token beginToken, Token name) { |
- debugEvent('beginNamedMixinApplication'); |
- scope = new ClassScope(scope); |
- } |
- |
- void beginOptionalFormalParameters(Token begin) { |
- _nextParamKind = |
- begin == '{' ? UnlinkedParamKind.named : UnlinkedParamKind.positional; |
- } |
- |
- void beginTopLevelMember(Token token) { |
- typeSeen = false; |
- inConstContext = false; |
- } |
- |
- /// If enabled, show a debug message. |
- void debugEvent(String name) { |
- if (const bool.fromEnvironment('DEBUG', defaultValue: false)) { |
- var s = stack.join(' :: '); |
- if (s == '') s = '<empty>'; |
- var bits = 'type?: $typeSeen, const?: $inConstContext'; |
- var prefix = "do $name on:"; |
- prefix = '$prefix${" " * (30 - prefix.length)}'; |
- print('$prefix $bits $s'); |
- } |
- } |
- |
- void endClassBody(int memberCount, Token beginToken, Token endToken) { |
- debugEvent("ClassBody"); |
- } |
- |
- void endClassDeclaration( |
- int interfacesCount, |
- Token beginToken, |
- Token classKeyword, |
- Token extendsKeyword, |
- Token implementsKeyword, |
- Token endToken) { |
- debugEvent("endClassDeclaration"); |
- List<EntityRefBuilder> interfaces = popList(interfacesCount); |
- EntityRef supertype = pop(); |
- List<UnlinkedTypeParamBuilder> typeVariables = pop(); |
- String name = pop(); |
- int modifiers = pop(); |
- List metadata = pop(); |
- checkEmpty(); |
- |
- ClassScope s = scope; |
- s.className = name; |
- s.currentClass |
- ..name = name |
- ..isAbstract = modifiers & _abstract_flag != 0 |
- ..annotations = metadata |
- ..typeParameters = typeVariables |
- ..interfaces = interfaces; |
- if (supertype != null) { |
- s.currentClass.supertype = supertype; |
- } else { |
- s.currentClass.hasNoSupertype = isCoreLibrary && name == 'Object'; |
- } |
- scope = scope.parent; |
- topScope.unit.classes.add(s.currentClass); |
- if (_isPrivate(name)) return; |
- s.publicName |
- ..name = name |
- ..kind = ReferenceKind.classOrEnum |
- ..numTypeParameters = typeVariables?.length; |
- topScope.publicNamespace.names.add(s.publicName); |
- } |
- |
- void endCombinators(int count) { |
- debugEvent("Combinators"); |
- push(popList(count) ?? NullValue.Combinators); |
- } |
- |
- void endCompilationUnit(int count, Token token) { |
- if (!isDartCoreImported) { |
- topScope.unit.imports.add(new UnlinkedImportBuilder(isImplicit: true)); |
- } |
- |
- topScope.expandLazyReferences(); |
- |
- // TODO(sigmund): could this be be optional: done by whoever consumes it? |
- if (const bool.fromEnvironment('SKIP_API')) return; |
- var apiSignature = new ApiSignature(); |
- topScope.unit.collectApiSignature(apiSignature); |
- topScope.unit.apiSignature = apiSignature.toByteList(); |
- } |
- |
- void endConditionalUri(Token ifKeyword, Token equalitySign) { |
- String dottedName = pop(); |
- String value = pop(); |
- String uri = pop(); |
- uri = uri.substring(1, uri.length - 1); |
- push(new UnlinkedConfigurationBuilder( |
- name: dottedName, value: value, uri: uri)); |
- } |
- |
- void endConditionalUris(int count) { |
- push(popList(count) ?? const <UnlinkedConfigurationBuilder>[]); |
- } |
- |
- // members: fields, methods. |
- |
- void endConstructorReference( |
- Token start, Token periodBeforeName, Token endToken) { |
- var ctorName = popIfNotNull(periodBeforeName); |
- var typeArguments = pop(); |
- var className = pop(); |
- push(['ctor-ref:', className, typeArguments, ctorName]); |
- } |
- |
- void endDottedName(count, firstIdentifier) { |
- push(popList(count).join('.')); |
- } |
- |
- void endEnum(Token enumKeyword, Token endBrace, int count) { |
- debugEvent("Enum"); |
- List<String> constants = popList(count); |
- String name = pop(); |
- List metadata = pop(); |
- checkEmpty(); |
- EnumScope s = scope; |
- scope = s.parent; |
- s.currentEnum |
- ..name = name |
- ..annotations = metadata; |
- s.top.unit.enums.add(s.currentEnum); |
- |
- // public namespace: |
- var e = new UnlinkedPublicNameBuilder( |
- name: name, kind: ReferenceKind.classOrEnum, numTypeParameters: 0); |
- for (var s in constants) { |
- e.members.add(new UnlinkedPublicNameBuilder( |
- name: s, kind: ReferenceKind.propertyAccessor, numTypeParameters: 0)); |
- } |
- topScope.publicNamespace.names.add(e); |
- } |
- |
- void endExport(Token exportKeyword, Token semicolon) { |
- debugEvent("Export"); |
- List<UnlinkedCombinator> combinators = pop(); |
- List<UnlinkedConfiguration> conditionalUris = pop(); |
- String uri = pop(); |
- List<UnlinkedExpr> metadata = pop(); |
- topScope.unit.exports |
- .add(new UnlinkedExportNonPublicBuilder(annotations: metadata)); |
- topScope.publicNamespace.exports.add(new UnlinkedExportPublicBuilder( |
- uri: uri, combinators: combinators, configurations: conditionalUris)); |
- checkEmpty(); |
- } |
- |
- void endFactoryMethod( |
- Token beginToken, Token factoryKeyword, Token endToken) { |
- debugEvent("FactoryMethod"); |
- throw new UnimplementedError(); // TODO(paulberry) |
- // pop(); // async-modifiers |
- // /* List<FormalParameterBuilder> formals = */ pop(); |
- // var name = pop(); |
- // /* List<MetadataBuilder> metadata = */ pop(); |
- } |
- |
- void endFieldInitializer(Token assignmentOperator, Token token) { |
- debugEvent("FieldInitializer $typeSeen $assignmentOperator"); |
- // This is a variable initializer and it's ignored for now. May also be |
- // constructor initializer. |
- var initializer = |
- needInitializer && assignmentOperator != null ? pop() : null; |
- var name = pop(); |
- push(new _InitializedName( |
- name, new UnlinkedExecutableBuilder(bodyExpr: initializer))); |
- } |
- |
- void endFields(int count, Token beginToken, Token endToken) { |
- debugEvent("Fields"); |
- var s = scope; |
- if (s is ClassScope) { |
- _endFields(count, s.currentClass.fields, false); |
- } else { |
- throw new UnimplementedError(); // TODO(paulberry): does this ever occur? |
- // _endFields(count, s.currentEnum.values, false); |
- } |
- } |
- |
- void endFormalParameter(Token thisKeyword, Token nameToken, |
- FormalParameterType kind, MemberKind memberKind) { |
- debugEvent("FormalParameter"); |
- // TODO(sigmund): clean up? |
- var nameOrFormal = pop(); |
- if (nameOrFormal is String) { |
- EntityRef type = pop(); |
- pop(); // Modifiers |
- List metadata = pop(); |
- push(new UnlinkedParamBuilder( |
- name: nameOrFormal, |
- kind: _nextParamKind, |
- inheritsCovariantSlot: slotIf(type == null), |
- annotations: metadata, |
- isInitializingFormal: thisKeyword != null, |
- type: type)); |
- } else { |
- push(nameOrFormal); |
- } |
- } |
- |
- void endFormalParameters( |
- int count, Token beginToken, Token endToken, MemberKind kind) { |
- debugEvent("FormalParameters"); |
- List formals = popList(count); |
- if (formals != null && formals.isNotEmpty) { |
- var last = formals.last; |
- if (last is List) { |
- var newList = new List(formals.length - 1 + last.length); |
- newList.setRange(0, formals.length - 1, formals); |
- newList.setRange(formals.length - 1, newList.length, last); |
- for (int i = 0; i < last.length; i++) { |
- newList[i + formals.length - 1] = last[i]; |
- } |
- formals = newList; |
- } |
- } |
- push(formals ?? NullValue.FormalParameters); |
- } |
- |
- void endFunctionTypeAlias( |
- Token typedefKeyword, Token equals, Token endToken) { |
- debugEvent("endFunctionTypeAlias"); |
- List formals = pop(); |
- List typeVariables = pop(); |
- String name = pop(); |
- EntityRef returnType = pop(); |
- List metadata = pop(); |
- // print('TODO: type alias $name'); |
- checkEmpty(); |
- |
- scope = scope.parent; |
- topScope.unit.typedefs.add(new UnlinkedTypedefBuilder( |
- name: name, |
- typeParameters: typeVariables, |
- returnType: returnType, |
- parameters: formals, |
- annotations: metadata)); |
- |
- _addNameIfPublic(name, ReferenceKind.typedef, typeVariables.length); |
- } |
- |
- void endFunctionTypedFormalParameter() { |
- debugEvent("FunctionTypedFormalParameter"); |
- List<UnlinkedParamBuilder> formals = pop(); |
- if (formals != null) formals.forEach((p) => p.inheritsCovariantSlot = null); |
- |
- String name = pop(); |
- EntityRef returnType = pop(); |
- /* List typeVariables = */ pop(); |
- /* int modifiers = */ pop(); |
- List metadata = pop(); |
- |
- push(new UnlinkedParamBuilder( |
- name: name, |
- kind: _nextParamKind, |
- isFunctionTyped: true, |
- parameters: formals, |
- annotations: metadata, |
- type: returnType)); |
- } |
- |
- void endHide(_) { |
- push(new UnlinkedCombinatorBuilder(hides: pop())); |
- } |
- |
- void endIdentifierList(int count) { |
- debugEvent("endIdentifierList"); |
- push(popList(count) ?? NullValue.IdentifierList); |
- } |
- |
- void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword, |
- Token semicolon) { |
- debugEvent("endImport"); |
- List<UnlinkedCombinator> combinators = pop(); |
- String prefix = popIfNotNull(asKeyword); |
- int prefixIndex = |
- prefix == null ? null : topScope.serializeReference(null, prefix); |
- List<UnlinkedConfiguration> conditionalUris = pop(); |
- String uri = pop(); |
- List<UnlinkedExpr> metadata = pop(); // metadata |
- |
- topScope.unit.imports.add(new UnlinkedImportBuilder( |
- uri: uri, |
- prefixReference: prefixIndex, |
- combinators: combinators, |
- configurations: conditionalUris, |
- isDeferred: deferredKeyword != null, |
- annotations: metadata, |
- )); |
- if (uri == 'dart:core') isDartCoreImported = true; |
- checkEmpty(); |
- } |
- |
- void endInitializer(Token assignmentOperator) { |
- // TODO(paulberry): add support for this. |
- debugEvent("Initializer $typeSeen $assignmentOperator"); |
- } |
- |
- void endInitializers(int count, Token beginToken, Token endToken) { |
- debugEvent("Initializers"); |
- // TODO(sigmund): include const-constructor initializers |
- } |
- |
- void endLibraryName(Token libraryKeyword, Token semicolon) { |
- debugEvent("endLibraryName"); |
- String name = pop(); |
- List<UnlinkedExpr> metadata = pop(); // metadata |
- |
- topScope.unit.libraryName = name; |
- topScope.unit.libraryAnnotations = metadata; |
- if (name == 'dart.core') isCoreLibrary = true; |
- } |
- |
- void endLiteralString(int interpolationCount, Token endToken) { |
- assert(interpolationCount == 0); // TODO(sigmund): handle interpolation |
- } |
- |
- void endMember() { |
- debugEvent("Member"); |
- } |
- |
- // TODO(sigmund): handle metadata (this code is incomplete). |
- void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
- debugEvent("Metadata"); |
- List arguments = pop(); |
- var result = new UnlinkedExprBuilder(); |
- // If arguments are null, this is an expression, otherwise a constructor |
- // reference. |
- if (arguments == null) { |
- /* String postfix = */ popIfNotNull(periodBeforeName); |
- /* String expression = */ pop(); |
- //push([expression, postfix]); // @x or @p.x |
- } else { |
- /* String name = */ popIfNotNull(periodBeforeName); |
- // TODO(ahe): Type arguments are missing, eventually they should be |
- // available as part of [arguments]. |
- // List<String> typeArguments = null; |
- /* EntityRef typeName = */ pop(); |
- //push([typeName, typeArguments, name, arguments]); |
- } |
- push(result); |
- } |
- |
- void endMetadataStar(int count, bool forParameter) { |
- debugEvent("MetadataStar"); |
- push(popList(count) ?? NullValue.Metadata); |
- } |
- |
- void endMethod(Token getOrSet, Token beginToken, Token endToken) { |
- debugEvent("Method"); |
- int asyncModifier = pop(); |
- List<UnlinkedParam> formals = pop(); |
- List<UnlinkedTypeParamBuilder> typeVariables = pop(); |
- String name = pop(); |
- EntityRef returnType = pop(); |
- int modifiers = pop(); |
- List metadata = pop(); |
- |
- ClassScope s = scope; |
- bool isStatic = modifiers & _static_flag != 0; |
- bool isConst = modifiers & _const_flag != 0; |
- bool isGetter = getOrSet == 'get'; |
- bool isSetter = getOrSet == 'set'; |
- bool isOperator = name == "operator"; // TODO |
- bool isConstructor = |
- name == s.className || name.startsWith('${s.className}.'); |
- |
- if (isConstructor) { |
- name = name == s.className ? '' : name.substring(name.indexOf('.') + 1); |
- } |
- |
- name = isSetter ? '$name=' : name; |
- // Note: we don't include bodies for any method. |
- s.currentClass.executables.add(new UnlinkedExecutableBuilder( |
- name: name, |
- kind: isGetter |
- ? UnlinkedExecutableKind.getter |
- : (isSetter |
- ? UnlinkedExecutableKind.setter |
- : (isConstructor |
- ? UnlinkedExecutableKind.constructor |
- : UnlinkedExecutableKind.functionOrMethod)), |
- isExternal: modifiers & _external_flag != 0, |
- isAbstract: modifiers & _abstract_flag != 0, |
- isAsynchronous: asyncModifier & _async_flag != 0, |
- isGenerator: asyncModifier & _star_flag != 0, |
- isStatic: isStatic, |
- isConst: isConst, |
- constCycleSlot: slotIf(isConst), |
- typeParameters: typeVariables, |
- returnType: returnType, |
- parameters: formals, // TODO: add inferred slot to args |
- annotations: metadata, |
- inferredReturnTypeSlot: |
- slotIf(returnType == null && !isStatic && !isConstructor))); |
- |
- if (isConstructor && name == '') return; |
- if (_isPrivate(name)) return; |
- if (isSetter || isOperator) return; |
- if (!isStatic && !isConstructor) return; |
- s.publicName.members.add(new UnlinkedPublicNameBuilder( |
- name: name, |
- kind: isGetter |
- ? ReferenceKind.propertyAccessor |
- : (isConstructor |
- ? ReferenceKind.constructor |
- : ReferenceKind.method), |
- numTypeParameters: typeVariables.length)); |
- } |
- |
- void endMixinApplication(Token withKeyword) { |
- debugEvent("MixinApplication"); |
- ClassScope s = scope; |
- s.currentClass.mixins = pop(); |
- } |
- |
- void endNamedMixinApplication(Token begin, Token classKeyword, Token equals, |
- Token implementsKeyword, Token endToken) { |
- debugEvent("endNamedMixinApplication"); |
- List<EntityRef> interfaces = popIfNotNull(implementsKeyword); |
- EntityRef supertype = pop(); |
- List typeVariables = pop(); |
- String name = pop(); |
- int modifiers = pop(); |
- List metadata = pop(); |
- // print('TODO: end mix, $name'); |
- checkEmpty(); |
- |
- ClassScope s = scope; |
- s.currentClass |
- ..name = name |
- ..isAbstract = modifiers & _abstract_flag != 0 |
- ..isMixinApplication = true |
- ..annotations = metadata |
- ..typeParameters = typeVariables |
- ..interfaces = interfaces; |
- if (supertype != null) { |
- s.currentClass.supertype = supertype; |
- } else { |
- s.currentClass.hasNoSupertype = isCoreLibrary && name == 'Object'; |
- } |
- scope = scope.parent; |
- topScope.unit.classes.add(s.currentClass); |
- |
- _addNameIfPublic(name, ReferenceKind.classOrEnum, typeVariables.length); |
- } |
- |
- void endOptionalFormalParameters( |
- int count, Token beginToken, Token endToken) { |
- debugEvent("OptionalFormalParameters"); |
- push(popList(count)); |
- } |
- |
- void endPart(Token partKeyword, Token semicolon) { |
- debugEvent("Part"); |
- String uri = pop(); |
- List<UnlinkedExpr> metadata = pop(); |
- topScope.unit.parts.add(new UnlinkedPartBuilder(annotations: metadata)); |
- topScope.publicNamespace.parts.add(uri); |
- checkEmpty(); |
- } |
- |
- void endPartOf(Token partKeyword, Token semicolon, bool hasName) { |
- debugEvent("endPartOf"); |
- String name = pop(); |
- pop(); // metadata |
- topScope.unit.isPartOf = true; |
- if (name == 'dart.core') isCoreLibrary = true; |
- } |
- |
- void endRedirectingFactoryBody(Token beginToken, Token endToken) { |
- debugEvent("RedirectingFactoryBody"); |
- pop(); // Discard ConstructorReferenceBuilder. |
- } |
- |
- void endShow(_) { |
- push(new UnlinkedCombinatorBuilder(shows: pop())); |
- } |
- |
- void endTopLevelFields(int count, Token beginToken, Token endToken) { |
- debugEvent("endTopLevelFields"); |
- _endFields(count, topScope.unit.variables, true); |
- checkEmpty(); |
- } |
- |
- void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) { |
- debugEvent("endTopLevelMethod"); |
- int asyncModifier = pop(); |
- List formals = pop(); |
- List typeVariables = pop(); |
- String name = pop(); |
- EntityRef returnType = pop(); |
- int modifiers = pop(); |
- List metadata = pop(); |
- checkEmpty(); |
- |
- topScope.unit.executables.add(new UnlinkedExecutableBuilder( |
- name: getOrSet == 'set' ? '$name=' : name, |
- kind: getOrSet == 'get' |
- ? UnlinkedExecutableKind.getter |
- : (getOrSet == 'set' |
- ? UnlinkedExecutableKind.setter |
- : UnlinkedExecutableKind.functionOrMethod), |
- isExternal: modifiers & _external_flag != 0, |
- isAbstract: modifiers & _abstract_flag != 0, |
- isAsynchronous: asyncModifier & _async_flag != 0, |
- isGenerator: asyncModifier & _star_flag != 0, |
- isStatic: modifiers & _static_flag != 0, |
- typeParameters: [], // TODO |
- returnType: returnType, |
- parameters: formals, |
- annotations: metadata, |
- inferredReturnTypeSlot: null, // not needed for top-levels |
- // skip body. |
- )); |
- |
- String normalizedName = getOrSet == 'set' ? '$name=' : name; |
- _addNameIfPublic( |
- normalizedName, |
- getOrSet != null |
- ? ReferenceKind.topLevelPropertyAccessor |
- : ReferenceKind.topLevelFunction, |
- typeVariables?.length ?? 0 /* todo */); |
- } |
- |
- void endTypeArguments(int count, Token beginToken, Token endToken) { |
- debugEvent("TypeArguments"); |
- push(popList(count) ?? const []); |
- } |
- |
- void endTypeList(int count) { |
- debugEvent("TypeList"); |
- push(popList(count) ?? NullValue.TypeList); |
- } |
- |
- void endTypeVariable(Token token, Token extendsOrSuper) { |
- debugEvent("endTypeVariable"); |
- EntityRef bound = pop(); |
- String name = pop(); |
- |
- var s = scope; |
- if (s is TypeParameterScope) { |
- s.typeParameters.add(name); |
- } else { |
- throw new UnimplementedError(); // TODO(paulberry) |
- } |
- push(new UnlinkedTypeParamBuilder(name: name, bound: bound)); |
- } |
- |
- void endTypeVariables(int count, Token beginToken, Token endToken) { |
- debugEvent("TypeVariables"); |
- push(popList(count) ?? const []); |
- } |
- |
- void handleAsyncModifier(Token asyncToken, Token starToken) { |
- debugEvent("AsyncModifier"); |
- int asyncModifier = 0; |
- if (asyncToken == "async") asyncModifier |= _async_flag; |
- if (asyncToken == "sync") asyncModifier |= _sync_flag; |
- if (starToken != null) asyncModifier |= _star_flag; |
- push(asyncModifier); |
- } |
- |
- void handleFormalParameterWithoutValue(Token token) { |
- debugEvent("FormalParameterWithoutValue"); |
- } |
- |
- void handleModifier(Token token) { |
- debugEvent("Modifier"); |
- var modifier = _modifierFlag[token.stringValue]; |
- if (modifier & _const_flag != 0) inConstContext = true; |
- push(modifier); |
- } |
- |
- void handleModifiers(int count) { |
- debugEvent("Modifiers"); |
- push((popList(count) ?? const []).fold/*<int>*/(0, (a, b) => a | b)); |
- } |
- |
- void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { |
- debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); |
- } |
- |
- void handleNoFieldInitializer(Token token) { |
- debugEvent("NoFieldInitializer"); |
- push(new _InitializedName(pop(), null)); |
- } |
- |
- void handleNoFunctionBody(Token token) { |
- debugEvent("NoFunctionBody"); |
- // Ignored for now. We shouldn't see any function bodies. |
- } |
- |
- void handleNoInitializers() { |
- debugEvent("NoInitializers"); |
- // This is a constructor initializer and it's ignored for now. |
- } |
- |
- void handleNoTypeVariables(Token token) { |
- debugEvent("NoTypeVariables"); |
- push(const []); |
- } |
- |
- void handleOperatorName(Token operatorKeyword, Token token) { |
- // TODO(sigmund): convert operator names to name used by summaries. |
- debugEvent("OperatorName"); |
- push(operatorKeyword.lexeme); |
- } |
- |
- void handleQualified(Token period) { |
- debugEvent("handleQualified"); |
- String name = pop(); |
- String receiver = pop(); |
- push("$receiver.$name"); |
- } |
- |
- void handleStringPart(token) { |
- debugEvent("handleStringPart"); |
- push(token.lexeme.substring(1, token.lexeme.length - 1)); |
- } |
- |
- void handleType(Token beginToken, Token endToken) { |
- debugEvent("Type"); |
- List<EntityRef> arguments = pop(); |
- String name = pop(); |
- |
- var type; |
- if (name.contains('.')) { |
- var parts = name.split('.'); |
- for (var p in parts) { |
- type = type == null |
- ? new LazyEntityRef(p, scope) |
- : new NestedLazyEntityRef(type, p, scope); |
- } |
- } else { |
- type = new LazyEntityRef(name, scope); |
- } |
- type.typeArguments = arguments; |
- push(type); |
- typeSeen = true; |
- } |
- |
- // helpers to work with the summary format. |
- |
- void handleValuedFormalParameter(Token equals, Token token) { |
- debugEvent("ValuedFormalParameter"); |
- // TODO(sigmund): include default value on optional args. |
- } |
- |
- void handleVoidKeyword(Token token) { |
- debugEvent("VoidKeyword"); |
- // TODO: skip the lazy mechanism |
- push(new LazyEntityRef("void", scope.top)); |
- } |
- |
- /// Assign the next slot if [condition] is true. |
- int slotIf(bool condition) => condition ? assignSlot() : 0; |
- |
- /// Add [name] to the public namespace. |
- void _addName(String name, ReferenceKind kind, {int numTypeParameters: 0}) { |
- topScope.publicNamespace.names.add(new UnlinkedPublicNameBuilder( |
- name: name, kind: kind, numTypeParameters: numTypeParameters)); |
- } |
- |
- /// Add [name] to the public namespace if it's public. |
- void _addNameIfPublic( |
- String name, ReferenceKind kind, int numTypeParameters) { |
- if (_isPrivate(name)) return null; |
- _addName(name, kind, numTypeParameters: numTypeParameters); |
- } |
- |
- /// Add `name` and, if requested, `name=` to the public namespace. |
- void _addPropertyName(String name, {bool includeSetter: false}) { |
- _addName(name, ReferenceKind.topLevelPropertyAccessor); |
- if (includeSetter) { |
- _addName('$name=', ReferenceKind.topLevelPropertyAccessor); |
- } |
- } |
- |
- void _endFields(int count, List result, bool isTopLevel) { |
- debugEvent('EndFields: $count $isTopLevel'); |
- List<_InitializedName> fields = popList(count); |
- EntityRef type = pop(); |
- int modifiers = pop(); |
- List metadata = pop(); |
- |
- bool isStatic = modifiers & _static_flag != 0; |
- bool isFinal = modifiers & _final_flag != 0; |
- bool isConst = modifiers & _const_flag != 0; |
- bool isInstance = !isStatic && !isTopLevel; |
- for (var field in fields) { |
- var name = field.name; |
- var initializer = field.initializer; |
- bool needsPropagatedType = initializer != null && (isFinal || isConst); |
- bool needsInferredType = |
- type == null && (initializer != null || isInstance); |
- result.add(new UnlinkedVariableBuilder( |
- isFinal: isFinal, |
- isConst: isConst, |
- isStatic: isStatic, |
- name: name, |
- type: type, |
- annotations: metadata, |
- initializer: initializer, |
- propagatedTypeSlot: slotIf(needsPropagatedType), |
- inferredTypeSlot: slotIf(needsInferredType))); |
- |
- if (_isPrivate(name)) continue; |
- if (isTopLevel) { |
- _addPropertyName(name, includeSetter: !isFinal && !isConst); |
- } else if (isStatic) { |
- // Any reason setters are not added as well? |
- (scope as ClassScope).publicName.members.add( |
- new UnlinkedPublicNameBuilder( |
- name: name, |
- kind: ReferenceKind.propertyAccessor, |
- numTypeParameters: 0)); |
- } |
- } |
- } |
- |
- /// Whether a name is private and should be excluded from the public |
- /// namespace. |
- bool _isPrivate(String name) => name.startsWith('_'); |
-} |
- |
-/// Internal representation of an initialized name. |
-class _InitializedName { |
- final String name; |
- final UnlinkedExecutableBuilder initializer; |
- _InitializedName(this.name, this.initializer); |
- |
- toString() => "II:" + (initializer != null ? "$name = $initializer" : name); |
-} |