| @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<param>? ")" } | |
| TypeParamList { "[" commaSep<TypeParam> "]" } | |
| TypeParam { | |
| ("*" | "**") VariableName | | |
| VariableName TypeDef? | |
| } | |
| MatchStatement { | |
| skw<"match"> "*"? expression MatchBody { ":" newline indent MatchClause+ (dedent | eof) } | |
| } | |
| MatchClause { | |
| skw<"case"> commaSep<pattern> 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]<identifier, "True" | "False"> | |
| } | |
| PatternArgList { "(" commaSep<pattern | KeywordPattern { VariableName "=" pattern }> ")" } | |
| SequencePattern { "[" commaSep<pattern> "]" | "(" commaSep<pattern> ")" } | |
| 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<test>) } | | |
| ExpressionStatement { expressions } | | |
| DeleteStatement { kw<"del"> commaSep<expression> } | | |
| PassStatement { kw<"pass"> } | | |
| BreakStatement { kw<"break"> } | | |
| ContinueStatement { kw<"continue"> } | | |
| ReturnStatement { kw<"return"> commaSep<test | "*" expression>? } | | |
| YieldStatement { yield } | | |
| PrintStatement { printKeyword test } | | |
| RaiseStatement { kw<"raise"> (test (kw<"from"> test | ("," test ("," test)?))?)? } | | |
| ImportStatement | | |
| ScopeStatement { (kw<"global"> | kw<"nonlocal">) commaSep<VariableName> } | | |
| AssertStatement { kw<"assert"> commaSep<test> } | | |
| 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<dottedName | dottedName kw<"as"> VariableName> } | |
| importList[@export] { "(" importedNames ")" } | |
| commaSep<expr> { expr ("," expr)* ","? } | |
| compoundStatement { | |
| IfStatement | | |
| WhileStatement { kw<"while"> testNamed Body elseClause? } | | |
| ForStatement { kw<"async">? kw<"for"> commaSep<"*"? expression> kw<"in"> commaSep<test> Body elseClause? } | | |
| TryStatement | | |
| WithStatement { kw<"async">? kw<"with"> commaSep<test (kw<"as"> 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]<identifier, "True" | "False"> | |
| } | |
| subscript[@export] { | |
| "[" commaSep<testNamed | testNamed? ":" testNamed? (":" testNamed?)?> "]" | |
| } | |
| ParenthesizedExpression { "(" (testNamed | "*" expression | YieldExpression) ")" } | |
| TupleExpression { "(" ((testNamed | "*" expression) (("," (testNamed | "*" expression))+ ","? | ","))? ")" } | |
| ComprehensionExpression { "(" (testNamed | "*" expression) compFor ")" } | |
| ArrayExpression { "[" commaSep<testNamed | "*" expression>? "]" } | |
| ArrayComprehensionExpression { "[" (testNamed | "*" expression) compFor "]" } | |
| DictionaryExpression { "{" commaSep<test ":" test | "**" expression>? "}" } | |
| DictionaryComprehensionExpression { "{" (test ":" test | "**" expression) compFor "}" } | |
| SetExpression { "{" commaSep<test | "*" expression> "}" } | |
| SetComprehensionExpression { "{" (test | "*" expression) compFor "}" } | |
| yield { kw<"yield"> (kw<"from"> test | commaSep<test | "*" expression>) } | |
| 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>? ")" } | |
| argument { test compFor? | VariableName AssignOp{"=" | ":="} test compFor? | "**" test | "*" test } | |
| compFor { | |
| kw<"async">? kw<"for"> commaSep<expression> 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<term> { @specialize[@name={term}]<identifier, term> } | |
| skw<term> { @extend[@name={term}]<identifier, 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> { | |
| start | |
| (YieldExpression | commaSep<"*"? test>) | |
| FormatSelfDoc {"="}? | |
| FormatConversion? | |
| (formatStringSpec | "}") | |
| } | |
| FormatReplacement[isolate] { formatReplacement<replacementStart> } | |
| 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 | |