Files
sdk/docs/language/Dart.g
T
Erik Ernst 6e3a274c5f "Magic" implicit creation.
Description which is relevant as of January 2018:

The more aggressive approach where `const` is inserted whenever
possible (for instance creation expressions) and whenever required
(for composite literals), and `new` is inserted otherwise, is now
the agreed policy. This means that the remaining discussion is on
the specification of this policy, not the policy itself. This has
been true approximately since Dec 1st, 2017.

Here is a brief overview of the feature which is specified in the
document added by this CL:

The introduction of 'implicit creation' adjusts the grammar such
that instance creation expressions (such as `new C()`) can always
omit the keyword (`new` or `const`). The semantics is that these
expressions will still invoke the same constructor (which may
produce a fresh instance in case of a generative constructor, and
some object that may or may not be new in case of a factory),
as if `new` or `const` had been added implicitly. The choice of
whether to add `new` or `const` is made according to the policy
described above.

----------------------------------------------------------------------
Original description, FYI:

Copy of Rietveld 3012703002: magic optional const

Adjusted informal spec optional-new to insert `const` whenever possible

The current version of optional-new.md specifies that `const` should be
inserted into certain syntactic phrases (when specific identifiers
satisfy some constraints), but only when these phrases occur in a const
context.

This CL changes that approach and specifies that `const` should also be
inserted outside const contexts, if the resulting expression is a
correct constant expression.

We haven't yet decided on whether we want the current (predictable)
model or we want the more "magic" one specified in this CL; this CL
is intended to be landed if we choose the latter, and discarded if we
choose the former.

Change-Id: I602e7eaf3d4c7904277af45c6f62089c77bd5117
Reviewed-on: https://dart-review.googlesource.com/3160
Reviewed-by: Leaf Petersen <leafp@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
2018-02-12 09:03:00 +00:00

1761 lines
39 KiB
Plaintext

// 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.
// *** This grammar is under development and it contains known bugs. ***
//
// CHANGES:
//
// v0.2 Changed top level variable declarations to avoid redundant and
// misleading occurrence of (FINAL|CONST).
//
// v0.1 First version available in the SDK github repository. Covers the
// Dart language as specified in the language specification based on the
// many grammar rule snippets. That grammar was then adjusted to remove
// known issues (e.g., misplaced metadata) and to resolve ambiguities.
grammar Dart;
@parser::header{
import java.util.Stack;
}
@lexer::header{
import java.util.Stack;
}
@parser::members {
static String filePath = null;
static boolean errorHasOccurred = false;
/// Must be invoked before the first error is reported for a library.
/// Will print the name of the library and indicate that it has errors.
static void prepareForErrors() {
errorHasOccurred = true;
System.err.println("Syntax error in " + filePath + ":");
}
/// Parse library, return true if success, false if errors occurred.
public boolean parseLibrary(String filePath) throws RecognitionException {
this.filePath = filePath;
errorHasOccurred = false;
libraryDefinition();
return !errorHasOccurred;
}
/// Produce grammar debugging friendly output, as described in 'The
/// Definitive ANTLR Reference', p247.
public String getErrorMessage(RecognitionException e, String[] tokenNames) {
List stack = getRuleInvocationStack(e, this.getClass().getName());
String msg = null;
if (e instanceof NoViableAltException) {
NoViableAltException nvae = (NoViableAltException)e;
msg = "no viable alt; token=" + e.token +
" (decision=" + nvae.decisionNumber +
" state " + nvae.stateNumber + ")" +
" decision=<<" + nvae.grammarDecisionDescription + ">>";
}
else {
msg = super.getErrorMessage(e, tokenNames);
}
if (!errorHasOccurred) prepareForErrors();
return stack + " " + msg;
}
public String getTokenErrorDisplay(Token t) {
return t.toString();
}
// Enable the parser to treat ASYNC/AWAIT/YIELD as keywords in the body of an
// `async`, `async*`, or `sync*` function. Access via methods below.
private Stack<Boolean> asyncEtcAreKeywords = new Stack<Boolean>();
{ asyncEtcAreKeywords.push(false); }
// Use this to indicate that we are now entering an `async`, `async*`,
// or `sync*` function.
void startAsyncFunction() { asyncEtcAreKeywords.push(true); }
// Use this to indicate that we are now entering a function which is
// neither `async`, `async*`, nor `sync*`.
void startNonAsyncFunction() { asyncEtcAreKeywords.push(false); }
// Use this to indicate that we are now leaving any funciton.
void endFunction() { asyncEtcAreKeywords.pop(); }
// Whether we can recognize ASYNC/AWAIT/YIELD as an identifier/typeIdentifier.
boolean asyncEtcPredicate(int tokenId) {
if (tokenId == ASYNC || tokenId == AWAIT || tokenId == YIELD) {
return !asyncEtcAreKeywords.peek();
}
return false;
}
// Debugging support methods.
void dp(int indent, String method, String sep) {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
}
System.out.println(method + sep + " " + input.LT(1) + " " + state.failed);
}
void dpBegin(int indent, String method) { dp(indent, method, ":"); }
void dpEnd(int indent, String method) { dp(indent, method, " END:"); }
void dpCall(int indent, String method) { dp(indent, method, "?"); }
void dpCalled(int indent, String method) { dp(indent, method, ".."); }
void dpResult(int indent, String method) { dp(indent, method, "!"); }
}
@lexer::members{
public static final int BRACE_NORMAL = 1;
public static final int BRACE_SINGLE = 2;
public static final int BRACE_DOUBLE = 3;
public static final int BRACE_THREE_SINGLE = 4;
public static final int BRACE_THREE_DOUBLE = 5;
/// This override ensures that lexer errors are recognized as errors,
/// but does not change the format of the reported error.
public String getErrorMessage(RecognitionException e, String[] tokenNames) {
if (!DartParser.errorHasOccurred) DartParser.prepareForErrors();
return super.getErrorMessage(e, tokenNames);
}
// Enable the parser to handle string interpolations via brace matching.
// The top of the `braceLevels` stack describes the most recent unmatched
// '{'. This is needed in order to enable/disable certain lexer rules.
//
// NORMAL: Most recent unmatched '{' was not string literal related.
// SINGLE: Most recent unmatched '{' was `'...${`.
// DOUBLE: Most recent unmatched '{' was `"...${`.
// THREE_SINGLE: Most recent unmatched '{' was `'''...${`.
// THREE_DOUBLE: Most recent unmatched '{' was `"""...${`.
//
// Access via functions below.
private Stack<Integer> braceLevels = new Stack<Integer>();
// Whether we are currently in a string literal context, and which one.
boolean currentBraceLevel(int braceLevel) {
if (braceLevels.empty()) return false;
return braceLevels.peek() == braceLevel;
}
// Use this to indicate that we are now entering a specific '{...}'.
// Call it after accepting the '{'.
void enterBrace() {
braceLevels.push(BRACE_NORMAL);
}
void enterBraceSingleQuote() {
braceLevels.push(BRACE_SINGLE);
}
void enterBraceDoubleQuote() {
braceLevels.push(BRACE_DOUBLE);
}
void enterBraceThreeSingleQuotes() {
braceLevels.push(BRACE_THREE_SINGLE);
}
void enterBraceThreeDoubleQuotes() {
braceLevels.push(BRACE_THREE_DOUBLE);
}
// Use this to indicate that we are now exiting a specific '{...}',
// no matter which kind. Call it before accepting the '}'.
void exitBrace() {
// We might raise a parse error here if the stack is empty, but the
// parsing rules should ensure that we get a parse error anyway, and
// it is not a big problem for the spec parser even if it misinterprets
// the brace structure of some programs with syntax errors.
if (!braceLevels.empty()) braceLevels.pop();
}
}
// ---------------------------------------- Grammar rules.
libraryDefinition
: FEFF? SCRIPT_TAG?
((metadata LIBRARY) => libraryName)?
((metadata (IMPORT | EXPORT)) => importOrExport)*
((metadata PART) => partDirective)*
(metadata topLevelDefinition)*
EOF
;
topLevelDefinition
: classDefinition
| enumType
| (TYPEDEF typeIdentifier typeParameters? '=') => typeAlias
| (TYPEDEF functionPrefix ('<' | '(')) => typeAlias
| (EXTERNAL functionSignature ';') => EXTERNAL functionSignature ';'
| (EXTERNAL getterSignature) => EXTERNAL getterSignature ';'
| (EXTERNAL type? SET identifier '(') =>
EXTERNAL setterSignature ';'
| (getterSignature functionBodyPrefix) => getterSignature functionBody
| (type? SET identifier '(') => setterSignature functionBody
| (type? identifierNotFUNCTION typeParameters? '(') =>
functionSignature functionBody
| (FINAL | CONST) type? staticFinalDeclarationList ';'
| topLevelVariableDeclaration ';'
;
topLevelVariableDeclaration
: varOrType identifier ('=' expression)? (',' initializedIdentifier)*
;
declaredIdentifier
: COVARIANT? finalConstVarOrType identifier
;
finalConstVarOrType
: FINAL type?
| CONST type?
| varOrType
;
varOrType
: VAR
| type
;
initializedIdentifier
: identifier ('=' expression)?
;
initializedIdentifierList
: initializedIdentifier (',' initializedIdentifier)*
;
functionSignature
: type? identifierNotFUNCTION formalParameterPart
;
functionBodyPrefix
: ASYNC? '=>'
| (ASYNC | ASYNC '*' | SYNC '*')? LBRACE
;
functionBody
: '=>' { startNonAsyncFunction(); } expression { endFunction(); } ';'
| { startNonAsyncFunction(); } block { endFunction(); }
| ASYNC '=>'
{ startAsyncFunction(); } expression { endFunction(); } ';'
| (ASYNC | ASYNC '*' | SYNC '*')
{ startAsyncFunction(); } block { endFunction(); }
;
block
: LBRACE statements RBRACE
;
formalParameterPart
: typeParameters? formalParameterList
;
formalParameterList
: '(' ')'
| '(' normalFormalParameters (','? | ',' optionalFormalParameters) ')'
| '(' optionalFormalParameters ')'
;
normalFormalParameters
: normalFormalParameter (',' normalFormalParameter)*
;
optionalFormalParameters
: optionalPositionalFormalParameters
| namedFormalParameters
;
optionalPositionalFormalParameters
: '[' defaultFormalParameter (',' defaultFormalParameter)* ','? ']'
;
namedFormalParameters
: LBRACE defaultNamedParameter (',' defaultNamedParameter)* ','? RBRACE
;
normalFormalParameter
: metadata normalFormalParameterNoMetadata
;
normalFormalParameterNoMetadata
: (COVARIANT? type? identifierNotFUNCTION formalParameterPart) =>
functionFormalParameter
| (finalConstVarOrType? THIS) => fieldFormalParameter
| simpleFormalParameter
;
// NB: It is an anomaly that a functionFormalParameter cannot be FINAL.
functionFormalParameter
: COVARIANT? type? identifierNotFUNCTION formalParameterPart
;
simpleFormalParameter
: declaredIdentifier
| COVARIANT? identifier
;
// NB: It is an anomaly that VAR can be a return type (`var this.x()`).
fieldFormalParameter
: finalConstVarOrType? THIS '.' identifier formalParameterPart?
;
defaultFormalParameter
: normalFormalParameter ('=' expression)?
;
defaultNamedParameter
: normalFormalParameter ((':' | '=') expression)?
;
typeApplication
: typeIdentifier typeParameters?
;
classDefinition
: (ABSTRACT? CLASS typeApplication (EXTENDS|IMPLEMENTS|LBRACE)) =>
ABSTRACT? CLASS typeApplication (superclass mixins?)? interfaces?
LBRACE (metadata classMemberDefinition)* RBRACE
| (ABSTRACT? CLASS typeApplication '=') =>
ABSTRACT? CLASS mixinApplicationClass
;
mixins
: WITH typeNotVoidNotFunctionList
;
classMemberDefinition
: (methodSignature functionBodyPrefix) => methodSignature functionBody
| declaration ';'
;
methodSignature
: (constructorSignature ':') => constructorSignature initializers
| (FACTORY constructorName '(') => factoryConstructorSignature
| (STATIC? type? identifierNotFUNCTION typeParameters? '(') =>
STATIC? functionSignature
| (STATIC? type? GET) => STATIC? getterSignature
| (STATIC? type? SET) => STATIC? setterSignature
| (type? OPERATOR operator '(') => operatorSignature
| constructorSignature
;
// https://github.com/dart-lang/sdk/issues/29501 reports on the problem which
// was solved by adding a case for redirectingFactoryConstructorSignature.
// TODO(eernst): Close that issue when this is integrated into the spec.
// https://github.com/dart-lang/sdk/issues/29502 reports on the problem that
// than external const factory constructor declaration cannot be derived by
// the spec grammar (and also not by this grammar). The following fixes were
// introduced for that: Added the 'factoryConstructorSignature' case below in
// 'declaration'; also added 'CONST?' in the 'factoryConstructorSignature'
// rule, such that const factories in general are allowed.
// TODO(eernst): Close that issue when this is integrated into the spec.
// TODO(eernst): Note that `EXTERNAL? STATIC? functionSignature` includes
// `STATIC functionSignature`, but a static function cannot be abstract.
// We might want to make that a syntax error rather than a static semantic
// check.
declaration
: (EXTERNAL CONST? FACTORY constructorName '(') =>
EXTERNAL factoryConstructorSignature
| (EXTERNAL CONST constructorName '(') =>
EXTERNAL constantConstructorSignature
| (EXTERNAL constructorName '(') => EXTERNAL constructorSignature
| ((EXTERNAL STATIC?)? type? GET identifier) =>
(EXTERNAL STATIC?)? getterSignature
| ((EXTERNAL STATIC?)? type? SET identifier) =>
(EXTERNAL STATIC?)? setterSignature
| (EXTERNAL? type? OPERATOR) => EXTERNAL? operatorSignature
| (STATIC (FINAL | CONST)) =>
STATIC (FINAL | CONST) type? staticFinalDeclarationList
| FINAL type? initializedIdentifierList
| ((STATIC | COVARIANT)? (VAR | type) identifier ('=' | ',' | ';')) =>
(STATIC | COVARIANT)? (VAR | type) initializedIdentifierList
| (EXTERNAL? STATIC? functionSignature ';') =>
EXTERNAL? STATIC? functionSignature
| (CONST? FACTORY constructorName formalParameterList '=') =>
redirectingFactoryConstructorSignature
| constantConstructorSignature (redirection | initializers)?
| constructorSignature (redirection | initializers)?
;
staticFinalDeclarationList
: staticFinalDeclaration (',' staticFinalDeclaration)*
;
staticFinalDeclaration
: identifier '=' expression
;
operatorSignature
: type? OPERATOR operator formalParameterList
;
operator
: '~'
| binaryOperator
| '[' ']'
| '[' ']' '='
;
binaryOperator
: multiplicativeOperator
| additiveOperator
| (shiftOperator) => shiftOperator
| relationalOperator
| '=='
| bitwiseOperator
;
getterSignature
: type? GET identifier
;
setterSignature
: type? SET identifier formalParameterList
;
constructorSignature
: constructorName formalParameterList
;
constructorName
: typeIdentifier ('.' identifier)?
;
redirection
: ':' THIS ('.' identifier)? arguments
;
initializers
: ':' superCallOrFieldInitializer (',' superCallOrFieldInitializer)*
;
superCallOrFieldInitializer
: SUPER arguments
| SUPER '.' identifier arguments
| fieldInitializer
| assertClause
;
fieldInitializer
: (THIS '.')? identifier '=' conditionalExpression cascadeSection*
;
factoryConstructorSignature
: CONST? FACTORY constructorName formalParameterList
;
redirectingFactoryConstructorSignature
: CONST? FACTORY constructorName formalParameterList '='
constructorDesignation
;
constantConstructorSignature
: CONST constructorName formalParameterList
;
superclass
: EXTENDS typeNotVoidNotFunction
;
interfaces
: IMPLEMENTS typeNotVoidNotFunctionList
;
mixinApplicationClass
: typeApplication '=' mixinApplication ';'
;
mixinApplication
: typeNotVoidNotFunction mixins interfaces?
;
enumType
: ENUM typeIdentifier LBRACE identifier (',' identifier)* (',')? RBRACE
;
typeParameter
: metadata typeIdentifier (EXTENDS typeNotVoid)?
;
typeParameters
: '<' typeParameter (',' typeParameter)* '>'
;
metadata
: ('@' metadatum)*
;
metadatum
: constructorDesignation arguments
| qualified
;
expression
: (formalParameterPart functionExpressionBodyPrefix) =>
functionExpression
| throwExpression
| (assignableExpression assignmentOperator) =>
assignableExpression assignmentOperator expression
| conditionalExpression cascadeSection*
;
expressionWithoutCascade
: (formalParameterPart functionExpressionBodyPrefix) =>
functionExpressionWithoutCascade
| throwExpressionWithoutCascade
| (assignableExpression assignmentOperator) =>
assignableExpression assignmentOperator expressionWithoutCascade
| conditionalExpression
;
expressionList
: expression (',' expression)*
;
primary
: thisExpression
| SUPER unconditionalAssignableSelector
| (CONST constructorDesignation) => constObjectExpression
| newExpression
| (formalParameterPart functionPrimaryBodyPrefix) => functionPrimary
| '(' expression ')'
| literal
| identifier
;
literal
: nullLiteral
| booleanLiteral
| numericLiteral
| stringLiteral
| symbolLiteral
| (CONST? typeArguments? LBRACE) => mapLiteral
| listLiteral
;
nullLiteral
: NULL
;
numericLiteral
: NUMBER
| HEX_NUMBER
;
booleanLiteral
: TRUE
| FALSE
;
stringLiteral
: (multiLineString | singleLineString)+
;
stringLiteralWithoutInterpolation
: singleLineStringWithoutInterpolation+
;
listLiteral
: CONST? typeArguments? '[' (expressionList ','?)? ']'
;
mapLiteral
: CONST? typeArguments?
LBRACE (mapLiteralEntry (',' mapLiteralEntry)* ','?)? RBRACE
;
mapLiteralEntry
: expression ':' expression
;
throwExpression
: THROW expression
;
throwExpressionWithoutCascade
: THROW expressionWithoutCascade
;
functionExpression
: formalParameterPart functionExpressionBody
;
functionExpressionBody
: '=>' { startNonAsyncFunction(); } expression { endFunction(); }
| ASYNC '=>' { startAsyncFunction(); } expression { endFunction(); }
;
functionExpressionBodyPrefix
: ASYNC? '=>'
;
functionExpressionWithoutCascade
: formalParameterPart functionExpressionWithoutCascadeBody
;
functionExpressionWithoutCascadeBody
: '=>' { startNonAsyncFunction(); }
expressionWithoutCascade { endFunction(); }
| ASYNC '=>' { startAsyncFunction(); }
expressionWithoutCascade { endFunction(); }
;
functionPrimary
: formalParameterPart functionPrimaryBody
;
functionPrimaryBody
: { startNonAsyncFunction(); } block { endFunction(); }
| (ASYNC | ASYNC '*' | SYNC '*')
{ startAsyncFunction(); } block { endFunction(); }
;
functionPrimaryBodyPrefix
: (ASYNC | ASYNC '*' | SYNC '*')? LBRACE
;
thisExpression
: THIS
;
newExpression
: NEW constructorDesignation arguments
;
constObjectExpression
: CONST constructorDesignation arguments
;
arguments
: '(' (argumentList ','?)? ')'
;
argumentList
: namedArgument (',' namedArgument)*
| expressionList (',' namedArgument)*
;
namedArgument
: label expression
;
cascadeSection
: '..'
(cascadeSelector argumentPart*)
(assignableSelector argumentPart*)*
(assignmentOperator expressionWithoutCascade)?
;
cascadeSelector
: '[' expression ']'
| identifier
;
assignmentOperator
: '='
| compoundAssignmentOperator
;
compoundAssignmentOperator
: '*='
| '/='
| '~/='
| '%='
| '+='
| '-='
| '<<='
| '>' '>' '='
| '&='
| '^='
| '|='
| '??='
;
conditionalExpression
: ifNullExpression
('?' expressionWithoutCascade ':' expressionWithoutCascade)?
;
ifNullExpression
: logicalOrExpression ('??' logicalOrExpression)*
;
logicalOrExpression
: logicalAndExpression ('||' logicalAndExpression)*
;
logicalAndExpression
: equalityExpression ('&&' equalityExpression)*
;
equalityExpression
: relationalExpression (equalityOperator relationalExpression)?
| SUPER equalityOperator relationalExpression
;
equalityOperator
: '=='
| '!='
;
relationalExpression
: bitwiseOrExpression
(typeTest | typeCast | relationalOperator bitwiseOrExpression)?
| SUPER relationalOperator bitwiseOrExpression
;
relationalOperator
: '>' '='
| '>'
| '<='
| '<'
;
bitwiseOrExpression
: bitwiseXorExpression ('|' bitwiseXorExpression)*
| SUPER ('|' bitwiseXorExpression)+
;
bitwiseXorExpression
: bitwiseAndExpression ('^' bitwiseAndExpression)*
| SUPER ('^' bitwiseAndExpression)+
;
bitwiseAndExpression
: shiftExpression ('&' shiftExpression)*
| SUPER ('&' shiftExpression)+
;
bitwiseOperator
: '&'
| '^'
| '|'
;
shiftExpression
: additiveExpression (shiftOperator additiveExpression)*
| SUPER (shiftOperator additiveExpression)+
;
shiftOperator
: '<<'
| '>' '>'
;
additiveExpression
: multiplicativeExpression (additiveOperator multiplicativeExpression)*
| SUPER (additiveOperator multiplicativeExpression)+
;
additiveOperator
: '+'
| '-'
;
multiplicativeExpression
: unaryExpression (multiplicativeOperator unaryExpression)*
| SUPER (multiplicativeOperator unaryExpression)+
;
multiplicativeOperator
: '*'
| '/'
| '%'
| '~/'
;
unaryExpression
: (prefixOperator ~SUPER) => prefixOperator unaryExpression
| (awaitExpression) => awaitExpression
| postfixExpression
| (minusOperator | tildeOperator) SUPER
| incrementOperator assignableExpression
;
prefixOperator
: minusOperator
| negationOperator
| tildeOperator
;
minusOperator
: '-'
;
negationOperator
: '!'
;
tildeOperator
: '~'
;
awaitExpression
: AWAIT unaryExpression
;
// The `(selector)` predicate ensures that the parser commits to the longest
// possible chain of selectors, e.g., `a<b,c>(d)` as a call rather than as a
// sequence of two relational expressions.
postfixExpression
: (assignableExpression postfixOperator) =>
assignableExpression postfixOperator
| (typeName typeArguments '.') =>
constructorInvocation ((selector) => selector)*
| primary ((selector) => selector)*
;
constructorInvocation
: typeName typeArguments '.' identifier arguments
;
postfixOperator
: incrementOperator
;
selector
: assignableSelector
| argumentPart
;
argumentPart
: typeArguments? arguments
;
incrementOperator
: '++'
| '--'
;
// The `(assignableSelectorPart)` predicate ensures that the parser
// commits to the longest possible chain, e.g., `a<b,c>(d).e` as one rather
// than two expressions. The first `identifier` alternative handles all
// the simple cases; the final `identifier` alternative at the end catches
// the case where we have `identifier '<'` and the '<' is used as a
// relationalOperator, not the beginning of typeArguments.
assignableExpression
: (SUPER unconditionalAssignableSelector
~('<' | '(' | '[' | '.' | '?.')) =>
SUPER unconditionalAssignableSelector
| (typeName typeArguments '.' identifier '(') =>
constructorInvocation
((assignableSelectorPart) => assignableSelectorPart)+
| (identifier ~('<' | '(' | '[' | '.' | '?.')) => identifier
| (primary assignableSelectorPart) =>
primary ((assignableSelectorPart) => assignableSelectorPart)+
| identifier
;
assignableSelectorPart
: argumentPart* assignableSelector
;
unconditionalAssignableSelector
: '[' expression ']'
| '.' identifier
;
assignableSelector
: unconditionalAssignableSelector
| '?.' identifier
;
identifierNotFUNCTION
: IDENTIFIER
| ABSTRACT // Built-in identifier.
| AS // Built-in identifier.
| COVARIANT // Built-in identifier.
| DEFERRED // Built-in identifier.
| DYNAMIC // Built-in identifier.
| EXPORT // Built-in identifier.
| EXTERNAL // Built-in identifier.
| FACTORY // Built-in identifier.
| GET // Built-in identifier.
| IMPLEMENTS // Built-in identifier.
| IMPORT // Built-in identifier.
| LIBRARY // Built-in identifier.
| OPERATOR // Built-in identifier.
| PART // Built-in identifier.
| SET // Built-in identifier.
| STATIC // Built-in identifier.
| TYPEDEF // Built-in identifier.
| HIDE // Not a built-in identifier.
| OF // Not a built-in identifier.
| ON // Not a built-in identifier.
| SHOW // Not a built-in identifier.
| SYNC // Not a built-in identifier.
| { asyncEtcPredicate(input.LA(1)) }? (ASYNC|AWAIT|YIELD)
;
identifier
: identifierNotFUNCTION
| FUNCTION // Built-in identifier that can be used as a type.
;
qualified
: typeIdentifier
| typeIdentifier '.' identifier
| typeIdentifier '.' typeIdentifier '.' identifier
;
typeIdentifier
: IDENTIFIER
| DYNAMIC // Built-in identifier that can be used as a type.
| HIDE // Not a built-in identifier.
| OF // Not a built-in identifier.
| ON // Not a built-in identifier.
| SHOW // Not a built-in identifier.
| SYNC // Not a built-in identifier.
| { asyncEtcPredicate(input.LA(1)) }? (ASYNC|AWAIT|YIELD)
;
typeTest
: isOperator typeNotVoid
;
isOperator
: IS '!'?
;
typeCast
: asOperator typeNotVoid
;
asOperator
: AS
;
statements
: statement*
;
statement
: label* nonLabelledStatement
;
// Exception in the language specification: An expressionStatement cannot
// start with LBRACE. We force anything that starts with LBRACE to be a block,
// which will prevent an expressionStatement from starting with LBRACE, and
// which will not interfere with the recognition of any other case. If we
// add another statement which can start with LBRACE we must adjust this
// check.
nonLabelledStatement
: (LBRACE) => block
| (metadata declaredIdentifier ('='|','|';')) =>
localVariableDeclaration
| (AWAIT? FOR) => forStatement
| whileStatement
| doStatement
| switchStatement
| ifStatement
| rethrowStatement
| tryStatement
| breakStatement
| continueStatement
| returnStatement
| (metadata functionSignature functionBodyPrefix) =>
localFunctionDeclaration
| assertStatement
| (YIELD ~'*') => yieldStatement
| yieldEachStatement
| expressionStatement
;
expressionStatement
: expression? ';'
;
localVariableDeclaration
: metadata initializedVariableDeclaration ';'
;
initializedVariableDeclaration
: declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
;
localFunctionDeclaration
: metadata functionSignature functionBody
;
ifStatement
: IF '(' expression ')' statement ((ELSE) => ELSE statement | ())
;
forStatement
: AWAIT? FOR '(' forLoopParts ')' statement
;
forLoopParts
: (metadata declaredIdentifier IN) =>
metadata declaredIdentifier IN expression
| (metadata identifier IN) => metadata identifier IN expression
| forInitializerStatement expression? ';' expressionList?
;
// The localVariableDeclaration cannot be CONST, but that can
// be enforced in a later phase, and the grammar allows it.
forInitializerStatement
: (localVariableDeclaration) => localVariableDeclaration
| expression? ';'
;
whileStatement
: WHILE '(' expression ')' statement
;
doStatement
: DO statement WHILE '(' expression ')' ';'
;
switchStatement
: SWITCH '(' expression ')' LBRACE switchCase* defaultCase? RBRACE
;
switchCase
: label* CASE expression ':' statements
;
defaultCase
: label* DEFAULT ':' statements
;
rethrowStatement
: RETHROW ';'
;
tryStatement
: TRY block (onParts finallyPart? | finallyPart)
;
onPart
: catchPart block
| ON typeNotVoid catchPart? block
;
onParts
: (onPart (ON|CATCH)) => onPart onParts
| onPart
;
catchPart
: CATCH '(' identifier (',' identifier)? ')'
;
finallyPart
: FINALLY block
;
returnStatement
: RETURN expression? ';'
;
label
: identifier ':'
;
breakStatement
: BREAK identifier? ';'
;
continueStatement
: CONTINUE identifier? ';'
;
yieldStatement
: YIELD expression ';'
;
yieldEachStatement
: YIELD '*' expression ';'
;
assertStatement
: assertClause ';'
;
assertClause
: ASSERT '(' expression (',' expression)? ','? ')'
;
libraryName
: metadata LIBRARY identifier ('.' identifier)* ';'
;
importOrExport
: (metadata IMPORT) => libraryImport
| (metadata EXPORT) => libraryExport
;
libraryImport
: metadata importSpecification
;
importSpecification
: IMPORT uri (AS identifier)? combinator* ';'
| IMPORT uri DEFERRED AS identifier combinator* ';'
;
combinator
: SHOW identifierList
| HIDE identifierList
;
identifierList
: identifier (',' identifier)*
;
libraryExport
: metadata EXPORT uri combinator* ';'
;
partDirective
: metadata PART uri ';'
;
partHeader
: metadata PART OF identifier ('.' identifier)* ';'
;
partDeclaration
: partHeader topLevelDefinition* EOF
;
uri
: stringLiteralWithoutInterpolation
;
type
: (FUNCTION ('('|'<')) => functionTypeTails
| (typeNotFunction FUNCTION ('('|'<')) =>
typeNotFunction functionTypeTails
| typeNotFunction
;
typeNotFunction
: typeNotVoidNotFunction
| VOID
;
typeNotVoid
: (typeNotFunction? FUNCTION ('('|'<')) => functionType
| typeNotVoidNotFunction
;
typeNotVoidNotFunction
: typeName typeArguments?
| FUNCTION
;
typeName
: typeIdentifier ('.' typeIdentifier)?
;
typeArguments
: '<' typeList '>'
;
typeList
: type (',' type)*
;
typeNotVoidNotFunctionList
: typeNotVoidNotFunction (',' typeNotVoidNotFunction)*
;
typeAlias
: (TYPEDEF typeIdentifier typeParameters? '=') =>
TYPEDEF typeIdentifier typeParameters? '=' functionType ';'
| TYPEDEF functionTypeAlias
;
functionTypeAlias
: functionPrefix formalParameterPart ';'
;
functionPrefix
: (type identifier) => type identifier
| identifier
;
functionTypeTail
: FUNCTION typeParameters? parameterTypeList
;
functionTypeTails
: (functionTypeTail FUNCTION ('<'|'(')) =>
functionTypeTail functionTypeTails
| functionTypeTail
;
functionType
: (FUNCTION ('<'|'(')) => functionTypeTails
| typeNotFunction functionTypeTails
;
parameterTypeList
: ('(' ')') => '(' ')'
| ('(' normalParameterTypes ',' ('['|'{')) =>
'(' normalParameterTypes ',' optionalParameterTypes ')'
| ('(' normalParameterTypes ','? ')') =>
'(' normalParameterTypes ','? ')'
| '(' optionalParameterTypes ')'
;
normalParameterTypes
: normalParameterType (',' normalParameterType)*
;
normalParameterType
: (typedIdentifier) => typedIdentifier
| type
;
optionalParameterTypes
: optionalPositionalParameterTypes
| namedParameterTypes
;
optionalPositionalParameterTypes
: '[' normalParameterTypes ','? ']'
;
namedParameterTypes
: LBRACE typedIdentifier (',' typedIdentifier)* ','? RBRACE
;
typedIdentifier
: type identifier
;
constructorDesignation
: qualified
| typeName typeArguments ('.' identifier)?
;
// Predicate: Force resolution as composite symbolLiteral as far as possible.
symbolLiteral
: '#' (operator | (identifier (('.' identifier) => '.' identifier)*))
;
singleLineStringWithoutInterpolation
: RAW_SINGLE_LINE_STRING
| SINGLE_LINE_STRING_DQ_BEGIN_END
| SINGLE_LINE_STRING_SQ_BEGIN_END
;
singleLineString
: RAW_SINGLE_LINE_STRING
| SINGLE_LINE_STRING_SQ_BEGIN_END
| SINGLE_LINE_STRING_SQ_BEGIN_MID expression
(SINGLE_LINE_STRING_SQ_MID_MID expression)*
SINGLE_LINE_STRING_SQ_MID_END
| SINGLE_LINE_STRING_DQ_BEGIN_END
| SINGLE_LINE_STRING_DQ_BEGIN_MID expression
(SINGLE_LINE_STRING_DQ_MID_MID expression)*
SINGLE_LINE_STRING_DQ_MID_END
;
multiLineString
: RAW_MULTI_LINE_STRING
| MULTI_LINE_STRING_SQ_BEGIN_END
| MULTI_LINE_STRING_SQ_BEGIN_MID expression
(MULTI_LINE_STRING_SQ_MID_MID expression)*
MULTI_LINE_STRING_SQ_MID_END
| MULTI_LINE_STRING_DQ_BEGIN_END
| MULTI_LINE_STRING_DQ_BEGIN_MID expression
(MULTI_LINE_STRING_DQ_MID_MID expression)*
MULTI_LINE_STRING_DQ_MID_END
;
// ---------------------------------------- Lexer rules.
fragment
LETTER
: 'a' .. 'z'
| 'A' .. 'Z'
;
fragment
DIGIT
: '0' .. '9'
;
fragment
EXPONENT
: ('e' | 'E') ('+' | '-')? DIGIT+
;
fragment
HEX_DIGIT
: ('a' | 'b' | 'c' | 'd' | 'e' | 'f')
| ('A' | 'B' | 'C' | 'D' | 'E' | 'F')
| DIGIT
;
FINAL
: 'final'
;
CONST
: 'const'
;
VAR
: 'var'
;
VOID
: 'void'
;
ASYNC
: 'async'
;
THIS
: 'this'
;
ABSTRACT
: 'abstract'
;
AS
: 'as'
;
SYNC
: 'sync'
;
CLASS
: 'class'
;
WITH
: 'with'
;
STATIC
: 'static'
;
DYNAMIC
: 'dynamic'
;
EXTERNAL
: 'external'
;
GET
: 'get'
;
SET
: 'set'
;
OPERATOR
: 'operator'
;
SUPER
: 'super'
;
FACTORY
: 'factory'
;
EXTENDS
: 'extends'
;
IMPLEMENTS
: 'implements'
;
ENUM
: 'enum'
;
NULL
: 'null'
;
TRUE
: 'true'
;
FALSE
: 'false'
;
THROW
: 'throw'
;
NEW
: 'new'
;
AWAIT
: 'await'
;
DEFERRED
: 'deferred'
;
EXPORT
: 'export'
;
IMPORT
: 'import'
;
LIBRARY
: 'library'
;
PART
: 'part'
;
TYPEDEF
: 'typedef'
;
IS
: 'is'
;
IF
: 'if'
;
ELSE
: 'else'
;
WHILE
: 'while'
;
FOR
: 'for'
;
IN
: 'in'
;
DO
: 'do'
;
SWITCH
: 'switch'
;
CASE
: 'case'
;
DEFAULT
: 'default'
;
RETHROW
: 'rethrow'
;
TRY
: 'try'
;
ON
: 'on'
;
CATCH
: 'catch'
;
FINALLY
: 'finally'
;
RETURN
: 'return'
;
BREAK
: 'break'
;
CONTINUE
: 'continue'
;
YIELD
: 'yield'
;
SHOW
: 'show'
;
HIDE
: 'hide'
;
OF
: 'of'
;
ASSERT
: 'assert'
;
COVARIANT
: 'covariant'
;
FUNCTION
: 'Function'
;
NUMBER
: (DIGIT+ '.' DIGIT) => DIGIT+ '.' DIGIT+ EXPONENT?
| DIGIT+ EXPONENT?
| '.' DIGIT+ EXPONENT?
;
HEX_NUMBER
: '0x' HEX_DIGIT+
| '0X' HEX_DIGIT+
;
RAW_SINGLE_LINE_STRING
: 'r' '\'' (~('\'' | '\r' | '\n'))* '\''
| 'r' '"' (~('"' | '\r' | '\n'))* '"'
;
RAW_MULTI_LINE_STRING
: 'r' '"""' (options {greedy=false;} : .)* '"""'
| 'r' '\'\'\'' (options {greedy=false;} : .)* '\'\'\''
;
fragment
SIMPLE_STRING_INTERPOLATION
: '$' IDENTIFIER_NO_DOLLAR
;
fragment
STRING_CONTENT_SQ
: ~('\\' | '\'' | '$' | '\r' | '\n')
| '\\' ~( '\r' | '\n')
| SIMPLE_STRING_INTERPOLATION
;
SINGLE_LINE_STRING_SQ_BEGIN_END
: '\'' STRING_CONTENT_SQ* '\''
;
SINGLE_LINE_STRING_SQ_BEGIN_MID
: '\'' STRING_CONTENT_SQ* '${' { enterBraceSingleQuote(); }
;
SINGLE_LINE_STRING_SQ_MID_MID
: { currentBraceLevel(BRACE_SINGLE) }? =>
('}' STRING_CONTENT_SQ* '${') =>
{ exitBrace(); } '}' STRING_CONTENT_SQ* '${'
{ enterBraceSingleQuote(); }
;
SINGLE_LINE_STRING_SQ_MID_END
: { currentBraceLevel(BRACE_SINGLE) }? =>
('}' STRING_CONTENT_SQ* '\'') =>
{ exitBrace(); } '}' STRING_CONTENT_SQ* '\''
;
fragment
STRING_CONTENT_DQ
: ~('\\' | '"' | '$' | '\r' | '\n')
| '\\' ~('\r' | '\n')
| SIMPLE_STRING_INTERPOLATION
;
SINGLE_LINE_STRING_DQ_BEGIN_END
: '"' STRING_CONTENT_DQ* '"'
;
SINGLE_LINE_STRING_DQ_BEGIN_MID
: '"' STRING_CONTENT_DQ* '${' { enterBraceDoubleQuote(); }
;
SINGLE_LINE_STRING_DQ_MID_MID
: { currentBraceLevel(BRACE_DOUBLE) }? =>
('}' STRING_CONTENT_DQ* '${') =>
{ exitBrace(); } '}' STRING_CONTENT_DQ* '${'
{ enterBraceDoubleQuote(); }
;
SINGLE_LINE_STRING_DQ_MID_END
: { currentBraceLevel(BRACE_DOUBLE) }? =>
('}' STRING_CONTENT_DQ* '"') =>
{ exitBrace(); } '}' STRING_CONTENT_DQ* '"'
;
fragment
QUOTES_SQ
:
| '\''
| '\'\''
;
// Read string contents, which may be almost anything, but stop when seeing
// '\'\'\'' and when seeing '${'. We do this by allowing all other
// possibilities including escapes, simple interpolation, and fewer than
// three '\''.
fragment
STRING_CONTENT_TSQ
: QUOTES_SQ
(~('\\' | '$' | '\'') | '\\' . | SIMPLE_STRING_INTERPOLATION)
;
MULTI_LINE_STRING_SQ_BEGIN_END
: '\'\'\'' STRING_CONTENT_TSQ* '\'\'\''
;
MULTI_LINE_STRING_SQ_BEGIN_MID
: '\'\'\'' STRING_CONTENT_TSQ* QUOTES_SQ '${'
{ enterBraceThreeSingleQuotes(); }
;
MULTI_LINE_STRING_SQ_MID_MID
: { currentBraceLevel(BRACE_THREE_SINGLE) }? =>
('}' STRING_CONTENT_TSQ* QUOTES_SQ '${') =>
{ exitBrace(); } '}' STRING_CONTENT_TSQ* QUOTES_SQ '${'
{ enterBraceThreeSingleQuotes(); }
;
MULTI_LINE_STRING_SQ_MID_END
: { currentBraceLevel(BRACE_THREE_SINGLE) }? =>
('}' STRING_CONTENT_TSQ* '\'\'\'') =>
{ exitBrace(); } '}' STRING_CONTENT_TSQ* '\'\'\''
;
fragment
QUOTES_DQ
:
| '"'
| '""'
;
// Read string contents, which may be almost anything, but stop when seeing
// '"""' and when seeing '${'. We do this by allowing all other possibilities
// including escapes, simple interpolation, and fewer-than-three '"'.
fragment
STRING_CONTENT_TDQ
: QUOTES_DQ
(~('\\' | '$' | '"') | '\\' . | SIMPLE_STRING_INTERPOLATION)
;
MULTI_LINE_STRING_DQ_BEGIN_END
: '"""' STRING_CONTENT_TDQ* '"""'
;
MULTI_LINE_STRING_DQ_BEGIN_MID
: '"""' STRING_CONTENT_TDQ* QUOTES_DQ '${'
{ enterBraceThreeDoubleQuotes(); }
;
MULTI_LINE_STRING_DQ_MID_MID
: { currentBraceLevel(BRACE_THREE_DOUBLE) }? =>
('}' STRING_CONTENT_TDQ* QUOTES_DQ '${') =>
{ exitBrace(); } '}' STRING_CONTENT_TDQ* QUOTES_DQ '${'
{ enterBraceThreeDoubleQuotes(); }
;
MULTI_LINE_STRING_DQ_MID_END
: { currentBraceLevel(BRACE_THREE_DOUBLE) }? =>
('}' STRING_CONTENT_TDQ* '"""') =>
{ exitBrace(); } '}' STRING_CONTENT_TDQ* '"""'
;
LBRACE
: '{' { enterBrace(); }
;
RBRACE
: { currentBraceLevel(BRACE_NORMAL) }? => ('}') => { exitBrace(); } '}'
;
fragment
IDENTIFIER_START_NO_DOLLAR
: LETTER
| '_'
;
fragment
IDENTIFIER_PART_NO_DOLLAR
: IDENTIFIER_START_NO_DOLLAR
| DIGIT
;
fragment
IDENTIFIER_NO_DOLLAR
: IDENTIFIER_START_NO_DOLLAR IDENTIFIER_PART_NO_DOLLAR*
;
fragment
IDENTIFIER_START
: IDENTIFIER_START_NO_DOLLAR
| '$'
;
fragment
IDENTIFIER_PART
: IDENTIFIER_START
| DIGIT
;
SCRIPT_TAG
: '#!' (~('\r' | '\n'))* NEWLINE
;
IDENTIFIER
: IDENTIFIER_START IDENTIFIER_PART*
;
SINGLE_LINE_COMMENT
: '//' (~('\r' | '\n'))* NEWLINE?
{ skip(); }
;
MULTI_LINE_COMMENT
: '/*' (options {greedy=false;} : (MULTI_LINE_COMMENT | .))* '*/'
{ skip(); }
;
fragment
NEWLINE
: ('\r' | '\n' | '\r\n')
;
FEFF
: '\uFEFF'
;
WS
: (' ' | '\t' | '\r' | '\n')+
{ skip(); }
;