@precedence { cond, trail, power @right, prefix, times @left, plus @left, shift @left, bitand @left, xor @left, bitor @left, compare @left, as @left, and @left, or @left } @top Script { statement+ } @skip { space | newlineBracketed | Comment | blankLine } Decorator { At dottedName ArgList? newline } FunctionDefinition { kw<"async">? kw<"def"> VariableName TypeParamList? ParamList TypeDef { "->" test }? Body } ParamList { "(" commaSep? ")" } TypeParamList { "[" commaSep "]" } TypeParam { ("*" | "**") VariableName | VariableName TypeDef? } MatchStatement { skw<"match"> "*"? expression MatchBody { ":" newline indent MatchClause+ (dedent | eof) } } MatchClause { skw<"case"> commaSep Guard { kw<"if"> expression }? Body } pattern[@isGroup=Pattern] { CapturePattern { VariableName } | LiteralPattern | AsPattern { pattern !as kw<"as"> VariableName } | OrPattern { pattern (!or LogicOp{"|"} pattern)+ } | AttributePattern | SequencePattern | MappingPattern | StarPattern { "*" !prefix pattern } | ClassPattern { (VariableName | AttributePattern) PatternArgList } } AttributePattern { VariableName ("." PropertyName)+ } LiteralPattern { ArithOp{"-"}? Number (ArithOp{"+"|"-"} Number)? | String | kw<"None"> | @specialize[@name=Boolean] } PatternArgList { "(" commaSep "]" | "(" commaSep ")" } MappingPattern { "{" commaSep<"**" pattern | (VariableName | LiteralPattern) ":" pattern> "}" } ClassDefinition { kw<"class"> VariableName TypeParamList? ArgList? Body } param { VariableName TypeDef? (AssignOp{"="} test)? | "*" VariableName? | "**" VariableName | "/" } TypeDef { ":" test } statement[@isGroup=Statement] { simpleStatement | compoundStatement } simpleStatement { smallStatement (newline | eof) | StatementGroup { smallStatement (";" smallStatement?)+ (newline | eof) } } smallStatement { AssignStatement { expressions (TypeDef? (AssignOp{"="} (YieldExpression | expressions))+ | TypeDef) } | UpdateStatement { expressions UpdateOp (YieldExpression | commaSep) } | ExpressionStatement { expressions } | DeleteStatement { kw<"del"> commaSep } | PassStatement { kw<"pass"> } | BreakStatement { kw<"break"> } | ContinueStatement { kw<"continue"> } | ReturnStatement { kw<"return"> commaSep? } | YieldStatement { yield } | PrintStatement { printKeyword test } | RaiseStatement { kw<"raise"> (test (kw<"from"> test | ("," test ("," test)?))?)? } | ImportStatement | ScopeStatement { (kw<"global"> | kw<"nonlocal">) commaSep } | AssertStatement { kw<"assert"> commaSep } | TypeDefinition { skw<"type"> VariableName TypeParamList? "=" test } } expressions { commaSep<"*" expression | test> } ImportStatement { kw<"import"> (importList | importedNames) | kw<"from"> (("." | "...")+ dottedName? | dottedName) kw<"import"> ("*" | importList | importedNames) } importedNames { commaSep VariableName> } importList[@export] { "(" importedNames ")" } commaSep { expr ("," expr)* ","? } compoundStatement { IfStatement | WhileStatement { kw<"while"> testNamed Body elseClause? } | ForStatement { kw<"async">? kw<"for"> commaSep<"*"? expression> kw<"in"> commaSep Body elseClause? } | TryStatement | WithStatement { kw<"async">? kw<"with"> commaSep VariableName)?> Body } | FunctionDefinition | ClassDefinition | DecoratedStatement { Decorator+ (ClassDefinition | FunctionDefinition) } | MatchStatement } elseClause { kw<"else"> Body } IfStatement { kw<"if"> testNamed Body (kw<"elif"> testNamed? Body)* elseClause? } TryStatement { kw<"try"> Body (kw<"except"> "*"? (test ((kw<"as"> | ",") VariableName)?)? Body)* elseClause? (kw<"finally"> Body)? } Body { ":" (simpleStatement | newline indent statement+ (dedent | eof)) } lambdaParam { VariableName (AssignOp{"="} test)? | "*" VariableName? | "**" VariableName } lambdaParams[@name="ParamList"] { (lambdaParam ("," lambdaParam)*)? } test { testInner | ConditionalExpression { testInner !cond kw<"if"> testInner kw<"else"> test } | LambdaExpression { kw<"lambda"> lambdaParams ":" test } } testNoCond { testInner | LambdaExpression { kw<"lambda"> lambdaParams ":" testNoCond } } testNamed { test | NamedExpression { test AssignOp{":="} test } } testInner { binaryTest | unaryTest | expression } binaryTest[@name="BinaryExpression"] { testInner !or kw<"or"> testInner | testInner !and kw<"and"> testInner | testInner !compare (CompareOp | kw<"in"> | kw<"not"> kw<"in"> | kw<"is"> kw<"not">?) testInner } unaryTest[@name="UnaryExpression"] { kw<"not"> testInner } expression[@isGroup=Expression] { BinaryExpression | UnaryExpression { !prefix (ArithOp{"+" | "-"} | BitOp{"~"}) expression } | AwaitExpression { kw<"await"> expression } | ParenthesizedExpression | TupleExpression | ComprehensionExpression | ArrayExpression | ArrayComprehensionExpression | DictionaryExpression | DictionaryComprehensionExpression | SetExpression | SetComprehensionExpression | CallExpression { expression !trail ArgList } | MemberExpression { expression !trail (subscript | "." PropertyName) } | VariableName | Number | String | FormatString | ContinuedString { (String | FormatString) (String | FormatString)+ } | "..." | kw<"None"> | @specialize[@name=Boolean] } subscript[@export] { "[" commaSep "]" } ParenthesizedExpression { "(" (testNamed | "*" expression | YieldExpression) ")" } TupleExpression { "(" ((testNamed | "*" expression) (("," (testNamed | "*" expression))+ ","? | ","))? ")" } ComprehensionExpression { "(" (testNamed | "*" expression) compFor ")" } ArrayExpression { "[" commaSep? "]" } ArrayComprehensionExpression { "[" (testNamed | "*" expression) compFor "]" } DictionaryExpression { "{" commaSep? "}" } DictionaryComprehensionExpression { "{" (test ":" test | "**" expression) compFor "}" } SetExpression { "{" commaSep "}" } SetComprehensionExpression { "{" (test | "*" expression) compFor "}" } yield { kw<"yield"> (kw<"from"> test | commaSep) } YieldExpression { yield } BinaryExpression { expression !bitor BitOp{"|"} expression | expression !xor BitOp{"^"} expression | expression !bitand BitOp{"&"} expression | expression !shift BitOp{"<<" | ">>"} expression | expression !plus ArithOp{"+" | "-"} expression | expression !times ArithOp{"*" | "@" | "/" | "%" | "//"} expression | expression !power ArithOp{"**"} expression } ArgList { "(" commaSep? ")" } argument { test compFor? | VariableName AssignOp{"=" | ":="} test compFor? | "**" test | "*" test } compFor { kw<"async">? kw<"for"> commaSep kw<"in"> testInner (compFor | compIf)? } compIf { kw<"if"> testNoCond (compFor | compIf)? } // FIXME Is it possible to distinguish between VariableName and VariableDefinition? VariableName { identifier } PropertyName { word } dottedName { VariableName ("." VariableName)* } kw { @specialize[@name={term}] } skw { @extend[@name={term}] } @skip {} { String[isolate] { (stringStart | stringStartD | stringStartL | stringStartLD | stringStartR | stringStartRD | stringStartRL | stringStartRLD) (stringContent | Escape)* stringEnd } FormatString[isolate] { (stringStartF | stringStartFD | stringStartFL | stringStartFLD | stringStartFR | stringStartFRD | stringStartFRL | stringStartFRLD) (stringContent | Escape | FormatReplacement)* stringEnd } formatStringSpec { FormatSpec { ":" (formatStringSpecChars | nestedFormatReplacement)* } "}" } blankLine { blankLineStart space? Comment? newline } } formatReplacement { start (YieldExpression | commaSep<"*"? test>) FormatSelfDoc {"="}? FormatConversion? (formatStringSpec | "}") } FormatReplacement[isolate] { formatReplacement } nestedFormatReplacement[isolate,@name=FormatReplacement,@export] { formatReplacement<"{"> } @context trackIndent from "./tokens.js" @external tokens legacyPrint from "./tokens.js" { printKeyword[@name="print"] } @external tokens indentation from "./tokens" { indent, dedent } @external tokens newlines from "./tokens" { newline, blankLineStart, newlineBracketed, eof } @external tokens strings from "./tokens" { stringContent Escape replacementStart[@name="{"] stringEnd } @tokens { CompareOp { "<" | ">" | $[<>=!] "=" | "<>" } UpdateOp { ($[+\-@%&|^] | "<<" | ">>" | "*" "*"? | "/" "/"?) "=" } // String types are identified by letter suffixes: // D: double quoted // L: long string // R: raw string // F: format string stringStart[@export] { stringPrefix? "'" } stringStartD[@export] { stringPrefix? '"' } stringStartL[@export] { stringPrefix? "'''" } stringStartLD[@export] { stringPrefix? '"""' } stringStartR[@export] { stringPrefixR "'" } stringStartRD[@export] { stringPrefixR '"' } stringStartRL[@export] { stringPrefixR "'''" } stringStartRLD[@export] { stringPrefixR '"""' } stringStartF[@export] { stringPrefixF "'" } stringStartFD[@export] { stringPrefixF '"' } stringStartFL[@export] { stringPrefixF "'''" } stringStartFLD[@export] { stringPrefixF '"""' } stringStartFR[@export] { stringPrefixFR "'" } stringStartFRD[@export] { stringPrefixFR '"' } stringStartFRL[@export] { stringPrefixFR "'''" } stringStartFRLD[@export] { stringPrefixFR '"""' } stringPrefix { $[uUbB] } stringPrefixR { $[rR] $[bB]? | $[bB] $[rR] } stringPrefixF { $[fF] } stringPrefixFR { $[rR] $[fF] | $[fF] $[rR] } // Give string quotes a higher precedence than identifiers, and long // strings a higher precedence than short strings @precedence { stringStartL, stringStart, identifier } @precedence { stringStartLD, stringStartD, identifier } @precedence { stringStartRL, stringStartR, identifier } @precedence { stringStartRLD, stringStartRD, identifier } @precedence { stringStartFL, stringStartF, identifier } @precedence { stringStartFLD, stringStartFD, identifier } @precedence { stringStartFRL, stringStartFR, identifier } @precedence { stringStartFRLD, stringStartFRD, identifier } identifierChar { @asciiLetter | $[_\u{a1}-\u{10ffff}] } word { identifierChar (@digit | identifierChar)* } identifier { word } FormatConversion { "!" $[sra] } formatStringSpecChars { ![{}]+ } Number { (@digit ("_" | @digit)* ("." @digit ("_" | @digit)*)? | "." @digit ("_" | @digit)*) ($[eE] $[+\-]? @digit ("_" | @digit)*)? $[jJ]? | "0" $[bB] $[_01]+ | "0" $[oO] $[_0-7]+ | "0" $[xX] $[_0-9a-fA-F]+ } Comment[isolate] { "#" ![\n\r]* } space { ($[ \t\f] | "\\" $[\n\r])+ } At { "@" } "..."[@name=Ellipsis] "("[@export=ParenL] ")" "["[@export=BracketL] "]" "{"[@export=BraceL] "}" "." "," ";" ":" "@" "*" "**" } @external propSource pythonHighlighting from "./highlight" @detectDelim