16. Grammars
N4JS extends the ECMAScript 2015 language grammar and combines it with type expression.
These grammars are slightly simplified versions of the "real" Xtext grammars used in the implementation. These grammars are post-processed and combined with additional validators so not all constructs are necessarily available in N4JS. |
16.1. Type Expressions Grammar
EBNF Type Expression Grammar
TypeRef:
TypeRefWithoutModifiers =>undefModifier=UndefModifierToken?
| undefModifier=UndefModifierToken;
TypeRefWithoutModifiers:
((ParameterizedTypeRef | ThisTypeRef) => dynamic?='+'?)
| ConstructorTypeRef
| ClassifierTypeRef
| FunctionTypeExpression
| UnionTypeExpression
| IntersectionTypeExpression;
TypeRefFunctionTypeExpression:
ParameterizedTypeRef
| ConstructorTypeRef
| ClassifierTypeRef
| UnionTypeExpression
| IntersectionTypeExpression
;
TypeRefForCast:
ParameterizedTypeRef
| ThisTypeRef
| ConstructorTypeRef
| ClassifierTypeRef
| FunctionTypeExpression;
TypeRefInClassifierType:
ParameterizedTypeRefNominal
| ThisTypeRefNominal;
ThisTypeRef:
ThisTypeRefNominal | ThisTypeRefStructural;
ThisTypeRefNominal:
'this';
ThisTypeRefStructural:
definedTypingStrategy=TypingStrategyUseSiteOperator
'this'
('with' TStructMemberList)?;
FunctionTypeExpression:
'{'
('@' 'This' '(' declaredThisType=TypeRefFunctionTypeExpression ')')?
'function'
('<' ownedTypeVars+=TypeVariable (',' ownedTypeVars+=TypeVariable)* '>')?
'(' TAnonymousFormalParameterList ')'
(':' returnTypeRef=TypeRef)?
'}';
fragment TAnonymousFormalParameterList*:
(fpars+=TAnonymousFormalParameter (',' fpars+=TAnonymousFormalParameter)*)?
;
TAnonymousFormalParameter:
variadic?='...'? (=> name=TIdentifier ':')? typeRef=TypeRef
;
UnionTypeExpression:
'union' '{' typeRefs+=TypeRefWithoutModifiers (',' typeRefs+=TypeRefWithoutModifiers)* '}';
IntersectionTypeExpression:
'intersection' '{' typeRefs+=TypeRefWithoutModifiers (',' typeRefs+=TypeRefWithoutModifiers)* '}';
ParameterizedTypeRef:
ParameterizedTypeRefNominal | ParameterizedTypeRefStructural;
ParameterizedTypeRefStructural:
definedTypingStrategy=TypingStrategyUseSiteOperator
declaredType=[Type|TypeReferenceName]
(=>'<' typeArgs+=TypeArgument (',' typeArgs+=TypeArgument)* '>')?
('with' TStructMemberList)?;
fragment TStructMemberList*: '{' (astStructuralMembers+=TStructMember (';'|',')?)* '}';
TStructMember:
TStructGetter
| TStructSetter
| TStructMethod
| TStructField;
TStructMethod:
=>
(('<' typeVars+=TypeVariable (',' typeVars+=TypeVariable)* '>')?
name=TypesIdentifier '('
) TAnonymousFormalParameterList ')'
(':' returnTypeRef=TypeRef)?
;
TStructField:
name=TypesIdentifier (':' typeRef=TypeRef)?
;
TStructGetter:
=> ('get'
name=TypesIdentifier)
'(' ')' (':' declaredTypeRef=TypeRef)?
;
TStructSetter:
=> ('set'
name=TypesIdentifier)
'(' fpar=TAnonymousFormalParameter ')'
;
ParameterizedTypeRefNominal:
declaredType=[Type|TypeReferenceName]
(=> '<' typeArgs+=TypeArgument (',' typeArgs+=TypeArgument)* '>')?;
TypingStrategyUseSiteOperator:
'~' ('~' | STRUCTMODSUFFIX)?;
TypingStrategyDefSiteOperator:
'~';
terminal STRUCTMODSUFFIX:
('r' | 'i' | 'w') '~'
;
ConstructorTypeRef:
'constructor' '{' staticTypeRef=TypeRefInClassifierType '}';
ClassifierTypeRef:
'type' '{' staticTypeRef=TypeRefInClassifierType '}';
TypeReferenceName:
IDENTIFIER ('.' IDENTIFIER)*;
TypeArgument:
Wildcard | TypeRef;
Wildcard:
=> ('?') (('extends' declaredUpperBound=TypeRef) | ('super'
declaredLowerBound=TypeRef))?;
UndefModifierToken:
'?';
TypeVariable:
name=IDENTIFIER ('extends' declaredUpperBounds+=ParameterizedTypeRef ('&'
declaredUpperBounds+=ParameterizedTypeRef)*)?;
TypesIdentifier:
IDENTIFIER
| 'get' | 'set' | 'abstract' | 'project'
| 'union' | 'intersection'
| 'as' | 'from' | 'type' | 'void' | 'null';
TIdentifier:
TypesIdentifier
| 'implements' | 'interface'
| 'private' | 'protected' | 'public'
| 'static'
;
terminal IDENTIFIER:
IDENTIFIER_START IDENTIFIER_PART*;
terminal INT:
DECIMAL_INTEGER_LITERAL_FRAGMENT;
terminal ML_COMMENT:
ML_COMMENT_FRAGMENT;
terminal SL_COMMENT:
'//' (!LINE_TERMINATOR_FRAGMENT)*;
terminal EOL:
LINE_TERMINATOR_SEQUENCE_FRAGMENT;
terminal WS:
WHITESPACE_FRAGMENT+;
terminal fragment UNICODE_ESCAPE_FRAGMENT:
'\\' ('u' (
HEX_DIGIT (HEX_DIGIT (HEX_DIGIT HEX_DIGIT?)?)?
| '{' HEX_DIGIT* '}'?
)?)?;
terminal fragment IDENTIFIER_START:
UNICODE_LETTER_FRAGMENT
| '$'
| '_'
| UNICODE_ESCAPE_FRAGMENT;
terminal fragment IDENTIFIER_PART:
UNICODE_LETTER_FRAGMENT
| UNICODE_ESCAPE_FRAGMENT
| '$'
| UNICODE_COMBINING_MARK_FRAGMENT
| UNICODE_DIGIT_FRAGMENT
| UNICODE_CONNECTOR_PUNCTUATION_FRAGMENT
| ZWNJ
| ZWJ;
terminal DOT_DOT:
'..'
;
16.2. N4JS Language Grammar
Script: annotations+=ScriptAnnotation*
scriptElements+=ScriptElement*;
ScriptElement:
AnnotatedScriptElement
| N4ClassDeclaration<Yield=false>
| N4InterfaceDeclaration<Yield=false>
| N4EnumDeclaration<Yield=false>
| ImportDeclaration
| ExportDeclaration
| RootStatement<Yield=false>
;
AnnotatedScriptElement:
AnnotationList (
{ExportDeclaration.annotationList=current} ExportDeclarationImpl
| {ImportDeclaration.annotationList=current} ImportDeclarationImpl
| {FunctionDeclaration.annotationList=current}
=>((declaredModifiers+=N4Modifier)* AsyncNoTrailingLineBreak
->FunctionImpl<Yield=false,YieldIfGenerator=false,Expression=false>)
| (
(
{N4ClassDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)*
'class' typingStrategy=TypingStrategyDefSiteOperator?
name=BindingIdentifier<Yield=false>
TypeVariables?
ClassExtendsClause<Yield=false>?
| {N4InterfaceDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)*
'interface' typingStrategy=TypingStrategyDefSiteOperator? name=BindingIdentifier<Yield=false>
TypeVariables?
InterfaceImplementsList?
)
Members<Yield=false>
)
| {N4EnumDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)*
'enum' name=BindingIdentifier<Yield=false>
'{'
literals+=N4EnumLiteral (',' literals+= N4EnumLiteral)*
'}'
)
;
fragment TypeVariables*:
'<' typeVars+=TypeVariable (',' typeVars+=TypeVariable)* '>'
;
ExportDeclaration:
ExportDeclarationImpl
;
fragment ExportDeclarationImpl*:
'export' (
wildcardExport?='*' ExportFromClause Semi
| ExportClause ->ExportFromClause? Semi
| exportedElement=ExportableElement
| defaultExport?='default' (->exportedElement=ExportableElement | defaultExportedExpression=AssignmentExpression<In=true,Yield=false> Semi)
)
;
fragment ExportFromClause*:
'from' reexportedFrom=[types::TModule|ModuleSpecifier]
;
fragment ExportClause*:
'{'
(namedExports+=ExportSpecifier (',' namedExports+=ExportSpecifier)* ','?)?
'}'
;
ExportSpecifier:
element=IdentifierRef<Yield=false> ('as' alias=IdentifierName)?
;
ExportableElement:
AnnotatedExportableElement<Yield=false>
| N4ClassDeclaration<Yield=false>
| N4InterfaceDeclaration<Yield=false>
| N4EnumDeclaration<Yield=false>
| ExportedFunctionDeclaration<Yield=false>
| ExportedVariableStatement
;
AnnotatedExportableElement <Yield>:
AnnotationList (
{FunctionDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)* AsyncNoTrailingLineBreak
FunctionImpl<Yield, Yield, Expression=false>
| {ExportedVariableStatement.annotationList=current}
(declaredModifiers+=N4Modifier)*
varStmtKeyword=VariableStatementKeyword
varDeclsOrBindings+=ExportedVariableDeclarationOrBinding<Yield> ( ',' varDeclsOrBindings+=ExportedVariableDeclarationOrBinding<Yield> )* Semi
| (
(
{N4ClassDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)*
'class' typingStrategy=TypingStrategyDefSiteOperator?
name=BindingIdentifier<Yield>
TypeVariables?
ClassExtendsClause<Yield>?
| {N4InterfaceDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)*
('interface') typingStrategy=TypingStrategyDefSiteOperator? name=BindingIdentifier<Yield>
TypeVariables?
InterfaceImplementsList?
)
Members<Yield>
)
| {N4EnumDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)*
'enum' name=BindingIdentifier<Yield>
'{'
literals+=N4EnumLiteral (',' literals+= N4EnumLiteral)*
'}'
)
;
ImportDeclaration:
ImportDeclarationImpl
;
fragment ImportDeclarationImpl*:
'import' (
ImportClause importFrom?='from'
)? module=[types::TModule|ModuleSpecifier] Semi
;
fragment ImportClause*:
importSpecifiers+=DefaultImportSpecifier (',' ImportSpecifiersExceptDefault)?
| ImportSpecifiersExceptDefault
;
fragment ImportSpecifiersExceptDefault*:
importSpecifiers+=NamespaceImportSpecifier
| '{' (importSpecifiers+=NamedImportSpecifier (',' importSpecifiers+=NamedImportSpecifier)* ','?)? '}'
;
NamedImportSpecifier:
importedElement=[types::TExportableElement|BindingIdentifier<Yield=false>]
| importedElement=[types::TExportableElement|IdentifierName] 'as' alias=BindingIdentifier<Yield=false>
;
DefaultImportSpecifier:
importedElement=[types::TExportableElement|BindingIdentifier<Yield=false>]
;
NamespaceImportSpecifier: '*' 'as' alias=BindingIdentifier<false> (declaredDynamic?='+')?;
ModuleSpecifier: STRING;
FunctionDeclaration <Yield>:
=> ((declaredModifiers+=N4Modifier)* AsyncNoTrailingLineBreak
-> FunctionImpl <Yield,Yield,Expression=false>
) => Semi?
;
fragment AsyncNoTrailingLineBreak *: (declaredAsync?='async' NoLineTerminator)?;
fragment FunctionImpl<Yield, YieldIfGenerator, Expression>*:
'function'
(
generator?='*' FunctionHeader<YieldIfGenerator,Generator=true> FunctionBody<Yield=true,Expression>
| FunctionHeader<Yield,Generator=false> FunctionBody<Yield=false,Expression>
)
;
fragment FunctionHeader<Yield, Generator>*:
TypeVariables?
name=BindingIdentifier<Yield>?
StrictFormalParameters<Yield=Generator>
(-> ':' returnTypeRef=TypeRef)?
;
fragment FunctionBody <Yield, Expression>*:
<Expression> body=Block<Yield>
| <!Expression> body=Block<Yield>?
;
ExportedFunctionDeclaration<Yield>:
FunctionDeclaration<Yield>
;
FunctionTypeExpression:
{types::FunctionTypeExpression}
'{'
('@' 'This' '(' declaredThisType=TypeRefFunctionTypeExpression ')')?
'function'
('<' ownedTypeVars+=TypeVariable (',' ownedTypeVars+=TypeVariable)* '>')?
'('
(fpars+=TAnonymousFormalParameter (',' fpars+=TAnonymousFormalParameter)*)?
')'
(':' returnTypeRef=TypeRef)?
'}';
AnnotatedFunctionDeclaration <Yield, Default>:
annotationList=AnnotationList
(declaredModifiers+=N4Modifier)* AsyncNoTrailingLineBreak
FunctionImpl<Yield,Yield,Expression=false>
;
FunctionExpression:
(FunctionImpl<Yield=false,YieldIfGenerator=true,Expression=true>
)
;
AsyncFunctionExpression:
=>(declaredAsync?='async' NoLineTerminator 'function')
FunctionHeader<Yield=false,Generator=false> FunctionBody<Yield=false,Expression=true>
;
ArrowExpression <In, Yield>:
=> (
(
'(' (fpars+=FormalParameter<Yield>
(',' fpars+=FormalParameter<Yield>)*)?
')' (':' returnTypeRef=TypeRef)?
| =>(declaredAsync?='async' NoLineTerminator '(')
(fpars+=FormalParameter<Yield> (',' fpars+=FormalParameter<Yield>)*)?
')' (':' returnTypeRef=TypeRef)?
| fpars+=BindingIdentifierAsFormalParameter<Yield>
)
'=>'
)
(-> hasBracesAroundBody?='{' body=BlockMinusBraces<Yield> '}'
| body=ExpressionDisguisedAsBlock<In>)
;
fragment StrictFormalParameters <Yield>*:
'(' (fpars+=FormalParameter<Yield> (',' fpars+=FormalParameter<Yield>)*)? ')'
;
BindingIdentifierAsFormalParameter <Yield>: name=BindingIdentifier<Yield>;
BlockMinusBraces <Yield>: statements+=Statement<Yield>*;
ExpressionDisguisedAsBlock <In>:
statements+=AssignmentExpressionStatement<In>
;
AssignmentExpressionStatement <In>: expression=AssignmentExpression<In,Yield=false>;
AnnotatedExpression <Yield>:
ExpressionAnnotationList (
{N4ClassExpression.annotationList=current}
'class' name=BindingIdentifier<Yield>?
ClassExtendsClause<Yield>?
Members<Yield>
| {FunctionExpression.annotationList=current} AsyncNoTrailingLineBreak
FunctionImpl<Yield=false,YieldIfGenerator=true,Expression=true>
)
;
TypeVariable:
name=IdentifierOrThis
( 'extends' declaredUpperBounds+=ParameterizedTypeRefNominal
('&' declaredUpperBounds+=ParameterizedTypeRefNominal)*
)?
;
FormalParameter <Yield>:
BindingElementFragment<Yield>
;
fragment BindingElementFragment <Yield>*:
(=> bindingPattern=BindingPattern<Yield>
| annotations+=Annotation*
(
variadic?='...'? name=BindingIdentifier<Yield> ColonSepTypeRef?
)
)
('=' initializer=AssignmentExpression<In=true, Yield>)?
;
fragment ColonSepTypeRef*:
':' declaredTypeRef=TypeRef
;
Block <Yield>: => ('{') statements+=Statement<Yield>* '}';
RootStatement <Yield>:
Block<Yield>
| FunctionDeclaration<Yield>
| VariableStatement<In=true,Yield>
| EmptyStatement
| LabelledStatement<Yield>
| ExpressionStatement<Yield>
| IfStatement<Yield>
| IterationStatement<Yield>
| ContinueStatement<Yield>
| BreakStatement<Yield>
| ReturnStatement<Yield>
| WithStatement<Yield>
| SwitchStatement<Yield>
| ThrowStatement<Yield>
| TryStatement<Yield>
| DebuggerStatement
;
Statement <Yield>:
AnnotatedFunctionDeclaration<Yield,Default=false>
| RootStatement<Yield>
;
enum VariableStatementKeyword:
var='var' | const='const' | let='let'
;
VariableStatement <In, Yield>:
=>(varStmtKeyword=VariableStatementKeyword
)
varDeclsOrBindings+=VariableDeclarationOrBinding<In,Yield,false>
(',' varDeclsOrBindings+=VariableDeclarationOrBinding<In,Yield,false>)* Semi
;
ExportedVariableStatement:
(declaredModifiers+=N4Modifier)*
varStmtKeyword=VariableStatementKeyword
varDeclsOrBindings+=ExportedVariableDeclarationOrBinding<Yield=false>
(',' varDeclsOrBindings+=ExportedVariableDeclarationOrBinding<Yield=false>)* Semi
;
VariableDeclarationOrBinding <In, Yield, OptionalInit>:
VariableBinding<In,Yield,OptionalInit>
| VariableDeclaration<In,Yield,true>
;
VariableBinding <In, Yield, OptionalInit>:
=> pattern=BindingPattern<Yield> (
<OptionalInit> ('=' expression=AssignmentExpression<In,Yield>)?
| <!OptionalInit> '=' expression=AssignmentExpression<In,Yield>
)
;
VariableDeclaration <In, Yield, AllowType>:
VariableDeclarationImpl<In,Yield,AllowType>;
fragment VariableDeclarationImpl <In, Yield, AllowType>*:
annotations+=Annotation*
(
<AllowType> =>(
name=BindingIdentifier<Yield> ColonSepTypeRef?
) ('=' expression=AssignmentExpression<In,Yield>)?
| <!AllowType> =>(
name=BindingIdentifier<Yield>
) ('=' expression=AssignmentExpression<In,Yield>)?
)
;
ExportedVariableDeclarationOrBinding <Yield>:
ExportedVariableBinding<Yield>
| ExportedVariableDeclaration<Yield>
;
ExportedVariableBinding <Yield>:
=> pattern=BindingPattern<Yield> '=' expression=AssignmentExpression<In=true,Yield>
;
ExportedVariableDeclaration <Yield>:
VariableDeclarationImpl<In=true,Yield,AllowType=true>
;
EmptyStatement: ';';
ExpressionStatement <Yield>: expression=Expression<In=true,Yield> Semi;
IfStatement <Yield>: 'if' '(' expression=Expression<In=true,Yield> ')'
ifStmt=Statement<Yield> (=> 'else' elseStmt=Statement<Yield>)?;
IterationStatement <Yield>:
DoStatement<Yield>
| WhileStatement<Yield>
| ForStatement<Yield>
;
DoStatement <Yield>: 'do' statement=Statement<Yield> 'while'
'(' expression=Expression<In=true,Yield> ')' => Semi?;
WhileStatement <Yield>: 'while' '(' expression=Expression<In=true,Yield> ')'
statement=Statement<Yield>;
ForStatement <Yield>:
'for' '('
(
=>(initExpr=LetIdentifierRef forIn?='in' expression=Expression<In=true,Yield> ')')
| ( ->varStmtKeyword=VariableStatementKeyword
(
=>(varDeclsOrBindings+=BindingIdentifierAsVariableDeclaration<In=false,Yield>
(forIn?='in' | forOf?='of') ->expression=AssignmentExpression<In=true,Yield>?)
| varDeclsOrBindings+=VariableDeclarationOrBinding<In=false,Yield,OptionalInit=true>
(
(',' varDeclsOrBindings+=VariableDeclarationOrBinding<In=false,Yield,false>)* ';'
expression=Expression<In=true,Yield>? ';' updateExpr=Expression<In=true,Yield>?
| forIn?='in' expression=Expression<In=true,Yield>?
| forOf?='of' expression=AssignmentExpression<In=true,Yield>?
)
)
| initExpr=Expression<In=false,Yield>
(
';' expression=Expression<In=true,Yield>? ';' updateExpr=Expression<In=true,Yield>?
| forIn?='in' expression=Expression<In=true,Yield>?
| forOf?='of' expression=AssignmentExpression<In=true,Yield>?
)
| ';' expression=Expression<In=true,Yield>? ';' updateExpr=Expression<In=true,Yield>?
)
')'
) statement=Statement<Yield>
;
LetIdentifierRef:
id=[types::IdentifiableElement|LetAsIdentifier]
;
LetAsIdentifier: 'let';
BindingIdentifierAsVariableDeclaration <In, Yield>:
name=BindingIdentifier<Yield>
;
ContinueStatement <Yield>: 'continue' (label=[LabelledStatement|BindingIdentifier<Yield>])? Semi;
BreakStatement <Yield>: 'break' (label=[LabelledStatement|BindingIdentifier<Yield>])? Semi;
ReturnStatement <Yield>: 'return' (expression=Expression<In=true,Yield>)? Semi;
WithStatement <Yield>: 'with' '(' expression=Expression<In=true,Yield> ')' statement=Statement<Yield>;
SwitchStatement <Yield>:
'switch' '(' expression=Expression<In=true,Yield> ')' '{'
(cases+=CaseClause<Yield>)*
((cases+=DefaultClause<Yield>)
(cases+=CaseClause<Yield>)*)? '}'
;
CaseClause <Yield>: 'case' expression=Expression<In=true,Yield> ':' (statements+=Statement<Yield>)*;
DefaultClause <Yield>: 'default' ':' (statements+=Statement<Yield>)*;
LabelledStatement <Yield>: => (name=BindingIdentifier<Yield> ':') statement=Statement<Yield>;
ThrowStatement <Yield>:
'throw' expression=Expression<In=true,Yield> Semi;
TryStatement <Yield>:
'try' block=Block<Yield>
((catch=CatchBlock<Yield> finally=FinallyBlock<Yield>?) | finally=FinallyBlock<Yield>)
;
CatchBlock <Yield>: 'catch' '(' catchVariable=CatchVariable<Yield> ')' block=Block<Yield>;
CatchVariable <Yield>:
=>bindingPattern=BindingPattern<Yield>
| =>(name=BindingIdentifier<Yield> -> ColonSepTypeRef)
| name=BindingIdentifier<Yield>
;
FinallyBlock <Yield>: 'finally' block=Block<Yield>;
DebuggerStatement:
'debugger' Semi;
PrimaryExpression <Yield>:
ThisLiteral
| SuperLiteral
| IdentifierRef<Yield>
| ParameterizedCallExpression<Yield>
| Literal
| ArrayLiteral<Yield>
| ObjectLiteral<Yield>
| ParenExpression<Yield>
| AnnotatedExpression<Yield>
| FunctionExpression
| AsyncFunctionExpression
| N4ClassExpression<Yield>
| TemplateLiteral<Yield>
;
ParenExpression <Yield>: '(' expression=Expression<In=true,Yield> ')';
IdentifierRef <Yield>:
id=[types::IdentifiableElement|BindingIdentifier<Yield>]
;
SuperLiteral: 'super';
ThisLiteral: 'this';
ArrayLiteral <Yield>:
'['
elements+=ArrayPadding* (
elements+=ArrayElement<Yield>
(',' elements+=ArrayPadding* elements+=ArrayElement<Yield>)*
(trailingComma?=',' elements+=ArrayPadding*)?
)?
']'
;
ArrayPadding: ',';
ArrayElement <Yield>: spread?='...'? expression=AssignmentExpression<In=true,Yield>;
ObjectLiteral <Yield>: '{'
( propertyAssignments+=PropertyAssignment<Yield>
(',' propertyAssignments+=PropertyAssignment<Yield>)* ','?
)?
'}'
;
PropertyAssignment <Yield>:
AnnotatedPropertyAssignment<Yield>
| PropertyNameValuePair<Yield>
| PropertyGetterDeclaration<Yield>
| PropertySetterDeclaration<Yield>
| PropertyMethodDeclaration<Yield>
| PropertyNameValuePairSingleName<Yield>
;
AnnotatedPropertyAssignment <Yield>:
PropertyAssignmentAnnotationList (
=>( {PropertyNameValuePair.annotationList=current} declaredTypeRef=TypeRef?
LiteralOrComputedPropertyName<Yield> ':'
) expression=AssignmentExpression<In=true,Yield>
| =>({PropertyGetterDeclaration.annotationList=current}
GetterHeader<Yield>
) body=Block<Yield=false>
| =>({PropertySetterDeclaration.annotationList=current}
'set' ->LiteralOrComputedPropertyName <Yield>
) '(' fpar=FormalParameter<Yield> ')' body=Block<Yield=false>
| =>({PropertyMethodDeclaration.annotationList=current}
TypeVariables? returnTypeRef=TypeRef?
(generator?='*' LiteralOrComputedPropertyName<Yield> ->MethodParamsAndBody <Generator=true>
| LiteralOrComputedPropertyName<Yield> -> MethodParamsAndBody <Generator=false>
)
) ';'?
| {PropertyNameValuePairSingleName.annotationList=current}
declaredTypeRef=TypeRef? identifierRef=IdentifierRef<Yield>
( '=' expression=AssignmentExpression<In=true,Yield>)?)
;
PropertyMethodDeclaration <Yield>:
=> (TypeVariables? returnTypeRef=TypeRef?
(
generator?='*' LiteralOrComputedPropertyName<Yield>
->MethodParamsAndBody<Generator=true>
| LiteralOrComputedPropertyName<Yield> ->MethodParamsAndBody <Generator=false>
)
)
';'?
;
PropertyNameValuePair <Yield>:
=> (
declaredTypeRef=TypeRef? LiteralOrComputedPropertyName<Yield> ':'
)
expression=AssignmentExpression<In=true,Yield>
;
PropertyNameValuePairSingleName <Yield>:
declaredTypeRef=TypeRef?
identifierRef=IdentifierRef<Yield>
('=' expression=AssignmentExpression<In=true,Yield>)?
;
PropertyGetterDeclaration <Yield>:
=>(
GetterHeader<Yield>
)
body=Block<Yield=false>
;
PropertySetterDeclaration <Yield>:
=>(
'set'
->LiteralOrComputedPropertyName <Yield>
)
'(' fpar=FormalParameter<Yield> ')' body=Block<Yield=false>
;
ParameterizedCallExpression <Yield>:
TypeArguments
target=IdentifierRef<Yield>
ArgumentsWithParentheses<Yield>
;
LeftHandSideExpression <Yield>:
MemberExpression<Yield> (
{ParameterizedCallExpression.target=current} ArgumentsWithParentheses<Yield>
(
{ParameterizedCallExpression.target=current} ArgumentsWithParentheses<Yield>
| {IndexedAccessExpression.target=current} IndexedAccessExpressionTail<Yield>
| {ParameterizedPropertyAccessExpression.target=current}
ParameterizedPropertyAccessExpressionTail<Yield>
| ->({TaggedTemplateString.target=current} template=TemplateLiteral<Yield>)
)*
)?
;
fragment Arguments <Yield>*:
arguments+=AssignmentExpression<In=true,Yield>
(',' arguments+=AssignmentExpression<In=true,Yield>)*
(',' spread?='...' arguments+=AssignmentExpression<In=true,Yield>)?
| spread?='...' arguments+=AssignmentExpression<In=true,Yield>
;
fragment TypeArguments*:
'<' typeArgs+=TypeRef (',' typeArgs+=TypeRef)* '>'
;
fragment ArgumentsWithParentheses <Yield>*:
'(' Arguments<Yield>? ')'
;
MemberExpression <Yield>:
=>('new' '.') 'target'
| => ('new') callee=MemberExpression<Yield> (-> TypeArguments)?
(=> withArgs?='(' Arguments<Yield>? ')'
(
{IndexedAccessExpression.target=current} IndexedAccessExpressionTail<Yield>
| {ParameterizedPropertyAccessExpression.target=current}
ParameterizedPropertyAccessExpressionTail<Yield>
| {TaggedTemplateString.target=current} template=TemplateLiteral<Yield>
)*
)?
| PrimaryExpression<Yield> (
{IndexedAccessExpression.target=current} IndexedAccessExpressionTail<Yield>
| {ParameterizedPropertyAccessExpression.target=current}
ParameterizedPropertyAccessExpressionTail<Yield>
| {TaggedTemplateString.target=current} template=TemplateLiteral<Yield>
)*
;
fragment IndexedAccessExpressionTail <Yield>*:
'[' index=Expression<In=true,Yield> ']'
;
fragment ParameterizedPropertyAccessExpressionTail <Yield>*:
'.' TypeArguments? property=[types::IdentifiableElement|IdentifierName]
;
PostfixExpression <Yield>:
LeftHandSideExpression<Yield> (
=>({PostfixExpression.expression=current} op=PostfixOperator
)
)?
;
enum PostfixOperator: inc='++' | dec='--';
CastExpression <Yield>: PostfixExpression<Yield>
(=>({CastExpression.expression=current} 'as') targetTypeRef=TypeRefForCast)?;
UnaryExpression <Yield>:
CastExpression<Yield>
| (op=UnaryOperator expression=UnaryExpression<Yield>);
enum UnaryOperator: delete | void | typeof | inc='++' | dec='--' | pos='+' | neg='-' | inv='~' | not='!';
MultiplicativeExpression <Yield>: UnaryExpression<Yield>
(=>({MultiplicativeExpression.lhs=current} op=MultiplicativeOperator)
rhs=UnaryExpression<Yield>)*;
enum MultiplicativeOperator: times='*' | div='/' | mod='%';
AdditiveExpression <Yield>: MultiplicativeExpression<Yield>
(=>({AdditiveExpression.lhs=current} op=AdditiveOperator)
rhs=MultiplicativeExpression<Yield>)*;
enum AdditiveOperator: add='+' | sub='-';
ShiftExpression <Yield>: AdditiveExpression<Yield>
(=>({ShiftExpression.lhs=current} op=ShiftOperator rhs=AdditiveExpression<Yield>))*
;
ShiftOperator:
'>' '>' '>'?
| '<<'
;
RelationalExpression <In, Yield>: ShiftExpression<Yield>
=>({RelationalExpression.lhs=current} op=RelationalOperator<In>
->rhs=ShiftExpression<Yield>)*;
RelationalOperator <In>:
'<' | '>' | '<=' | '>=' | 'instanceof' | <In> 'in';
EqualityExpression <In, Yield>: RelationalExpression<In,Yield>
(=>({EqualityExpression.lhs=current} op=EqualityOperator) rhs=RelationalExpression<In,Yield>)*;
enum EqualityOperator: same='===' | nsame='!==' | eq='==' | neq='!=';
BitwiseANDExpression <In, Yield>: EqualityExpression<In,Yield>
(=>({BinaryBitwiseExpression.lhs=current} op=BitwiseANDOperator) rhs=EqualityExpression<In,Yield>)*;
BitwiseANDOperator: '&';
BitwiseXORExpression <In, Yield>: BitwiseANDExpression<In,Yield>
(=>({BinaryBitwiseExpression.lhs=current} op=BitwiseXOROperator) rhs=BitwiseANDExpression<In,Yield>)*;
BitwiseXOROperator: '^';
BitwiseORExpression <In, Yield>: BitwiseXORExpression<In,Yield>
(=>({BinaryBitwiseExpression.lhs=current} op=BitwiseOROperator) rhs=BitwiseXORExpression<In,Yield>)*;
BitwiseOROperator: '|';
LogicalANDExpression <In, Yield>: BitwiseORExpression<In,Yield>
(=> ({BinaryLogicalExpression.lhs=current} op=LogicalANDOperator) rhs=BitwiseORExpression<In,Yield>)*;
LogicalANDOperator: '&&';
LogicalORExpression <In, Yield>: LogicalANDExpression<In,Yield>
(=>({BinaryLogicalExpression.lhs=current} op=LogicalOROperator) rhs=LogicalANDExpression<In,Yield>)*;
LogicalOROperator: '||';
ConditionalExpression <In, Yield>: LogicalORExpression<In,Yield>
(=> ({ConditionalExpression.expression=current} '?') trueExpression=AssignmentExpression<In=true,Yield>
':' falseExpression=AssignmentExpression<In,Yield>)?;
AssignmentExpression <In, Yield>:
AwaitExpression<In,Yield>
| PromisifyExpression<In,Yield>
| ArrowExpression<In,Yield>
| <Yield> YieldExpression<In>
| ConditionalExpression<In,Yield>
(=> ({AssignmentExpression.lhs=current} op=AssignmentOperator)
rhs=AssignmentExpression<In,Yield>)?
;
YieldExpression <In>:
'yield' => many?='*'? -> expression=AssignmentExpression<In,Yield=true>?
;
AssignmentOperator:
'=' | '*=' | '/=' | '%=' | '+=' | '-='
| '<<='
| '>' '>'? '>='
| '&=' | '^=' | '|='
;
AwaitExpression <In, Yield>:
=>('await') expression=AssignmentExpression<In,Yield>;
PromisifyExpression <In, Yield>:
=> ('@' 'Promisify') expression=AssignmentExpression<In,Yield>;
Expression <In, Yield>:
AssignmentExpression<In,Yield> ({CommaExpression.exprs+=current}
',' exprs+=AssignmentExpression<In,Yield>
(',' exprs+=AssignmentExpression<In,Yield>)*)?
;
TemplateLiteral <Yield>:
(
segments+=NoSubstitutionTemplate
| segments+=TemplateHead segments+=Expression<In=true,Yield>? TemplateExpressionEnd
(
segments+=TemplateMiddle segments+=Expression<In=true,Yield>?
TemplateExpressionEnd
)*
segments+=TemplateTail
)
;
TemplateExpressionEnd:
'}'
;
NoSubstitutionTemplate:
rawValue=NO_SUBSTITUTION_TEMPLATE_LITERAL
;
TemplateHead:
rawValue=TEMPLATE_HEAD
;
TemplateTail:
rawValue=TemplateTailLiteral;
TemplateMiddle:
rawValue=TemplateMiddleLiteral;
Literal:
NumericLiteral | BooleanLiteral | StringLiteral
| NullLiteral | RegularExpressionLiteral;
NullLiteral: 'null';
BooleanLiteral: (true?='true' | 'false');
StringLiteral: value=STRING;
NumericLiteral:
DoubleLiteral | IntLiteral | BinaryIntLiteral | OctalIntLiteral
| LegacyOctalIntLiteral | HexIntLiteral | ScientificIntLiteral;
DoubleLiteral: value=DOUBLE;
IntLiteral: value=INT;
OctalIntLiteral: value=OCTAL_INT;
LegacyOctalIntLiteral: value=LEGACY_OCTAL_INT;
HexIntLiteral: value=HEX_INT;
BinaryIntLiteral: value=BINARY_INT;
ScientificIntLiteral: value=SCIENTIFIC_INT;
RegularExpressionLiteral: value=REGEX_LITERAL;
NumericLiteralAsString:
DOUBLE | INT | OCTAL_INT | HEX_INT | SCIENTIFIC_INT
;
IdentifierOrThis:
IDENTIFIER
| 'This'
| 'Promisify'
| 'target';
AnnotationName:
IDENTIFIER
| 'This'
| 'target';
BindingIdentifier <Yield>:
IDENTIFIER
| <!Yield> 'yield'
| N4Keyword
;
IdentifierName:
IDENTIFIER | ReservedWord | N4Keyword
;
ReservedWord:
'break' | 'case' | 'catch' | 'class' | 'const' | 'continue' | 'debugger' | 'default' | 'delete'
| 'do' | 'else' | 'export' | 'extends' | 'finally' | 'for' | 'function' | 'if' | 'import'
| 'in' | 'instanceof' | 'new' | 'return' | 'super' | 'switch' | 'this' | 'throw' | 'try'
| 'typeof' | 'var' | 'void' | 'while' | 'with' | 'yield'
| 'null'
| 'true' | 'false'
| 'enum';
N4Keyword:
'get' | 'set'
| 'let'
| 'project'
| 'external' | 'abstract' | 'static'
| 'as' | 'from' | 'constructor' | 'of' | 'target'
| 'type' | 'union' | 'intersection'
| 'This' | 'Await' | 'Promisify'
| 'await'
| 'async'
| 'implements' | 'interface'
| 'private' | 'protected' | 'public'
;
SymbolLiteralComputedName <Yield>:
BindingIdentifier<Yield> ('.' IdentifierName)?
;
terminal DOUBLE:
'.' DECIMAL_DIGIT_FRAGMENT+ EXPONENT_PART?
| DECIMAL_INTEGER_LITERAL_FRAGMENT '.' DECIMAL_DIGIT_FRAGMENT* EXPONENT_PART?
;
terminal HEX_INT: '0' ('x' | 'X') INT_SUFFIX;
terminal BINARY_INT: '0' ('b' | 'B') INT_SUFFIX;
terminal OCTAL_INT: '0' ('o' | 'O') INT_SUFFIX;
terminal LEGACY_OCTAL_INT: '0' DECIMAL_DIGIT_FRAGMENT INT_SUFFIX;
terminal fragment INT_SUFFIX: IDENTIFIER_PART*;
terminal SCIENTIFIC_INT:
DECIMAL_INTEGER_LITERAL_FRAGMENT EXPONENT_PART
;
terminal fragment EXPONENT_PART:
('e' | 'E') SIGNED_INT
| IDENTIFIER
;
terminal fragment SIGNED_INT:
('+' | '-') DECIMAL_DIGIT_FRAGMENT+ IDENTIFIER?
;
terminal STRING:
'"' DOUBLE_STRING_CHAR* '"'?
| "'" SINGLE_STRING_CHAR* "'"?
;
terminal fragment DOUBLE_STRING_CHAR:
!(LINE_TERMINATOR_FRAGMENT | '"' | '\\')
| '\\' (LINE_TERMINATOR_SEQUENCE_FRAGMENT | !LINE_TERMINATOR_FRAGMENT)?
;
terminal fragment SINGLE_STRING_CHAR:
!(LINE_TERMINATOR_FRAGMENT | "'" | '\\')
| '\\' (LINE_TERMINATOR_SEQUENCE_FRAGMENT | !LINE_TERMINATOR_FRAGMENT)?
;
terminal fragment BACKSLASH_SEQUENCE:
'\\' !(LINE_TERMINATOR_FRAGMENT)?
;
terminal fragment REGEX_CHAR:
!(LINE_TERMINATOR_FRAGMENT | '\\' | '/' | '[')
| BACKSLASH_SEQUENCE
| '[' REGEX_CHAR_OR_BRACKET* ']'?
;
terminal fragment REGEX_CHAR_OR_BRACKET:
!(LINE_TERMINATOR_FRAGMENT | '\\' | ']')
| BACKSLASH_SEQUENCE
;
REGEX_LITERAL:
('/' | '/=') REGEX_TAIL?
;
terminal fragment ACTUAL_REGEX_TAIL:
REGEX_CHAR+ ('/' IDENTIFIER_PART*)?
| '/' IDENTIFIER_PART*
;
terminal fragment REGEX_START:
('/' | '/=')
;
terminal REGEX_TAIL: // post processed
'//1'
;
terminal TEMPLATE_HEAD:
"`" TEMPLATE_LITERAL_CHAR* '$'+ '{'
;
terminal NO_SUBSTITUTION_TEMPLATE_LITERAL:
'`' TEMPLATE_LITERAL_CHAR* '$'* "`"?
;
terminal fragment ACTUAL_TEMPLATE_END:
TEMPLATE_LITERAL_CHAR* ('$'+ ('{' | '`'?) | '`'?)
;
terminal fragment TEMPLATE_LITERAL_CHAR:
!(LINE_TERMINATOR_FRAGMENT | '`' | '\\' | '$')
| '$'+ !('{' | '`' | '$')
| LINE_TERMINATOR_SEQUENCE_FRAGMENT
| '\\' (LINE_TERMINATOR_SEQUENCE_FRAGMENT | !LINE_TERMINATOR_FRAGMENT)?
;
TemplateTailLiteral:
TEMPLATE_END?
;
TemplateMiddleLiteral:
TEMPLATE_MIDDLE
;
terminal TEMPLATE_MIDDLE:
'//2' // will never be lexed
;
terminal TEMPLATE_END:
'//3' // will never be lexed
;
terminal fragment TEMPLATE_CONTINUATION:
'//4' // actually '}'
;
Semi: ';'; // automatic semicolon instertion, post-processed
fragment NoLineTerminator*: NO_LINE_TERMINATOR?;
terminal NO_LINE_TERMINATOR:
'//5' // post-processed, will never be lexed
;
Annotation:'@' AnnotationNoAtSign;
ScriptAnnotation: '@@' AnnotationNoAtSign;
AnnotationNoAtSign:
name=AnnotationName (=> '(' (args+=AnnotationArgument (',' args+=AnnotationArgument)*)? ')')?;
AnnotationArgument:
LiteralAnnotationArgument | TypeRefAnnotationArgument
;
LiteralAnnotationArgument:
literal=Literal
;
TypeRefAnnotationArgument:
typeRef=TypeRef
;
AnnotationList:
=>('@' -> annotations+=AnnotationNoAtSign) annotations+=Annotation*
;
ExpressionAnnotationList:
annotations+=Annotation+
;
PropertyAssignmentAnnotationList:
annotations+=Annotation+
;
N4MemberAnnotationList:
{N4MemberAnnotationList} annotations+=Annotation+
;
TypeReferenceName:
'void' | 'This' | 'await' | 'Promisify' | 'target' | QualifiedTypeReferenceName
;
QualifiedTypeReferenceName:
IDENTIFIER ('.' IDENTIFIER)?
;
N4ClassDeclaration <Yield>:
=>(
{N4ClassDeclaration}
(declaredModifiers+=N4Modifier)*
'class' typingStrategy=TypingStrategyDefSiteOperator? name=BindingIdentifier<Yield>?
)
TypeVariables?
ClassExtendsClause<Yield>?
Members<Yield>
;
fragment Members <Yield>*:
'{'
ownedMembersRaw+=N4MemberDeclaration<Yield>*
'}'
;
fragment ClassExtendsClause <Yield>*:
'extends' (
=>superClassRef=ParameterizedTypeRefNominal ('implements' ClassImplementsList)?
| superClassExpression=LeftHandSideExpression<Yield>
)
| 'implements' ClassImplementsList
;
fragment ClassImplementsList*:
implementedInterfaceRefs+=ParameterizedTypeRefNominal
(',' implementedInterfaceRefs+=ParameterizedTypeRefNominal)*
;
N4ClassExpression <Yield>:
{N4ClassExpression}
'class' name=BindingIdentifier<Yield>?
ClassExtendsClause<Yield>?
Members<Yield>;
N4InterfaceDeclaration <Yield>:
=> (
{N4InterfaceDeclaration}
(declaredModifiers+=N4Modifier)*
'interface' typingStrategy=TypingStrategyDefSiteOperator? name=BindingIdentifier<Yield>?
)
TypeVariables?
InterfaceImplementsList?
Members<Yield>
;
fragment InterfaceImplementsList*:
'extends' superInterfaceRefs+=ParameterizedTypeRefNominal
(',' superInterfaceRefs+=ParameterizedTypeRefNominal)*
;
N4EnumDeclaration <Yield>:
=>(
{N4EnumDeclaration}
(declaredModifiers+=N4Modifier)*
'enum' name=BindingIdentifier<Yield>?
)
'{'
(literals+=N4EnumLiteral (',' literals+=N4EnumLiteral)*)?
'}'
;
N4EnumLiteral: name=IdentifierOrThis (':' value=STRING)?;
enum N4Modifier: // validator applies further checks
private | project | protected | public
| external | abstract | static | const;
N4MemberDeclaration <Yield>:
AnnotatedN4MemberDeclaration<Yield>
| N4GetterDeclaration<Yield>
| N4SetterDeclaration<Yield>
| N4MethodDeclaration<Yield>
| N4FieldDeclaration<Yield>
| N4CallableConstructorDeclaration<Yield>
;
AnnotatedN4MemberDeclaration <Yield> returns N4MemberDeclaration:
N4MemberAnnotationList (
=> ({N4GetterDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)* GetterHeader<Yield>) (body=Block<Yield>)? ';'?
| => ({N4SetterDeclaration.annotationList=current}
(declaredModifiers+=N4Modifier)* 'set' -> LiteralOrComputedPropertyName <Yield>)
'(' fpar=FormalParameter<Yield> ')' (body=Block<Yield>)? ';'?
| => (
{N4MethodDeclaration.annotationList=current} (declaredModifiers+=N4Modifier)* TypeVariables?
(
generator?='*' LiteralOrComputedPropertyName<Yield>
->MethodParamsReturnAndBody <Generator=true>
| AsyncNoTrailingLineBreak LiteralOrComputedPropertyName<Yield>
->MethodParamsReturnAndBody <Generator=false>
)
)';'?
| {N4FieldDeclaration.annotationList=current} FieldDeclarationImpl<Yield>
)
;
fragment LiteralOrComputedPropertyName <Yield>*:
name=IdentifierName | name=STRING | name=NumericLiteralAsString
| '[' (=>((name=SymbolLiteralComputedName<Yield> | name=StringLiteralAsName) ']')
| computeNameFrom=AssignmentExpression<In=true,Yield> ']')
;
fragment LiteralPropertyName <Yield>*:
name=IdentifierName | name=STRING | name=NumericLiteralAsString
| '[' (name=SymbolLiteralComputedName<Yield> | name=StringLiteralAsName) ']'
;
StringLiteralAsName:
STRING
;
fragment FieldDeclarationImpl <Yield>*:
(declaredModifiers+=N4Modifier)*
LiteralPropertyName<Yield> ColonSepTypeRef? ('=' expression=Expression<In=true,Yield>)? ';'
;
N4FieldDeclaration <Yield>:
{N4FieldDeclaration}
FieldDeclarationImpl<Yield>
;
N4MethodDeclaration <Yield>:
=> ({N4MethodDeclaration} (declaredModifiers+=N4Modifier)* TypeVariables?
(
generator?='*' LiteralOrComputedPropertyName<Yield>
->MethodParamsReturnAndBody <Generator=true>
| AsyncNoTrailingLineBreak LiteralOrComputedPropertyName<Yield>
->MethodParamsReturnAndBody <Generator=false>
)
) ';'?
;
N4CallableConstructorDeclaration <Yield> returns N4MethodDeclaration:
MethodParamsReturnAndBody <Generator=false> ';'?
;
fragment MethodParamsAndBody <Generator>*:
StrictFormalParameters<Yield=Generator>
(body=Block<Yield=Generator>)?
;
fragment MethodParamsReturnAndBody <Generator>*:
StrictFormalParameters<Yield=Generator>
(':' returnTypeRef=TypeRef)?
(body=Block<Yield=Generator>)?
;
N4GetterDeclaration <Yield>:
=> ({N4GetterDeclaration}
(declaredModifiers+=N4Modifier)*
GetterHeader<Yield>)
(body=Block<Yield>)? ';'?
;
fragment GetterHeader <Yield>*:
('get' -> LiteralOrComputedPropertyName <Yield> '(' ')' ColonSepTypeRef?)
;
N4SetterDeclaration <Yield>:
=>({N4SetterDeclaration}
(declaredModifiers+=N4Modifier)*
'set'
->LiteralOrComputedPropertyName <Yield>
)
'(' fpar=FormalParameter<Yield> ')' (body=Block<Yield>)? ';'?
;
BindingPattern <Yield>:
ObjectBindingPattern<Yield>
| ArrayBindingPattern<Yield>
;
ObjectBindingPattern <Yield>:
'{' (properties+=BindingProperty<Yield,AllowType=false>
(',' properties+=BindingProperty<Yield,AllowType=false>)*)? '}'
;
ArrayBindingPattern <Yield>:
'['
elements+=Elision* (
elements+=BindingRestElement<Yield>
(',' elements+=Elision* elements+=BindingRestElement<Yield>)*
(',' elements+=Elision*)?
)?
']'
;
BindingProperty <Yield, AllowType>:
=>(LiteralBindingPropertyName<Yield> ':') value=BindingElement<Yield>
| value=SingleNameBinding<Yield,AllowType>
;
fragment LiteralBindingPropertyName <Yield>*:
declaredName=IdentifierName | declaredName=STRING | declaredName=NumericLiteralAsString
| '[' (declaredName=SymbolLiteralComputedName<Yield> | declaredName=STRING) ']'
;
SingleNameBinding <Yield, AllowType>:
varDecl=VariableDeclaration<In=true,Yield,AllowType>
;
BindingElement <Yield>:
=>(nestedPattern=BindingPattern<Yield>) ('=' expression=AssignmentExpression<In=true,Yield>)?
| varDecl=VariableDeclaration<In=true,Yield,AllowType=true>
;
BindingRestElement <Yield>:
rest?='...'?
(
=>(nestedPattern=BindingPattern<Yield>)
('=' expression=AssignmentExpression<In=true,Yield>)?
| varDecl=VariableDeclaration<In=true,Yield,AllowType=true>
)
;
Elision:
','
;