//!precedence @precedence { member, newArgs, call, times @left, plus @left, rel @left, ternary @right, assign @right, forIn, else, statement @cut } //!top @top Script { statement* } @top SingleExpression { expression } //!statement statement[@isGroup=Statement] { FunctionDeclaration | VariableDeclaration | ForStatement | IfStatement | ReturnStatement | Block | LabeledStatement { Identifier ":" statement } | ExpressionStatement { expression semi } | EmptyStatement { ";" } } //!ifstatement IfStatement { kw<"if"> ParenthesizedExpression statement (!else kw<"else"> statement)? } //!returnstatement ReturnStatement { kw<"return"> (noSemi expression)? semi } //!for ForStatement { kw<"for"> (ForSpec | ForInSpec) statement } ForSpec { "(" (VariableDeclaration | expression ";" | ";") expression? ";" expression? ")" } ForInSpec { "(" ((kw<"let"> | kw<"var"> | kw<"const">) pattern | Identifier) !forIn kw<"in"> expression ")" } //!functiondeclaration FunctionDeclaration { !statement kw<"function"> Identifier ParamList Block } ParamList { "(" commaSep<"..."? pattern ("=" expression)?> ")" } //!variabledeclaration VariableDeclaration { (kw<"let"> | kw<"var"> | kw<"const">) commaSep1 ~destructure "}" } } PatternProperty { ("..." pattern | propName ":" pattern | PropertyName) ("=" expression)? } //!block Block { !statement "{" statement* "}" } //!expression expression[@isGroup=Expression] { Number | String | TemplateString | Identifier ~arrow | @specialize[@name=BooleanLiteral] | kw<"this"> | kw<"null"> | kw<"super"> | RegExp | ArrayExpression { "[" commaSep1<"..."? expression | ""> ~destructure "]" } | ObjectExpression { "{" commaSep ~destructure "}" } | NewExpression { kw<"new"> expression (!newArgs ArgList)? } | UnaryExpression | ParenthesizedExpression | FunctionExpression { kw<"function"> Identifier? ParamList Block } | ArrowFunction { (ParamList { Identifier ~arrow } | ParamList) "=>" (Block | expression) } | MemberExpression | BinaryExpression | ConditionalExpression { expression !ternary LogicOp<"?"> expression LogicOp<":"> expression } | AssignmentExpression | CallExpression { expression !call ArgList } } //!expression_misc ParenthesizedExpression { "(" expression ")" } ArgList { "(" commaSep<"..."? expression> ")" } //!property propName { PropertyName | "[" expression "]" | Number | String } Property { (propKw<"get"> | propKw<"set">)? propName ParamList Block | propName ~destructure (":" expression)? | "..." expression } //!operators UnaryExpression { (kw<"void"> | kw<"typeof"> | kw<"delete"> | LogicOp<"!"> | ArithOp<"+" | "-">) expression } BinaryExpression { expression !times (ArithOp<"/"> | ArithOp<"%"> | ArithOp<"*">) expression | expression !plus ArithOp<"+" | "-"> expression | expression !rel CompareOp expression } //!assign AssignmentExpression { (Identifier | MemberExpression) !assign UpdateOp expression | (MemberExpression | pattern) !assign "=" expression } MemberExpression { expression !member ("." PropertyName | "[" expression "]") } //!commaSep commaSep { (content ("," content)*)? } commaSep1 { content ("," content)* } //!kw kw { @specialize[@name={term}] } //!propKw propKw { @extend[@name={term}] } //!semi semi { ";" | insertSemi } //!skip @skip { spaces | newline | LineComment | BlockComment } //!context @context trackNewline from "./tokens.js" //!noSemi @external tokens noSemicolon from "./tokens.js" { noSemi } //!templateStrings @skip {} { TemplateString { "`" (templateEscape | templateContent | Interpolation)* templateEnd } } Interpolation { InterpolationStart expression "}" } @local tokens { InterpolationStart[@name="${"] { "${" } templateEnd { "`" } templateEscape { "\\" _ } @else templateContent } //!blockComment @skip {} { BlockComment { "/*" (blockCommentContent | blockCommentNewline)* blockCommentEnd } } @local tokens { blockCommentEnd { "*/" } blockCommentNewline { "\n" } @else blockCommentContent } //!tokens @tokens { //!skippedTokens spaces[@export] { $[\u0009 \u000b\u00a0]+ } newline[@export] { $[\r\n] } LineComment { "//" ![\n]* } @precedence { "/*", LineComment, ArithOp<"/"> } @precedence { "/*", LineComment, RegExp } //!identifierTokens identifierChar { @asciiLetter | $[_$\u{a1}-\u{10ffff}] } Identifier { identifierChar (identifierChar | @digit)* } PropertyName { Identifier } //!numberTokens hex { @digit | $[a-fA-F] } Number { (@digit ("_" | @digit)* ("." ("_" | @digit)*)? | "." @digit ("_" | @digit)*) (("e" | "E") ("+" | "-")? ("_" | @digit)+)? | @digit ("_" | @digit)* "n" | "0x" (hex | "_")+ "n"? | "0b" $[01_]+ "n"? | "0o" $[0-7_]+ "n"? } @precedence { Number "." } //!stringTokens String { '"' (![\\\n"] | "\\" _)* '"'? | "'" (![\\\n'] | "\\" _)* "'"? } //!operatorTokens ArithOp { expr } LogicOp { expr } UpdateOp { $[+\-/%*] "=" } CompareOp { ("<" | ">" | "==" | "!=") "="? } //!regexpTokens RegExp { "/" (![/\\\n[] | "\\" ![\n] | "[" (![\n\\\]] | "\\" ![\n])* "]")+ ("/" $[gimsuy]*)? } //!literalTokens "=" "..." "=>" "(" ")" "[" "]" "{" "}" "." "," ";" ":" } //!insertSemicolon @external tokens insertSemicolon from "./tokens.js" { insertSemi } //!detectDelim @detectDelim