include "./jsdoc.grammar" as doccomment skip whitespace { start top { whitespace Statement* } context Statement { var VariableDeclarator ("," VariableDeclarator)* semi | (while | with) CondExpr Statement | do Statement (while CondExpr semi)? | Block | ";" | debugger | Conditional | function asyncStar? declName FunctionDef | for ForStatement | Label | return (semi | Expression semi) | throw Expression semi | breakCont identifier? semi | switch CondExpr Block | try Block CatchFinally | class typeDeclName ClassDef | Export | Import | async Statement | Decorator | Expression semi } VariableDeclarator { Pattern (op("=") ExpressionNoComma)? } context Block { "{" Statement* "}" } Label { (default | labelName | case Expression) ":" } context ForStatement { ForSpec Statement } context ForSpec { "(" StatementMaybeOf (Expression? ";" Expression?)? ")" } context StatementMaybeOf { Statement (kw("of") Expression)? } context CatchFinally { (catch ("(" Pattern ")")? Block)? (finally Block)? } Export { export (("*" | default | "{" CommaSep(DeclMaybeAs) "}") (kw("from") string)? semi | Statement) } Import { import (string | ((asyncStar (kw("as") declName)? | DeclMaybeAs | "{" CommaSep(DeclMaybeAs) "}") (kw("from") string)?)) semi } DeclMaybeAs { variableAs kw("as") declName | declName } Expression { BaseExpression ("," ExpressionNoComma | ExpressionSuffix(Expression))* } ExpressionNoComma { BaseExpression ExpressionSuffix(ExpressionNoComma)* } context ParenExpr { "(" Expression ")" } context CondExpr { "(" Expression ")" } BaseExpression { atom | kwExpr | (kwPrefix | prefixOp | async) BaseExpression | NewExpression | function asyncStar? declName? FunctionDef | class (!kw("extends") typeDeclName)? ClassDef | ArrowFunc | Callee | variable | number | string | regexp | template | ArrayLiteral | ObjectLiteral | ParenExpr } Callee { calleeName } context NewExpression { new ("." kw("target") | BaseExpression (ArgList | "." (calleeProp | propName))*) } context ArrowFunc { (declNameAndArrow | ParamsAndArrow) ArrowRest } context ArrowRest { op("=>") (Block | ExpressionNoComma) } context ArrayLiteral { "[" CommaSep(ExpressionNoComma) "]" } context ObjectLiteral { "{" CommaSep(ObjectMember) "}" } context ObjectMember { propModifier? asyncStar? ((propDeclName | "[" Expression "]" | number | string) (FunctionDef | ":" ExpressionNoComma)? | op("...") ExpressionNoComma) } ExpressionSuffix(ContExpression) { suffixOp | (binOp | kwBinOp) ContExpression | ArgList | template | ("." | "?.") (calleeProp | propName) | "[" Expression "]" | op("?") Expression op(":") ContExpression } context ArgList { "(" CommaSep(ExpressionNoComma) ")" } context ParamList { "(" CommaSep(PatternDefault) ")" } context FunctionDef { ParamList Block } ClassDef { (extends Expression)? ClassBody } context ClassBody { "{" (kw("static")? ObjectMember | Decorator)* "}" } Decorator { "@" Expression } Pattern { op("...")? (declName | ArrayPattern | ObjectPattern) } PatternDefault { Pattern (op("=") ExpressionNoComma)? } context ArrayPattern { "[" CommaSep(PatternDefault?) "]" } context ObjectPattern { "{" CommaSep(PropPattern) "}" } PropPattern { declNameNoColon (op("=") ExpressionNoComma)? | (propName | number | string) ":" PatternDefault | op("...") PatternDefault } CommaSep(expr) { (expr ("," expr?)*)? } ParamsAndArrow { ~(ParamList "=>") ParamList } } Conditional { if whitespace CondExpr whitespace Statement Alternative } context Alternative { whitespace (else whitespace Statement)? } tokens { var { kw("var" | "let" | "const") } while { kw("while") } with { kw("with") } else { kw("else") } do { kw("do") } try { kw("try") } finally { kw("finally") } return { kw("return") } throw { kw("throw") } breakCont { kw("break" | "continue") } debugger { kw("debugger") } case { kw("case") } default { kw("default") } function { kw("function") } if { kw("if") } catch { kw("catch") } for { kw("for") } switch { kw("switch") } class { kw("class") } export { kw("export") } import { kw("import") } extends { kw("extends") } async { kw("async") ~(whitespace (function | identifier | "(")) } new { kw("new") } kwBinOp { kw("in" | "instanceof") } kwPrefix { kw("delete" | "typeof" | "yield" | "await" | "void") } kwExpr { kw("super" | "this") } atom="atom" { ("true" | "false" | "null" | "undefined" | "NaN" | "Infinity") !identifierChar } variable="variable" { identifier } prefixOp="operator" { "..." | "!" | "+" "+"? | "-" "-"? } binOp="operator" { ("+" | "-" | "%" | "*" | slash | ">" ">"? ">"? | "<" "<"? | "=" "="? | "&" "&"? | "|" "|"? | "^" | "!=") "="? | "??" } suffixOp="operator" { "++" | "--" } string="string" { "'" ("\\" _ | (!"'" .))* "'" | "\"" ("\\" _ | (!"\"" .))* "\"" } number="number" { "0x" (digit | "a"-"f" | "A"-"F" | "_")+ | "0o" ("0"-"7" | "_")+ | "0b" ("0" | "1" | "_")+ | (digit (digit | "_")* ("." (digit | "_")*)? | "." (digit | "_")+) (("e" | "E") ("+" | "-")? (digit | "_")+)? } comment="comment" { doccomment.comment | "/*" (!"*/" _)* "*/" | "//" .* } regexp="string-2" { slash ("\\" . | "[" (!"]" .)* "]" | !"/" .)+ "/" ("g" | "i" | "m" | "y" | "u" | "s")* } template { str2("`") (str2("${") Expression str2("}") | str2("\\" _ | "\n") | str2((!("`" | "${" | "\\") .)+))* str2("`") } } whitespace { (spaceChar | comment)* } kw(value)="keyword" { value !identifierChar } op(value)="operator" { value } str2(value)="string-2" { value } propName="property" { identifier } propDeclName="def property" { identifier } declName="def" { identifier } typeDeclName="type def" { identifier } calleeName="variable callee" { identifier ~(" "* "(") } calleeProp="property callee" { identifier ~(" "* "(") } labelName { identifier ~(" "* ":") } declNameNoColon { declName !(identifierChar | " "* ":") } declNameAndArrow { declName ~(whitespace "=>") } propModifier { kw("get" | "set" | "async") !(" "* ("," | "}" | ":" | "(")) } asyncStar="keyword" { "*" } variableAs { variable ~(" "+ "as") } identifier { identifierStart identifierChar* } semi { ";" | ~"}" | &canInsertSemi } letter { "a"-"z" | "A"-"Z" | "\u00a1"-"\uffff" | "_" } digit { "0"-"9" } identifierStart { letter | "_" | "$" } identifierChar { letter | digit | "_" | "$" } spaceChar { "\n" | "\t" | " " } slash { "/" !("/" | "*") }