Index: pkg/front_end/lib/src/fasta/source/diet_listener.dart |
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart |
index 0721751c7cff280f5771ecc717b15015fe6e9756..0a20f0b834c5ab311242a37cabe8c68a8312029c 100644 |
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart |
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart |
@@ -28,7 +28,7 @@ import '../util/link.dart' show Link; |
import '../errors.dart' show Crash, InputError, inputError, internalError; |
-import 'stack_listener.dart' show StackListener; |
+import 'stack_listener.dart' show NullValue, StackListener; |
import '../kernel/body_builder.dart' show BodyBuilder; |
@@ -72,19 +72,21 @@ class DietListener extends StackListener { |
@override |
void endMetadataStar(int count, bool forParameter) { |
debugEvent("MetadataStar"); |
+ push(popList(count)?.first ?? NullValue.Metadata); |
} |
@override |
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
debugEvent("Metadata"); |
- popIfNotNull(periodBeforeName); |
- discard(1); |
+ discard(periodBeforeName == null ? 1 : 2); |
+ push(beginToken); |
} |
@override |
void endPartOf(Token partKeyword, Token semicolon, bool hasName) { |
debugEvent("PartOf"); |
if (hasName) discard(1); |
+ discard(1); // Metadata. |
} |
@override |
@@ -184,9 +186,9 @@ class DietListener extends StackListener { |
debugEvent("FunctionTypeAlias"); |
if (equals != null) { |
// This is a `typedef NAME = TYPE`. |
- discard(1); // Name. |
+ discard(2); // Name and metadata. |
} else { |
- discard(2); // Name + endToken. |
+ discard(3); // Name, endToken, and metadata. |
} |
checkEmpty(typedefKeyword.charOffset); |
} |
@@ -194,9 +196,7 @@ class DietListener extends StackListener { |
@override |
void endFields(int count, Token beginToken, Token endToken) { |
debugEvent("Fields"); |
- List<String> names = popList(count); |
- Builder builder = lookupBuilder(beginToken, null, names.first); |
- buildFields(beginToken, false, builder); |
+ buildFields(count, beginToken, false); |
} |
@override |
@@ -209,9 +209,10 @@ class DietListener extends StackListener { |
debugEvent("TopLevelMethod"); |
Token bodyToken = pop(); |
String name = pop(); |
+ Token metadata = pop(); |
checkEmpty(beginToken.charOffset); |
buildFunctionBody(bodyToken, lookupBuilder(beginToken, getOrSet, name), |
- MemberKind.TopLevelMethod); |
+ MemberKind.TopLevelMethod, metadata); |
} |
@override |
@@ -222,9 +223,7 @@ class DietListener extends StackListener { |
@override |
void endTopLevelFields(int count, Token beginToken, Token endToken) { |
debugEvent("TopLevelFields"); |
- List<String> names = popList(count); |
- Builder builder = lookupBuilder(beginToken, null, names.first); |
- buildFields(beginToken, true, builder); |
+ buildFields(count, beginToken, true); |
} |
@override |
@@ -254,7 +253,7 @@ class DietListener extends StackListener { |
@override |
void endLibraryName(Token libraryKeyword, Token semicolon) { |
debugEvent("endLibraryName"); |
- discard(1); |
+ discard(2); // Name and metadata. |
} |
@override |
@@ -326,22 +325,25 @@ class DietListener extends StackListener { |
Token semicolon) { |
debugEvent("Import"); |
popIfNotNull(asKeyword); |
+ discard(1); // Metadata. |
} |
@override |
void endExport(Token exportKeyword, Token semicolon) { |
debugEvent("Export"); |
+ discard(1); // Metadata. |
} |
@override |
void endPart(Token partKeyword, Token semicolon) { |
debugEvent("Part"); |
+ discard(1); // Metadata. |
} |
@override |
void endTypeVariable(Token token, Token extendsOrSuper) { |
debugEvent("TypeVariable"); |
- discard(1); |
+ discard(2); // Name and metadata. |
} |
@override |
@@ -367,12 +369,15 @@ class DietListener extends StackListener { |
debugEvent("FactoryMethod"); |
BeginToken bodyToken = pop(); |
String name = pop(); |
+ Token metadata = pop(); |
checkEmpty(beginToken.charOffset); |
if (bodyToken == null || optional("=", bodyToken.endGroup.next)) { |
+ // TODO(ahe): Don't skip this. We need to compile metadata and |
+ // redirecting factory bodies. |
return; |
} |
- buildFunctionBody( |
- bodyToken, lookupBuilder(beginToken, null, name), MemberKind.Factory); |
+ buildFunctionBody(bodyToken, lookupBuilder(beginToken, null, name), |
+ MemberKind.Factory, metadata); |
} |
@override |
@@ -386,17 +391,18 @@ class DietListener extends StackListener { |
debugEvent("Method"); |
Token bodyToken = pop(); |
String name = pop(); |
+ Token metadata = pop(); |
checkEmpty(beginToken.charOffset); |
if (bodyToken == null) { |
+ // TODO(ahe): Don't skip this. We need to compile metadata. |
return; |
} |
ProcedureBuilder builder = lookupBuilder(beginToken, getOrSet, name); |
buildFunctionBody( |
bodyToken, |
builder, |
- builder.isStatic |
- ? MemberKind.StaticMethod |
- : MemberKind.NonStaticMethod); |
+ builder.isStatic ? MemberKind.StaticMethod : MemberKind.NonStaticMethod, |
+ metadata); |
} |
StackListener createListener( |
@@ -418,7 +424,7 @@ class DietListener extends StackListener { |
} |
void buildFunctionBody( |
- Token token, ProcedureBuilder builder, MemberKind kind) { |
+ Token token, ProcedureBuilder builder, MemberKind kind, Token metadata) { |
Scope typeParameterScope = builder.computeTypeParameterScope(memberScope); |
Scope formalParameterScope = |
builder.computeFormalParameterScope(typeParameterScope); |
@@ -428,14 +434,18 @@ class DietListener extends StackListener { |
createListener(builder, typeParameterScope, builder.isInstanceMember, |
formalParameterScope), |
token, |
+ metadata, |
kind); |
} |
- void buildFields(Token token, bool isTopLevel, MemberBuilder builder) { |
+ void buildFields(int count, Token token, bool isTopLevel) { |
+ List<String> names = popList(count); |
+ Builder builder = lookupBuilder(token, null, names.first); |
+ Token metadata = pop(); |
// TODO(paulberry): don't re-parse the field if we've already parsed it |
// for type inference. |
parseFields(createListener(builder, memberScope, builder.isInstanceMember), |
- token, isTopLevel); |
+ token, metadata, isTopLevel); |
} |
@override |
@@ -448,6 +458,7 @@ class DietListener extends StackListener { |
void beginClassBody(Token token) { |
debugEvent("beginClassBody"); |
String name = pop(); |
+ pop(); // Metadata. |
assert(currentClass == null); |
currentClass = lookupBuilder(token, null, name); |
assert(memberScope == library.scope); |
@@ -458,7 +469,6 @@ class DietListener extends StackListener { |
void endClassBody(int memberCount, Token beginToken, Token endToken) { |
debugEvent("ClassBody"); |
currentClass = null; |
- checkEmpty(beginToken.charOffset); |
memberScope = library.scope; |
} |
@@ -477,8 +487,7 @@ class DietListener extends StackListener { |
@override |
void endEnum(Token enumKeyword, Token endBrace, int count) { |
debugEvent("Enum"); |
- discard(count); |
- pop(); // Name. |
+ discard(count + 2); // Name and metadata. |
checkEmpty(enumKeyword.charOffset); |
} |
@@ -486,7 +495,7 @@ class DietListener extends StackListener { |
void endNamedMixinApplication(Token beginToken, Token classKeyword, |
Token equals, Token implementsKeyword, Token endToken) { |
debugEvent("NamedMixinApplication"); |
- pop(); // Name. |
+ discard(2); // Name and metadata. |
checkEmpty(beginToken.charOffset); |
} |
@@ -507,9 +516,15 @@ class DietListener extends StackListener { |
AsyncMarker getAsyncMarker(StackListener listener) => listener.pop(); |
- void parseFunctionBody(StackListener listener, Token token, MemberKind kind) { |
+ void parseFunctionBody( |
+ StackListener listener, Token token, Token metadata, MemberKind kind) { |
try { |
Parser parser = new Parser(listener); |
+ List metadataConstants; |
+ if (metadata != null) { |
+ parser.parseMetadataStar(metadata); |
+ metadataConstants = listener.pop(); |
+ } |
token = parser.parseFormalParametersOpt(token, kind); |
var formals = listener.pop(); |
listener.checkEmpty(token.charOffset); |
@@ -521,7 +536,7 @@ class DietListener extends StackListener { |
parser.parseFunctionBody(token, isExpression, allowAbstract); |
var body = listener.pop(); |
listener.checkEmpty(token.charOffset); |
- listener.finishFunction(formals, asyncModifier, body); |
+ listener.finishFunction(metadataConstants, formals, asyncModifier, body); |
} on InputError { |
rethrow; |
} catch (e, s) { |
@@ -529,12 +544,16 @@ class DietListener extends StackListener { |
} |
} |
- void parseFields(StackListener listener, Token token, bool isTopLevel) { |
+ void parseFields( |
+ StackListener listener, Token token, Token metadata, bool isTopLevel) { |
Parser parser = new Parser(listener); |
if (isTopLevel) { |
+ // There's a slight asymmetry between [parseTopLevelMember] and |
+ // [parseMember] because the former doesn't call `parseMetadataStar`. |
+ token = parser.parseMetadataStar(metadata ?? token); |
token = parser.parseTopLevelMember(token); |
} else { |
- token = parser.parseMember(token); |
+ token = parser.parseMember(metadata ?? token); |
} |
listener.checkEmpty(token.charOffset); |
} |