hydra-0.5.0: src/main/haskell/Hydra/Sources/Tier4/Langs/Python/Python3.hs
{-# LANGUAGE OverloadedStrings #-}
module Hydra.Sources.Tier4.Langs.Python.Python3 (python3Module) where
import Hydra.Kernel
import Hydra.Dsl.Grammars
import Hydra.Tools.GrammarToModule
import qualified Hydra.Dsl.Annotations as Ann
import qualified Hydra.Grammar as G
import qualified Data.List as L
python3Module :: Module
python3Module = grammarToModule ns python3Grammar $
Just "A Python 3 syntax model, based on the BNF/PEG grammar at https://docs.python.org/3/reference/grammar.html as of 2023-04-03."
where
ns = Namespace "hydra/langs/python/python3"
python3Grammar :: G.Grammar
python3Grammar = G.Grammar $ tokens ++ productions
amp_ = terminal "&"
assign_ = terminal ":="
star_ = terminal "*"
at_ = terminal "@"
close_curly_ = terminal "}"
close_paren_ = terminal ")"
close_square_ = terminal "]"
colon_ = terminal ":"
comma_ = terminal ","
dot_ = terminal "."
double_equal_ = terminal "=="
double_gt_ = terminal ">>"
double_lt_ = terminal "<<"
double_slash_ = terminal "//"
double_star_ = terminal "**"
ellipsis_ = terminal "..."
endmarker_ = terminal ""
equal_ = terminal "="
gt_ = terminal ">"
gte_ = terminal ">="
hat_ = terminal "^"
lt_ = terminal "<"
lte_ = terminal "<="
minus_ = terminal "-"
newline_ = terminal "\n"
noteq_ = terminal "!="
open_curly_ = terminal "{"
open_paren_ = terminal "("
open_square_ = terminal "["
percent_ = terminal "%"
pipe_ = terminal "|"
plus_ = terminal "+"
right_arrow_ = terminal "->"
semi_ = terminal ";"
slash_ = terminal "/"
tilde_ = terminal "~"
underscore_ = terminal "_"
tokens :: [G.Production]
tokens = [
define "Async" [terminal "async"], -- TODO: not specified in the BNF
define "Await" [terminal "await"], -- TODO: not specified in the BNF
define "Dedent" [terminal "\n"], -- TODO: not specified in the BNF
define "Indent" [terminal "\t"], -- TODO: not specified in the BNF
define "Name" [regex "[A-Za-z0-9][A-Za-z0-9_]*"], -- TODO: not specified in the BNF
define "Number" [regex "[0-9]+"], -- TODO: not specified in the BNF
define "String" [regex "\"[^\"]*\""], -- TODO: not specified in the BNF
define "TypeComment" [terminal ""]] -- TODO: not specified in the BNF
productions :: [G.Production]
productions = [
-- # STARTING RULES
-- # ==============
-- file: [statements] ENDMARKER
define "File" [
star "Statement"],
-- interactive: statement_newline
define "Interactive" [
"StatementNewline"],
-- eval: expressions NEWLINE* ENDMARKER
define "Eval" [
list[sepp comma_ "Expression", star newline_]],
-- func_type: '(' [type_expressions] ')' '->' expression NEWLINE* ENDMARKER
define "FuncType" [open_paren_, opt "TypeExpressions", close_paren_, right_arrow_, star newline_, endmarker_],
-- fstring: star_expressions
define "Fstring" [
sepp comma_ "StarExpression"],
-- # GENERAL STATEMENTS
-- # ==================
-- statements: statement+
-- statement: compound_stmt | simple_stmts
define "Statement" [
"CompoundStmt",
"SimpleStmts"],
-- statement_newline:
-- | compound_stmt NEWLINE
-- | simple_stmts
-- | NEWLINE
-- | ENDMARKER
define "StatementNewline" [
list["CompoundStmt", newline_],
"SimpleStmts",
newline_,
endmarker_],
-- simple_stmts:
-- | simple_stmt !';' NEWLINE # Not needed, there for speedup
-- | ';'.simple_stmt+ [';'] NEWLINE
define "SimpleStmts" [
list ["SimpleStmt", star(list[semi_, dot_, "SimpleStmt"]), newline_]],
-- # NOTE: assignment MUST precede expression, else parsing a simple assignment
-- # will throw a SyntaxError.
-- simple_stmt:
-- | assignment
-- | star_expressions
-- | return_stmt
-- | import_stmt
-- | raise_stmt
-- | 'pass'
-- | del_stmt
-- | yield_stmt
-- | assert_stmt
-- | 'break'
-- | 'continue'
-- | global_stmt
-- | nonlocal_stmt
define "SimpleStmt" [
"Assignment",
sepp comma_ "StarExpression",
"ReturnStmt",
"ImportStmt",
"RaiseStmt",
terminal "pass",
"DelStmt",
"YieldStmt",
"AssertStmt",
terminal "break",
terminal "continue",
"GlobalStmt",
"NonlocalStmt"],
-- compound_stmt:
-- | function_def
-- | if_stmt
-- | class_def
-- | with_stmt
-- | for_stmt
-- | try_stmt
-- | while_stmt
-- | match_stmt
define "CompoundStmt" [
"FunctionDef",
"IfStmt",
"ClassDef",
"WithStmt",
"ForStmt",
"TryStmt",
"WhileStmt",
"MatchStmt"],
-- # SIMPLE STATEMENTS
-- # =================
-- # NOTE: annotated_rhs may start with 'yield'; yield_expr must start with 'yield'
-- assignment:
-- | NAME ':' expression ['=' annotated_rhs ]
-- | ('(' single_target ')'
-- | single_subscript_attribute_target) ':' expression ['=' annotated_rhs ]
-- | (star_targets '=' )+ (yield_expr | star_expressions) !'=' [TYPE_COMMENT]
-- | single_target augassign ~ (yield_expr | star_expressions)
define "Assignment" [
list["Name", colon_, "Expression", opt(list[equal_, "AnnotatedRhs"])],
list[alts[list[open_paren_, "SingleTarget", close_paren_], "SingleSubscriptAttributeTarget"], colon_, "Expression", opt(list[equal_, "AnnotatedRhs"])],
list[plus(list[sepp comma_ "StarTarget", equal_]), alts["YieldExpr", sepp comma_ "StarExpression"], opt("TypeComment")],
list["SingleTarget", "Augassign", tilde_, alts["YieldExpr", sepp comma_ "StarExpression"]]],
-- annotated_rhs: yield_expr | star_expressions
define "AnnotatedRhs" [
"YieldExpr",
sepp comma_ "StarExpression"],
-- augassign:
-- | '+='
-- | '-='
-- | '*='
-- | '@='
-- | '/='
-- | '%='
-- | '&='
-- | '|='
-- | '^='
-- | '<<='
-- | '>>='
-- | '**='
-- | '//='
define "Augassign" [
terminal "+=",
terminal "-=",
terminal "*=",
terminal "@=",
terminal "/=",
terminal "%=",
terminal "&=",
terminal "|=",
terminal "^=",
terminal "<<=",
terminal ">>=",
terminal "**=",
terminal "//="],
-- return_stmt:
-- | 'return' [star_expressions]
define "ReturnStmt" [
list [terminal "return", opt(sepp comma_ "StarExpression")]],
-- raise_stmt:
-- | 'raise' expression ['from' expression ]
-- | 'raise'
define "RaiseStmt" [
list[terminal "raise", "Expression", opt(list[terminal "from", "Expression"])],
terminal "raise"],
-- global_stmt: 'global' ','.NAME+
define "GlobalStmt" [
list[terminal "global", comma_, dot_, plus(list[dot_, "Name"])]], -- Note: interpreting the above as (.NAME)+, not .(Name+)
-- nonlocal_stmt: 'nonlocal' ','.NAME+
define "NonlocalStmt" [
list[terminal "nonlocal", comma_, plus(list[dot_, "Name"])]], -- Note: interpreting the above as (.NAME)+, not .(Name+)
-- del_stmt:
-- | 'del' del_targets &(';' | NEWLINE)
define "DelStmt" [
list[terminal "del", "DelTargets"]],
-- yield_stmt: yield_expr
define "YieldStmt" [
"YieldExpr"],
-- assert_stmt: 'assert' expression [',' expression ]
define "AssertStmt" [
list[terminal "assert", "Expression", opt(list[comma_, "Expression"])]],
-- import_stmt: import_name | import_from
define "ImportStmt" [
"ImportName",
"ImportFrom"],
-- # Import statements
-- # -----------------
-- import_name: 'import' dotted_as_names
define "ImportName" [
list[terminal "import", sep comma_ "DottedAsName"]],
-- # note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
-- import_from:
-- | 'from' ('.' | '...')* dotted_name 'import' import_from_targets
-- | 'from' ('.' | '...')+ 'import' import_from_targets
define "ImportFrom" [
list[terminal "from", star(alts[dot_, ellipsis_]), "DottedName", terminal "import", "ImportFromTargets"],
list[terminal "from", plus(alts[dot_, ellipsis_]), terminal "import", "ImportFromTargets"]],
-- import_from_targets:
-- | '(' import_from_as_names [','] ')'
-- | import_from_as_names !','
-- | '*'
define "ImportFromTargets" [
list[open_paren_, "ImportFromAsNames", opt(comma_), close_paren_],
"ImportFromAsNames"],
-- import_from_as_names:
-- | ','.import_from_as_name+
define "ImportFromAsNames" [
list[comma_, plus(list[dot_, "ImportFromAsName"])]], -- Note: interpreting the above as (.import_from_as_name)+, not .(import_from_as_name+)
-- import_from_as_name:
-- | NAME ['as' NAME ]
define "ImportFromAsName" [
list["Name", opt(list[terminal "as", "Name"])]],
-- dotted_as_names:
-- | ','.dotted_as_name+
-- dotted_as_name:
-- | dotted_name ['as' NAME ]
define "DottedAsName" [
list["DottedName", opt(list[terminal "as", "Name"])]],
-- dotted_name:
-- | dotted_name '.' NAME
-- | NAME
define "DottedName" [
sep dot_ "Name"],
-- # COMPOUND STATEMENTS
-- # ===================
-- # Common elements
-- # ---------------
-- block:
-- | NEWLINE INDENT statements DEDENT
-- | simple_stmts
define "Block" [
list[newline_, "Indent", star "Statement", "Dedent"],
"SimpleStmts"],
-- decorators: ('@' named_expression NEWLINE )+
define "Decorators" [
plus(list[at_, "NamedExpression", newline_])],
-- # Class definitions
-- # -----------------
-- class_def:
-- | decorators class_def_raw
-- | class_def_raw
define "ClassDef" [
list["Decorators", "ClassDefRaw"],
"ClassDefRaw"],
-- class_def_raw:
-- | 'class' NAME ['(' [arguments] ')' ] ':' block
define "ClassDefRaw" [
list[terminal "class", "Name", opt(list[open_paren_, opt("Arguments"), close_paren_]), colon_, "Block"]],
-- # Function definitions
-- # --------------------
-- function_def:
-- | decorators function_def_raw
-- | function_def_raw
define "FunctionDef" [
list["Decorators", "FunctionDefRaw"],
"FunctionDefRaw"],
-- function_def_raw:
-- | 'def' NAME '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
-- | ASYNC 'def' NAME '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
define "FunctionDefRaw" [
list[
opt(list["Async", terminal "def"]), "Name",
open_paren_, opt("Parameters"), close_paren_,
opt(list[right_arrow_, "Expression"]),
colon_, opt("FuncTypeComment"), "Block"]],
-- # Function parameters
-- # -------------------
-- params:
-- | parameters
-- parameters:
-- | slash_no_default param_no_default* param_with_default* [star_etc]
-- | slash_with_default param_with_default* [star_etc]
-- | param_no_default+ param_with_default* [star_etc]
-- | param_with_default+ [star_etc]
-- | star_etc
define "Parameters" [
list["SlashNoDefault", star("ParamNoDefault"), star("ParamWithDefault"), opt("StarEtc")],
list["SlashWithDefault", star("ParamWithDefault"), opt("StarEtc")],
list[plus("ParamNoDefault"), star("ParamWithDefault"), opt("StarEtc")],
list[plus("ParamWithDefault"), opt("StarEtc")],
"StarEtc"],
-- # Some duplication here because we can't write (',' | &')'),
-- # which is because we don't support empty alternatives (yet).
-- slash_no_default:
-- | param_no_default+ '/' ','
-- | param_no_default+ '/' &')'
define "SlashNoDefault" [
list[plus("ParamNoDefault"), slash_, opt(comma_)]],
-- slash_with_default:
-- | param_no_default* param_with_default+ '/' ','
-- | param_no_default* param_with_default+ '/' &')'
define "SlashWithDefault" [
list[star("ParamNoDefault"), plus("ParamWithDefault"), slash_, opt(comma_)]],
-- star_etc:
-- | '*' param_no_default param_maybe_default* [kwds]
-- | '*' param_no_default_star_annotation param_maybe_default* [kwds]
-- | '*' ',' param_maybe_default+ [kwds]
-- | kwds
define "StarEtc" [
list[star_, "ParamNoDefault", star("ParamMaybeDefault"), opt("Kwds")],
list[star_, "ParamNoDefaultStarAnnotation", star("ParamMaybeDefault"), opt("Kwds")],
list[star_, comma_, plus("ParamMaybeDefault"), opt("Kwds")],
"Kwds"],
-- kwds:
-- | '**' param_no_default
define "Kwds" [
list[double_star_, "ParamNoDefault"]],
-- # One parameter. This *includes* a following comma and type comment.
-- #
-- # There are three styles:
-- # - No default
-- # - With default
-- # - Maybe with default
-- #
-- # There are two alternative forms of each, to deal with type comments:
-- # - Ends in a comma followed by an optional type comment
-- # - No comma, optional type comment, must be followed by close paren
-- # The latter form is for a final parameter without trailing comma.
-- #
--
-- param_no_default:
-- | param ',' TYPE_COMMENT?
-- | param TYPE_COMMENT? &')'
define "ParamNoDefault" [
list["Param", opt(comma_), opt("TypeComment")]],
-- param_no_default_star_annotation::r
-- | param_star_annotation ',' TYPE_COMMENT?
-- | param_star_annotation TYPE_COMMENT? &')'
define "ParamNoDefaultStarAnnotation" [
list["ParamStarAnnotation", opt(comma_), opt("TypeComment")]],
-- param_with_default:
-- | param default ',' TYPE_COMMENT?
-- | param default TYPE_COMMENT? &')'
define "ParamWithDefault" [
list["Param", "Default", opt(comma_), opt("TypeComment")]],
-- param_maybe_default:
-- | param default? ',' TYPE_COMMENT?
-- | param default? TYPE_COMMENT? &')'
define "ParamMaybeDefault" [
list["Param", opt("Default"), opt(comma_), opt("TypeComment")]],
-- param: NAME annotation?
define "Param" [
list["Name", opt("Annotation")]],
-- param_star_annotation: NAME star_annotation
define "ParamStarAnnotation" [
list["Name", "StarAnnotation"]],
-- annotation: ':' expression
define "Annotation" [
list[colon_, "Expression"]],
-- star_annotation: ':' star_expression
define "StarAnnotation" [
list[colon_, "StarExpression"]],
-- default: '=' expression | invalid_default
define "Default" [
list[equal_, "Expression"]],
-- "InvalidDefault"], -- TODO: invalid_default is referenced but not defined in the source grammar
-- # If statement
-- # ------------
-- if_stmt:
-- | 'if' named_expression ':' block elif_stmt
-- | 'if' named_expression ':' block [else_block]
define "IfStmt" [
list[terminal "if", "NamedExpression", colon_, "Block", alts["ElifStmt", "ElseBlock"]]],
-- elif_stmt:
-- | 'elif' named_expression ':' block elif_stmt
-- | 'elif' named_expression ':' block [else_block]
define "ElifStmt" [
list[terminal "elif", "NamedExpression", colon_, "Block", alts["ElifStmt", "ElseBlock"]]],
-- else_block:
-- | 'else' ':' block
define "ElseBlock" [
list[terminal "else", colon_, "Block"]],
-- # While statement
-- # ---------------
-- while_stmt:
-- | 'while' named_expression ':' block [else_block]
define "WhileStmt" [
list[terminal "while", "NamedExpression", colon_, "Block", opt("ElseBlock")]],
-- # For statement
-- # -------------
-- for_stmt:
-- | 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]
-- | ASYNC 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]
define "ForStmt" [
list[opt("Async"), terminal "for", sepp comma_ "StarTarget", terminal "in", tilde_, sepp comma_ "StarExpression", colon_, opt("TypeComment"), "Block", opt("ElseBlock")]],
-- # With statement
-- # --------------
-- with_stmt:
-- | 'with' '(' ','.with_item+ ','? ')' ':' block
-- | 'with' ','.with_item+ ':' [TYPE_COMMENT] block
-- | ASYNC 'with' '(' ','.with_item+ ','? ')' ':' block
-- | ASYNC 'with' ','.with_item+ ':' [TYPE_COMMENT] block
define "WithStmt" [
list[opt("Async"), terminal "with", alts[
list[open_paren_, sepp comma_ "WithItem", close_paren_, colon_],
list[sepp comma_ "WithItem", colon_, opt("TypeComment")]], "Block"]],
-- with_item:
-- | expression 'as' star_target &(',' | ')' | ':')
-- | expression
define "WithItem" [
list["Expression", opt(list[terminal "as", "StarTarget"])]],
-- # Try statement
-- # -------------
-- try_stmt:
-- | 'try' ':' block finally_block
-- | 'try' ':' block except_block+ [else_block] [finally_block]
-- | 'try' ':' block except_star_block+ [else_block] [finally_block]
define "TryStmt" [
list[terminal "try", colon_, "Block", alts[
"FinallyBlock",
list[plus("ExceptBlock"), opt("ElseBlock"), opt("FinallyBlock")],
list[plus("ExceptStarBlock"), opt("ElseBlock"), opt("FinallyBlock")]]]],
-- # Except statement
-- # ----------------
-- except_block:
-- | 'except' expression ['as' NAME ] ':' block
-- | 'except' ':' block
define "ExceptBlock" [
list[terminal "except", opt(list["Expression", opt(list[terminal "as", "Name"])]), colon_, "Block"]],
-- except_star_block:
-- | 'except' '*' expression ['as' NAME ] ':' block
define "ExceptStarBlock" [
list[terminal "except", star_, "Expression", opt(list[terminal "as", "Name"]), colon_, "Block"]],
-- finally_block:
-- | 'finally' ':' block
define "FinallyBlock" [
list[terminal "finally", colon_, "Block"]],
-- # Match statement
-- # ---------------
-- match_stmt:
-- | "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
define "MatchStmt" [
list[terminal "match", "SubjectExpr", colon_, newline_, "Indent", plus("CaseBlock"), "Dedent"]],
-- subject_expr:
-- | star_named_expression ',' star_named_expressions?
-- | named_expression
define "SubjectExpr" [
list["StarNamedExpression", comma_, opt(sepp comma_ "StarNamedExpression")]],
-- case_block:
-- | "case" patterns guard? ':' block
define "CaseBlock" [
list[terminal "case", "Patterns", opt("Guard"), colon_, "Block"]],
-- guard: 'if' named_expression
define "Guard" [
list[terminal "if", "NamedExpression"]],
-- patterns:
-- | open_sequence_pattern
-- | pattern
define "Patterns" [
"OpenSequencePattern",
"Pattern"],
-- pattern:
-- | as_pattern
-- | or_pattern
define "Pattern" [
"AsPattern",
"OrPattern"],
-- as_pattern:
-- | or_pattern 'as' pattern_capture_target
define "AsPattern" [
list["OrPattern", terminal "as", "PatternCaptureTarget"]],
-- or_pattern:
-- | '|'.closed_pattern+
define "OrPattern" [
list[pipe_, sep dot_ "ClosedPattern"]],
-- closed_pattern:
-- | literal_pattern
-- | capture_pattern
-- | wildcard_pattern
-- | value_pattern
-- | group_pattern
-- | sequence_pattern
-- | mapping_pattern
-- | class_pattern
define "ClosedPattern" [
"LiteralPattern",
"CapturePattern",
"WildcardPattern",
"ValuePattern",
"GroupPattern",
"SequencePattern",
"MappingPattern",
"ClassPattern"],
-- # Literal patterns are used for equality and identity constraints
-- literal_pattern:
-- | signed_number !('+' | '-')
-- | complex_number
-- | strings
-- | 'None'
-- | 'True'
-- | 'False'
define "LiteralPattern" [
"SignedNumber",
"ComplexNumber",
plus("String"),
terminal "None",
terminal "True",
terminal "False"],
-- # Literal expressions are used to restrict permitted mapping pattern keys
-- literal_expr:
-- | signed_number !('+' | '-')
-- | complex_number
-- | strings
-- | 'None'
-- | 'True'
-- | 'False'
-- complex_number:
-- | signed_real_number '+' imaginary_number
-- | signed_real_number '-' imaginary_number
define "ComplexNumber" [
list["SignedRealNumber", alts[plus_, minus_], "ImaginaryNumber"]],
-- signed_number:
-- | NUMBER
-- | '-' NUMBER
define "SignedNumber" [
list[opt(minus_), "Number"]],
-- signed_real_number:
-- | real_number
-- | '-' real_number
define "SignedRealNumber" [
list[opt(minus_), "RealNumber"]],
-- real_number:
-- | NUMBER
define "RealNumber" [
"Number"],
-- imaginary_number:
-- | NUMBER
define "ImaginaryNumber" [
"Number"],
-- capture_pattern:
-- | pattern_capture_target
define "CapturePattern" [
"PatternCaptureTarget"],
-- pattern_capture_target:
-- | !"_" NAME !('.' | '(' | '=')
define "PatternCaptureTarget" [
"Name"],
-- wildcard_pattern:
-- | "_"
define "WildcardPattern" [
underscore_],
-- value_pattern:
-- | attr !('.' | '(' | '=')
define "ValuePattern" [
"Attr"],
-- attr:
-- | name_or_attr '.' NAME
define "Attr" [
list["NameOrAttr", dot_, "Name"]],
-- name_or_attr:
-- | attr
-- | NAME
define "NameOrAttr" [
"Attr",
"Name"],
-- group_pattern:
-- | '(' pattern ')'
define "GroupPattern" [
list[open_paren_, "Pattern", close_paren_]],
-- sequence_pattern:
-- | '[' maybe_sequence_pattern? ']'
-- | '(' open_sequence_pattern? ')'
define "SequencePattern" [
list[open_square_, opt("MaybeSequencePattern"), close_square_],
list[open_paren_, opt("MaybeSequencePattern"), close_paren_]],
-- open_sequence_pattern:
-- | maybe_star_pattern ',' maybe_sequence_pattern?
define "OpenSequencePattern" [
list["MaybeStarPattern", comma_, opt("MaybeSequencePattern")]],
-- maybe_sequence_pattern:
-- | ','.maybe_star_pattern+ ','?
define "MaybeSequencePattern" [
seq comma_ "MaybeStarPattern"],
-- maybe_star_pattern:
-- | star_pattern
-- | pattern
define "MaybeStarPattern" [
"StarPattern",
"Pattern"],
-- star_pattern:
-- | '*' pattern_capture_target
-- | '*' wildcard_pattern
define "StarPattern" [
list[star_, alts["PatternCaptureTarget", "WildcardPattern"]]],
-- mapping_pattern:
-- | '{' '}'
-- | '{' double_star_pattern ','? '}'
-- | '{' items_pattern ',' double_star_pattern ','? '}'
-- | '{' items_pattern ','? '}'
define "MappingPattern" [
"empty">: list[open_curly_, close_curly_],
list[open_curly_, "DoubleStarPattern", opt(comma_), close_curly_],
list[open_curly_, "ItemsPattern", comma_, "DoubleStarPattern", opt(comma_), close_curly_],
list[open_curly_, "ItemsPattern", opt(comma_), close_curly_]],
-- items_pattern:
-- | ','.key_value_pattern+
define "ItemsPattern" [
sep comma_ "KeyValuePattern"],
-- key_value_pattern:
-- | (literal_expr | attr) ':' pattern
define "KeyValuePattern" [
list[alts["LiteralPattern", "Attr"], colon_, "Pattern"]],
-- double_star_pattern:
-- | '**' pattern_capture_target
define "DoubleStarPattern" [
list[double_star_, "PatternCaptureTarget"]],
-- class_pattern:
-- | name_or_attr '(' ')'
-- | name_or_attr '(' positional_patterns ','? ')'
-- | name_or_attr '(' keyword_patterns ','? ')'
-- | name_or_attr '(' positional_patterns ',' keyword_patterns ','? ')'
define "ClassPattern" [
list["NameOrAttr", open_paren_, alts[
nil,
list[seq comma_ "Pattern", opt(comma_)],
list[seq comma_ "KeywordPattern", opt(comma_)],
list[seq comma_ "Pattern", comma_, seq comma_ "KeywordPattern", opt(comma_)]
], close_paren_]],
-- positional_patterns:
-- | ','.pattern+
-- keyword_patterns:
-- | ','.keyword_pattern+
-- keyword_pattern:
-- | NAME '=' pattern
define "KeywordPattern" [
list["Name", equal_, "Pattern"]],
-- # EXPRESSIONS
-- # -----------
-- expressions:
-- | expression (',' expression )+ [',']
-- | expression ','
-- | expression
-- expression:
-- | disjunction 'if' disjunction 'else' expression
-- | disjunction
-- | lambdef
define "Expression" [
list["Disjunction", terminal "if", "Disjunction", terminal "else", "Expression"],
"Disjunction",
"Lambdef"],
-- yield_expr:
-- | 'yield' 'from' expression
-- | 'yield' [star_expressions]
define "YieldExpr" [
list[terminal "yield", alts[list[terminal "from", "Expression"], opt(sepp comma_ "StarExpression")]]],
-- star_expressions:
-- | star_expression (',' star_expression )+ [',']
-- | star_expression ','
-- | star_expression
-- star_expression:
-- | '*' bitwise_or
-- | expression
define "StarExpression" [
list[star_, "BitwiseOr"],
"Expression"],
-- star_named_expressions: ','.star_named_expression+ [',']
--
-- star_named_expression:
-- | '*' bitwise_or
-- | named_expression
define "StarNamedExpression" [
list[star_, "BitwiseOr"],
"NamedExpression"],
-- assignment_expression:
-- | NAME ':=' ~ expression
define "AssignmentExpression" [
list["Name", assign_, tilde_, "Expression"]],
-- named_expression:
-- | assignment_expression
-- | expression !':='
define "NamedExpression" [
"AssignmentExpression",
"Expression"],
-- disjunction:
-- | conjunction ('or' conjunction )+
-- | conjunction
define "Disjunction" [
sep (terminal "or") "Conjunction"],
-- conjunction:
-- | inversion ('and' inversion )+
-- | inversion
define "Conjunction" [
sep (terminal "and") "Inversion"],
-- inversion:
-- | 'not' inversion
-- | comparison
define "Inversion" [
list[terminal "not", "Inversion"],
"Comparison"],
-- # Comparison operators
-- # --------------------
-- comparison:
-- | bitwise_or compare_op_bitwise_or_pair+
-- | bitwise_or
define "Comparison" [
list["BitwiseOr", star("CompareOpBitwiseOrPair")]],
-- compare_op_bitwise_or_pair:
-- | eq_bitwise_or
-- | noteq_bitwise_or
-- | lte_bitwise_or
-- | lt_bitwise_or
-- | gte_bitwise_or
-- | gt_bitwise_or
-- | notin_bitwise_or
-- | in_bitwise_or
-- | isnot_bitwise_or
-- | is_bitwise_or
define "CompareOpBitwiseOrPair" [
"EqBitwiseOr",
"NoteqBitwiseOr",
"LteBitwiseOr",
"LtBitwiseOr",
"GteBitwiseOr",
"GtBitwiseOr",
"NotinBitwiseOr",
"InBitwiseOr",
"IsnotBitwiseOr",
"IsBitwiseOr"],
-- eq_bitwise_or: '==' bitwise_or
define "EqBitwiseOr" [
list[double_equal_, "BitwiseOr"]],
-- noteq_bitwise_or:
-- | ('!=' ) bitwise_or
define "NoteqBitwiseOr" [
list[noteq_, "BitwiseOr"]],
-- lte_bitwise_or: '<=' bitwise_or
define "LteBitwiseOr" [
list[lte_, "BitwiseOr"]],
-- lt_bitwise_or: '<' bitwise_or
define "LtBitwiseOr" [
list[lt_, "BitwiseOr"]],
-- gte_bitwise_or: '>=' bitwise_or
define "GteBitwiseOr" [
list[gte_, "BitwiseOr"]],
-- gt_bitwise_or: '>' bitwise_or
define "GtBitwiseOr" [
list[gt_, "BitwiseOr"]],
-- notin_bitwise_or: 'not' 'in' bitwise_or
define "NotinBitwiseOr" [
list[terminal "not", terminal "in", "BitwiseOr"]],
-- in_bitwise_or: 'in' bitwise_or
define "InBitwiseOr" [
list[terminal "in", "BitwiseOr"]],
-- isnot_bitwise_or: 'is' 'not' bitwise_or
define "IsnotBitwiseOr" [
list[terminal "is", terminal "not", "BitwiseOr"]],
-- is_bitwise_or: 'is' bitwise_or
define "IsBitwiseOr" [
list[terminal "is", "BitwiseOr"]],
-- # Bitwise operators
-- # -----------------
-- bitwise_or:
-- | bitwise_or '|' bitwise_xor
-- | bitwise_xor
define "BitwiseOr" [
list[opt(list["BitwiseOr", pipe_]), "BitwiseXor"]],
-- bitwise_xor:
-- | bitwise_xor '^' bitwise_and
-- | bitwise_and
define "BitwiseXor" [
list[opt(list["BitwiseXor", hat_]), "BitwiseAnd"]],
-- bitwise_and:
-- | bitwise_and '&' shift_expr
-- | shift_expr
define "BitwiseAnd" [
list[opt(list["BitwiseAnd", amp_]), "ShiftExpr"]],
-- shift_expr:
-- | shift_expr '<<' sum
-- | shift_expr '>>' sum
-- | sum
define "ShiftExpr" [
list[
opt(list["ShiftExpr", alts[double_lt_, double_gt_]]),
"Sum"]],
-- # Arithmetic operators
-- # --------------------
-- sum:
-- | sum '+' term
-- | sum '-' term
-- | term
define "Sum" [
list[opt(list["Sum", alts[plus_, minus_]]), "Term"]],
-- term:
-- | term '*' factor
-- | term '/' factor
-- | term '//' factor
-- | term '%' factor
-- | term '@' factor
-- | factor
define "Term" [
list[opt(list["Term", alts[star_, slash_, double_slash_, percent_, at_]]), "Factor"]],
-- factor:
-- | '+' factor
-- | '-' factor
-- | '~' factor
-- | power
define "Factor" [
list[alts[plus_, minus_, tilde_], "Factor"],
"Power"],
-- power:
-- | await_primary '**' factor
-- | await_primary
define "Power" [
list["AwaitPrimary", opt(list[double_star_, "Factor"])]],
-- # Primary elements
-- # ----------------
-- # Primary elements are things like "obj.something.something", "obj[something]", "obj(something)", "obj" ...
-- await_primary:
-- | AWAIT primary
-- | primary
define "AwaitPrimary" [
list[opt("Await"), "Primary"]],
-- primary:
-- | primary '.' NAME
-- | primary genexp
-- | primary '(' [arguments] ')'
-- | primary '[' slices ']'
-- | atom
define "Primary" [
list["Primary", alts[
list[dot_, "Name"],
"Genexp",
list[open_paren_, opt("Arguments"), close_paren_],
list[open_square_, "Slices", close_square_]]],
"Atom"],
-- slices:
-- | slice !','
-- | ','.(slice | starred_expression)+ [',']
define "Slices" [
"Slice",
sepp comma_ (alts["Slice", "StarredExpression"])],
-- slice:
-- | [expression] ':' [expression] [':' [expression] ]
-- | named_expression
define "Slice" [
list[opt("Expression"), colon_, opt("Expression"), opt(list[colon_, opt("Expression")])],
"NamedExpression"],
-- atom:
-- | NAME
-- | 'True'
-- | 'False'
-- | 'None'
-- | strings
-- | NUMBER
-- | (tuple | group | genexp)
-- | (list | listcomp)
-- | (dict | set | dictcomp | setcomp)
-- | '...'
define "Atom" [
"Name",
terminal "True",
terminal "False",
terminal "None",
plus("String"),
"Number",
"Tuple",
"Group",
"Genexp",
"List",
"Listcomp",
"Dict",
"Set",
"Dictcomp",
"Setcomp",
ellipsis_],
-- group:
-- | '(' (yield_expr | named_expression) ')'
define "Group" [
list[open_paren_, alts["YieldExpr", "NamedExpression"], close_paren_]],
-- # Lambda functions
-- # ----------------
-- lambdef:
-- | 'lambda' [lambda_params] ':' expression
define "Lambdef" [
list[terminal "lambda", opt("LambdaParameters"), colon_, "Expression"]],
-- lambda_params:
-- | lambda_parameters
-- # lambda_parameters etc. duplicates parameters but without annotations
-- # or type comments, and if there's no comma after a parameter, we expect
-- # a colon, not a close parenthesis. (For more, see parameters above.)
-- #
-- lambda_parameters:
-- | lambda_slash_no_default lambda_param_no_default* lambda_param_with_default* [lambda_star_etc]
-- | lambda_slash_with_default lambda_param_with_default* [lambda_star_etc]
-- | lambda_param_no_default+ lambda_param_with_default* [lambda_star_etc]
-- | lambda_param_with_default+ [lambda_star_etc]
-- | lambda_star_etc
define "LambdaParameters" [
list["LambdaSlashNoDefault", star("LambdaParamNoDefault"), star("LambdaParamWithDefault"), opt("LambdaStarEtc")],
list["LambdaSlashWithDefault", star("LambdaParamWithDefault"), opt("LambdaStarEtc")],
list[plus("LambdaParamNoDefault"), star("LambdaParamWithDefault"), opt("LambdaStarEtc")],
list[plus("LambdaParamWithDefault"), opt("LambdaStarEtc")],
"LambdaStarEtc"],
-- lambda_slash_no_default:
-- | lambda_param_no_default+ '/' ','
-- | lambda_param_no_default+ '/' &':'
define "LambdaSlashNoDefault" [
list[plus("LambdaParamNoDefault"), slash_, opt(comma_)]],
-- lambda_slash_with_default:
-- | lambda_param_no_default* lambda_param_with_default+ '/' ','
-- | lambda_param_no_default* lambda_param_with_default+ '/' &':'
define "LambdaSlashWithDefault" [
list[star("LambdaParamNoDefault"), plus("LambdaParamWithDefault"), slash_, opt(comma_)]],
-- lambda_star_etc:
-- | '*' lambda_param_no_default lambda_param_maybe_default* [lambda_kwds]
-- | '*' ',' lambda_param_maybe_default+ [lambda_kwds]
-- | lambda_kwds
define "LambdaStarEtc" [
list[star_, "LambdaParamNoDefault", star("LambdaParamMaybeDefault"), opt("LambdaKwds")],
list[star_, comma_, plus("LambdaParamMaybeDefault"), opt("LambdaKwds")],
"LambdaKwds"],
-- lambda_kwds:
-- | '**' lambda_param_no_default
define "LambdaKwds" [
list[double_star_, "LambdaParamNoDefault"]],
-- lambda_param_no_default:
-- | lambda_param ','
-- | lambda_param &':'
define "LambdaParamNoDefault" [
list["LambdaParam", opt(comma_)]],
-- lambda_param_with_default:
-- | lambda_param default ','
-- | lambda_param default &':'
define "LambdaParamWithDefault" [
list["LambdaParam", "Default", opt(comma_)]],
-- lambda_param_maybe_default:
-- | lambda_param default? ','
-- | lambda_param default? &':'
define "LambdaParamMaybeDefault" [
list["LambdaParam", opt("Default"), opt(comma_)]],
-- lambda_param: NAME
define "LambdaParam" [
"Name"],
-- # LITERALS
-- # ========
-- strings: STRING+
-- list:
-- | '[' [star_named_expressions] ']'
define "List" [
list[open_square_, sepp comma_ "StarNamedExpression", close_square_]],
-- tuple:
-- | '(' [star_named_expression ',' [star_named_expressions] ] ')'
define "Tuple" [
list[open_paren_, opt(sepp comma_ "StarNamedExpression"), close_paren_]],
-- set: '{' star_named_expressions '}'
define "Set" [
list[open_curly_, sepp comma_ "StarNamedExpression", close_curly_]],
-- # Dicts
-- # -----
-- dict:
-- | '{' [double_starred_kvpairs] '}'
define "Dict" [
list[open_curly_, opt(sepp comma_ "DoubleStarredKvpair"), close_curly_]],
-- double_starred_kvpairs: ','.double_starred_kvpair+ [',']
-- double_starred_kvpair:
-- | '**' bitwise_or
-- | kvpair
define "DoubleStarredKvpair" [
list[double_star_, "BitwiseOr"],
"Kvpair"],
-- kvpair: expression ':' expression
define "Kvpair" [
list["Expression", colon_, "Expression"]],
-- # Comprehensions & Generators
-- # ---------------------------
-- for_if_clauses:
-- | for_if_clause+
-- for_if_clause:
-- | ASYNC 'for' star_targets 'in' ~ disjunction ('if' disjunction )*
-- | 'for' star_targets 'in' ~ disjunction ('if' disjunction )*
define "ForIfClause" [
list[opt("Async"), terminal "for", sepp comma_ "StarTarget", terminal "in", tilde_, "Disjunction", star(list[terminal "if", "Disjunction"])]],
-- listcomp:
-- | '[' named_expression for_if_clauses ']'
define "Listcomp" [
list[open_square_, "NamedExpression", plus("ForIfClause"), close_square_]],
-- setcomp:
-- | '{' named_expression for_if_clauses '}'
define "Setcomp" [
list[open_curly_, "NamedExpression", plus("ForIfClause"), close_curly_]],
-- genexp:
-- | '(' ( assignment_expression | expression !':=') for_if_clauses ')'
define "Genexp" [
list[open_paren_, alts["AssignmentExpression", "Expression"], plus("ForIfClause"), close_paren_]],
-- dictcomp:
-- | '{' kvpair for_if_clauses '}'
define "Dictcomp" [
list[open_curly_, "Kvpair", plus("ForIfClause"), close_curly_]],
-- # FUNCTION CALL ARGUMENTS
-- # =======================
--
-- arguments:
-- | args [','] &')'
define "Arguments" [
list["Args", opt(comma_)]],
-- args:
-- | ','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ [',' kwargs ]
-- | kwargs
define "Args" [
list[sep comma_ (alts["StarredExpression", "AssignmentExpression", "Expression"]), opt(list[comma_, "Kwargs"])],
"Kwargs"],
-- kwargs:
-- | ','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+
-- | ','.kwarg_or_starred+
-- | ','.kwarg_or_double_starred+
define "Kwargs" [
list[comma_, alts[
list[plus(list[dot_, "KwargOrStarred"]), opt(list[comma_, comma_, plus(list[dot_, "KwargOrDoubleStarred"])])],
plus(list[dot_, "KwargOrDoubleStarred"])]]],
-- starred_expression:
-- | '*' expression
define "StarredExpression" [
list[star_, "Expression"]],
-- kwarg_or_starred:
-- | NAME '=' expression
-- | starred_expression
define "KwargOrStarred" [
list["Name", equal_, "Expression"],
"StarredExpression"],
-- kwarg_or_double_starred:
-- | NAME '=' expression
-- | '**' expression
define "KwargOrDoubleStarred" [
list["Name", equal_, "Expression"],
list[double_star_, "Expression"]],
-- # ASSIGNMENT TARGETS
-- # ==================
-- # Generic targets
-- # ---------------
-- # NOTE: star_targets may contain *bitwise_or, targets may not.
-- star_targets:
-- | star_target !','
-- | star_target (',' star_target )* [',']
-- star_targets_list_seq: ','.star_target+ [',']
define "StarTargetsListSeq" [
sepp comma_ (plus(list[dot_, "StarTarget"]))],
-- star_targets_tuple_seq:
-- | star_target (',' star_target )+ [',']
-- | star_target ','
define "StarTargetsTupleSeq" [
sepp comma_ (plus("StarTarget"))],
-- star_target:
-- | '*' (!'*' star_target)
-- | target_with_star_atom
define "StarTarget" [
list[star_, "StarTarget"],
"TargetWithStarAtom"],
-- target_with_star_atom:
-- | t_primary '.' NAME !t_lookahead
-- | t_primary '[' slices ']' !t_lookahead
-- | star_atom
define "TargetWithStarAtom" [
list["TPrimary", dot_, "Name"],
list["TPrimary", open_square_, "Slices", close_square_],
"StarAtom"],
-- star_atom:
-- | NAME
-- | '(' target_with_star_atom ')'
-- | '(' [star_targets_tuple_seq] ')'
-- | '[' [star_targets_list_seq] ']'
define "StarAtom" [
"Name",
list[open_paren_, "TargetWithStarAtom", close_paren_],
list[open_paren_, "StarTargetsTupleSeq", close_paren_],
list[open_square_, "StarTargetsListSeq", close_square_]],
-- single_target:
-- | single_subscript_attribute_target
-- | NAME
-- | '(' single_target ')'
define "SingleTarget" [
"SingleSubscriptAttributeTarget",
"Name",
list[open_paren_, "SingleTarget", close_paren_]],
-- single_subscript_attribute_target:
-- | t_primary '.' NAME !t_lookahead
-- | t_primary '[' slices ']' !t_lookahead
define "SingleSubscriptAttributeTarget" [
list["TPrimary", dot_, "Name"],
list["TPrimary", open_square_, "Slices", close_square_]],
-- t_primary:
-- | t_primary '.' NAME &t_lookahead
-- | t_primary '[' slices ']' &t_lookahead
-- | t_primary genexp &t_lookahead
-- | t_primary '(' [arguments] ')' &t_lookahead
-- | atom &t_lookahead
define "TPrimary" [
list["TPrimary", dot_, "Name"],
list["TPrimary", open_square_, "Slices", close_square_],
list["TPrimary", "Genexp"],
list["TPrimary", open_paren_, opt("Arguments"), close_paren_],
"Atom"],
-- t_lookahead: '(' | '[' | '.'
define "TLookahead" [
open_paren_, open_square_, dot_],
-- # Targets for del statements
-- # --------------------------
-- del_targets: ','.del_target+ [',']
define "DelTargets" [
list["TPrimary", dot_, "Name"],
list["TPrimary", open_square_, "Slices", close_square_],
"DelTAtom"],
-- del_target:
-- | t_primary '.' NAME !t_lookahead
-- | t_primary '[' slices ']' !t_lookahead
-- | del_t_atom
define "DelTarget" [
list["TPrimary", dot_, "Name"],
list["TPrimary", open_square_, "Slices", close_square_],
"DelTAtom"],
-- del_t_atom:
-- | NAME
-- | '(' del_target ')'
-- | '(' [del_targets] ')'
-- | '[' [del_targets] ']'
define "DelTAtom" [
"Name",
list[open_paren_, "DelTarget", close_paren_],
list[open_paren_, opt("DelTargets"), close_paren_],
list[open_square_, opt("DelTargets"), close_square_]],
-- # TYPING ELEMENTS
-- # ---------------
-- # type_expressions allow */** but ignore them
-- type_expressions:
-- | ','.expression+ ',' '*' expression ',' '**' expression
-- | ','.expression+ ',' '*' expression
-- | ','.expression+ ',' '**' expression
-- | '*' expression ',' '**' expression
-- | '*' expression
-- | '**' expression
-- | ','.expression+
define "TypeExpressions" [
list[sepp comma_ "Expression", star_, "Expression", opt(list[comma_, double_star_, "Expression"])],
list[sepp comma_ "Expression", star_, double_star_, "Expression"],
list[star_, "Expression", opt(list[comma_, double_star_, "Expression"])],
list[double_star_, "Expression"],
list[sepp comma_ "Expression"]],
-- func_type_comment:
-- | NEWLINE TYPE_COMMENT &(NEWLINE INDENT) # Must be followed by indented block
-- | TYPE_COMMENT
define "FuncTypeComment" [
list[opt(newline_), "TypeComment"]]]