hydra-0.15.0: src/main/haskell/Hydra/Sources/Python/Syntax.hs
module Hydra.Sources.Python.Syntax where
-- Standard imports for type-level sources outside of the kernel
import Hydra.Kernel
import Hydra.Dsl.Annotations
import Hydra.Dsl.Bootstrap
import Hydra.Dsl.Types ((>:))
import qualified Hydra.Dsl.Types as T
import qualified Hydra.Sources.Kernel.Types.Core as Core
ns :: Namespace
ns = Namespace "hydra.python.syntax"
def :: String -> Type -> Binding
def = datatype ns
python :: String -> Type
python = typeref ns
module_ :: Module
module_ = Module {
moduleNamespace = ns,
moduleDefinitions = (map toTypeDef definitions),
moduleTermDependencies = [Core.ns],
moduleTypeDependencies = [Core.ns],
moduleDescription = Just ("A Python syntax model, based on the Python v3 PEG grammar retrieved on 2024-12-22"
++ " from https://docs.python.org/3/reference/grammar.html")}
where
definitions = constructs ++ terminals ++ nonterminals
-- These definitions are not based on the grammar, but are convenient for working with Python sources in Hydra.
constructs = [
annotatedStatement,
pythonModule,
quoteStyle]
-- Terminals from the PEG grammar (see below)
terminals = [
name,
number,
string,
typeComment]
-- Nonterminal productions from the PEG grammar (inline).
-- Note: all significant deviations from the grammar are indicated with the word "Hydra" in comments.
nonterminals = [
file,
interactive,
eval,
funcType,
statement,
simpleStatement,
compoundStatement,
assignment,
typedAssignment,
untypedAssignment,
augAssignment,
annotatedRhs,
augAssign,
returnStatement,
raiseStatement,
raiseExpression,
delStatement,
yieldStatement,
assertStatement,
importStatement,
importName,
importFrom,
relativeImportPrefix,
importFromTargets,
importFromAsName,
dottedAsName,
dottedName,
block,
decorators,
classDefinition,
functionDefinition,
functionDefRaw,
parameters,
slashNoDefaultParameters,
slashWithDefaultParameters,
paramNoDefaultParameters,
paramWithDefaultParameters,
slashNoDefault,
slashWithDefault,
starEtc,
noDefaultStarEtc,
noDefaultStarAnnotationStarEtc,
commaStarEtc,
keywords,
paramNoDefault,
paramNoDefaultStarAnnotation,
paramWithDefault,
paramMaybeDefault,
param,
paramStarAnnotation,
annotation,
starAnnotation,
default_,
ifStatement,
ifTail,
whileStatement,
forStatement,
withStatement,
withItem,
tryStatement,
tryFinallyStatement,
tryExceptStatement,
tryExceptStarStatement,
exceptBlock,
exceptExpression,
exceptStarBlock,
matchStatement,
subjectExpression,
caseBlock,
guard,
patterns,
pattern_,
asPattern,
orPattern,
closedPattern,
literalExpression,
complexNumber,
plusOrMinus,
signedNumber,
signedRealNumber,
realNumber,
imaginaryNumber,
capturePattern,
patternCaptureTarget,
valuePattern,
attribute,
nameOrAttribute,
groupPattern,
sequencePattern,
openSequencePattern,
maybeSequencePattern,
maybeStarPattern,
starPattern,
mappingPattern,
itemsPattern,
keyValuePattern,
literalExpressionOrAttribute,
doubleStarPattern,
classPattern,
positionalPatterns,
keywordPatterns,
keywordPattern,
typeAlias,
typeParameter,
simpleTypeParameter,
starTypeParameter,
doubleStarTypeParameter,
expression,
conditional,
yieldExpression,
starExpression,
starNamedExpressions,
starNamedExpression,
assignmentExpression,
namedExpression,
disjunction,
conjunction,
inversion,
comparison,
compareOpBitwiseOrPair,
compareOp,
bitwiseOr,
bitwiseXor,
bitwiseAnd,
shiftExpression,
shiftLhs,
shiftOp,
sum_,
sumLhs,
sumOp,
term,
termLhs,
termOp,
factor,
power,
awaitPrimary,
primary,
primaryWithRhs,
primaryRhs,
slices,
sliceOrStarredExpression,
slice,
sliceExpression,
atom,
group,
lambda_,
lambdaParameters,
lambdaSlashNoDefault,
lambdaSlashWithDefault,
lambdaStarEtc,
lambdaKwds,
lambdaParamNoDefault,
lambdaParamWithDefault,
lambdaParamMaybeDefault,
list,
tuple,
set,
dict,
doubleStarredKvpair,
kvpair,
forIfClauses,
forIfClause,
listcomp,
setcomp,
genexp,
genexpHead,
dictcomp,
args,
posArg,
starredExpression,
kwargOrStarred,
kwarg,
kwargOrDoubleStarred,
starTargetsListSeq,
starTargetsTupleSeq,
starTarget,
targetWithStarAtom,
tPrimaryAndName,
tPrimaryAndSlices,
starAtom,
singleTarget,
singleSubscriptAttributeTarget,
tPrimary,
tPrimaryAndGenexp,
tPrimaryAndArguments,
delTargets,
delTarget,
delTAtom,
typeExpression,
funcTypeComment]
-- These definitions are not based on the grammar, but are convenient for working with Python sources in Hydra.
annotatedStatement :: Binding
annotatedStatement = def "AnnotatedStatement" $ T.record [ -- Note: added for Hydra-Python
"comment">: T.string,
"statement">: python "Statement"]
pythonModule :: Binding
pythonModule = def "Module" $
-- Groups of statements are separated by a double newline; see also the "Block" production.
T.wrap $ T.list $ nonemptyList $ python "Statement"
quoteStyle :: Binding
quoteStyle = def "QuoteStyle" $ T.enum ["single", "double", "triple"]
-- Terminals from the PEG grammar (see below)
name :: Binding
name = def "Name" $ T.wrap T.string -- NAME in the grammar
number :: Binding
number = def "Number" $ T.union [ -- NUMBER in the grammar
"integer">: T.bigint,
"float">: T.bigfloat]
string :: Binding
string = def "String" $ T.record [ -- STRING in the grammar
"value">: T.string,
"quoteStyle">: python "QuoteStyle"]
typeComment :: Binding
typeComment = def "TypeComment" $ T.wrap T.string -- TYPE_COMMENT in the grammar
-- Nonterminal productions from the PEG grammar (inline).
-- Note: all significant deviations from the grammar are indicated with the word "Hydra" in comments.
-- # General grammatical elements and rules:
-- #
-- # * Strings with double quotes (") denote SOFT KEYWORDS
-- # * Strings with single quotes (') denote KEYWORDS
-- # * Upper case names (NAME) denote tokens in the Grammar/Tokens file
-- # * Rule names starting with "invalid_" are used for specialized syntax errors
-- # - These rules are NOT used in the first pass of the parser.
-- # - Only if the first pass fails to parse, a second pass including the invalid
-- # rules will be executed.
-- # - If the parser fails in the second phase with a generic syntax error, the
-- # location of the generic failure of the first pass will be used (this avoids
-- # reporting incorrect locations due to the invalid rules).
-- # - The order of the alternatives involving invalid rules matter
-- # (like any rule in PEG).
-- #
-- # Grammar Syntax (see PEP 617 for more information):
-- #
-- # rule_name: expression
-- # Optionally, a type can be included right after the rule name, which
-- # specifies the return type of the C or Python function corresponding to the
-- # rule:
-- # rule_name[return_type]: expression
-- # If the return type is omitted, then a void * is returned in C and an Any in
-- # Python.
-- # e1 e2
-- # Match e1, then match e2.
-- # e1 | e2
-- # Match e1 or e2.
-- # The first alternative can also appear on the line after the rule name for
-- # formatting purposes. In that case, a | must be used before the first
-- # alternative, like so:
-- # rule_name[return_type]:
-- # | first_alt
-- # | second_alt
-- # ( e )
-- # Match e (allows also to use other operators in the group like '(e)*')
-- # [ e ] or e?
-- # Optionally match e.
-- # e*
-- # Match zero or more occurrences of e.
-- # e+
-- # Match one or more occurrences of e.
-- # s.e+
-- # Match one or more occurrences of e, separated by s. The generated parse tree
-- # does not include the separator. This is otherwise identical to (e (s e)*).
-- # &e
-- # Succeed if e can be parsed, without consuming any input.
-- # !e
-- # Fail if e can be parsed, without consuming any input.
-- # ~
-- # Commit to the current alternative, even if it fails to parse.
-- # &&e
-- # Eager parse e. The parser will not backtrack and will immediately
-- # fail with SyntaxError if e cannot be parsed.
-- #
--
-- # STARTING RULES
-- # ==============
--
-- file: [statements] ENDMARKER
file :: Binding
file = def "File" $ T.wrap $ T.list $ python "Statement"
-- interactive: statement_newline
interactive :: Binding
interactive = def "Interactive" $ T.wrap $ python "Statement"
-- eval: expressions NEWLINE* ENDMARKER
eval :: Binding
eval = def "Eval" $ T.wrap $ nonemptyList $ python "Expression"
-- func_type: '(' [type_expressions] ')' '->' expression NEWLINE* ENDMARKER
funcType :: Binding
funcType = def "FuncType" $ T.record [ -- TODO: func_type is defined in the official BNF grammar, but never used
"type">: T.list $ python "TypeExpression",
"body">: python "Expression"]
-- # GENERAL STATEMENTS
-- # ==================
--
-- statements: statement+
--
-- statement: compound_stmt | simple_stmts
statement :: Binding
statement = def "Statement" $ T.union [
"compound">: python "CompoundStatement",
"simple">: nonemptyList $ python "SimpleStatement",
"annotated">: python "AnnotatedStatement"] -- Added for Hydra-Python
-- statement_newline:
-- | compound_stmt NEWLINE
-- | simple_stmts
-- | NEWLINE
-- | ENDMARKER
--
-- simple_stmts:
-- | simple_stmt !';' NEWLINE # Not needed, there for speedup
-- | ';'.simple_stmt+ [';'] NEWLINE
--
-- # NOTE: assignment MUST precede expression, else parsing a simple assignment
-- # will throw a SyntaxError.
-- simple_stmt:
-- | assignment
-- | type_alias
-- | star_expressions
-- | return_stmt
-- | import_stmt
-- | raise_stmt
-- | 'pass'
-- | del_stmt
-- | yield_stmt
-- | assert_stmt
-- | 'break'
-- | 'continue'
-- | global_stmt
-- | nonlocal_stmt
simpleStatement :: Binding
simpleStatement = def "SimpleStatement" $ T.union [
"assignment">: python "Assignment",
"typeAlias">: python "TypeAlias",
"starExpressions">: nonemptyList $ python "StarExpression",
"return">: python "ReturnStatement",
"import">: python "ImportStatement",
"raise">: python "RaiseStatement",
"pass">: T.unit,
"del">: python "DelStatement",
"yield">: python "YieldStatement",
"assert">: python "AssertStatement",
"break">: T.unit,
"continue">: T.unit,
"global">: nonemptyList $ python "Name",
"nonlocal">: nonemptyList $ python "Name"]
-- compound_stmt:
-- | function_def
-- | if_stmt
-- | class_def
-- | with_stmt
-- | for_stmt
-- | try_stmt
-- | while_stmt
-- | match_stmt
compoundStatement :: Binding
compoundStatement = def "CompoundStatement" $ T.union [
"function">: python "FunctionDefinition",
"if">: python "IfStatement",
"classDef">: python "ClassDefinition",
"with">: python "WithStatement",
"for">: python "ForStatement",
"try">: python "TryStatement",
"while">: python "WhileStatement",
"match">: python "MatchStatement"]
-- # 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)
assignment :: Binding
assignment = def "Assignment" $ T.union [
"typed">: python "TypedAssignment",
"untyped">: python "UntypedAssignment",
"aug">: python "AugAssignment"]
typedAssignment :: Binding
typedAssignment = def "TypedAssignment" $ T.record [
"lhs">: python "SingleTarget",
"type">: python "Expression",
"rhs">: T.maybe $ python "AnnotatedRhs"]
untypedAssignment :: Binding
untypedAssignment = def "UntypedAssignment" $ T.record [
"targets">: nonemptyList $ python "StarTarget",
"rhs">: python "AnnotatedRhs",
"typeComment">: T.maybe $ python "TypeComment"]
augAssignment :: Binding
augAssignment = def "AugAssignment" $ T.record [
"lhs">: python "SingleTarget",
"augassign">: python "AugAssign",
"rhs">: python "AnnotatedRhs"]
-- annotated_rhs: yield_expr | star_expressions
annotatedRhs :: Binding
annotatedRhs = def "AnnotatedRhs" $ T.union [
"yield">: python "YieldExpression",
"star">: nonemptyList $ python "StarExpression"]
-- augassign:
-- | '+='
-- | '-='
-- | '*='
-- | '@='
-- | '/='
-- | '%='
-- | '&='
-- | '|='
-- | '^='
-- | '<<='
-- | '>>='
-- | '**='
-- | '//='
augAssign :: Binding
augAssign = def "AugAssign" $ T.enum [
"plusEqual",
"minusEqual",
"timesEqual",
"atEqual",
"slashEqual",
"percentEqual",
"ampersandEqual",
"barEqual",
"caretEqual",
"leftShiftEqual",
"rightShiftEqual",
"starStarEqual",
"doubleSlashEqual"]
-- return_stmt:
-- | 'return' [star_expressions]
returnStatement :: Binding
returnStatement = def "ReturnStatement" $ T.wrap $ T.list $ python "StarExpression"
-- raise_stmt:
-- | 'raise' expression ['from' expression ]
-- | 'raise'
raiseStatement :: Binding
raiseStatement = def "RaiseStatement" $ T.wrap $ T.maybe $ python "RaiseExpression"
raiseExpression :: Binding
raiseExpression = def "RaiseExpression" $ T.record [
"expression">: python "Expression",
"from">: T.maybe $ python "Expression"]
-- global_stmt: 'global' ','.NAME+
--
-- nonlocal_stmt: 'nonlocal' ','.NAME+
--
-- del_stmt:
-- | 'del' del_targets &(';' | NEWLINE)
delStatement :: Binding
delStatement = def "DelStatement" $ T.wrap $ python "DelTargets"
-- yield_stmt: yield_expr
yieldStatement :: Binding
yieldStatement = def "YieldStatement" $ T.wrap $ python "YieldExpression"
-- assert_stmt: 'assert' expression [',' expression ]
assertStatement :: Binding
assertStatement = def "AssertStatement" $ T.record [
"expression1">: python "Expression",
"expression2">: T.maybe $ python "Expression"]
-- import_stmt:
-- | import_name
-- | import_from
importStatement :: Binding
importStatement = def "ImportStatement" $ T.union [
"name">: python "ImportName",
"from">: python "ImportFrom"]
-- # Import statements
-- # -----------------
--
-- import_name: 'import' dotted_as_names
importName :: Binding
importName = def "ImportName" $ T.wrap $ nonemptyList $ python "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
importFrom :: Binding
importFrom = def "ImportFrom" $ T.record [
"prefixes">: T.list $ python "RelativeImportPrefix",
"dottedName">: T.maybe $ python "DottedName",
"targets">: python "ImportFromTargets"]
relativeImportPrefix :: Binding
relativeImportPrefix = def "RelativeImportPrefix" $ T.enum ["dot", "ellipsis"]
-- import_from_targets:
-- | '(' import_from_as_names [','] ')'
-- | import_from_as_names !','
-- | '*'
importFromTargets :: Binding
importFromTargets = def "ImportFromTargets" $ T.union [
"simple">: nonemptyList $ python "ImportFromAsName",
"parens">: nonemptyList $ python "ImportFromAsName",
"star">: T.unit]
-- import_from_as_names:
-- | ','.import_from_as_name+
--
-- import_from_as_name:
-- | NAME ['as' NAME ]
importFromAsName :: Binding
importFromAsName = def "ImportFromAsName" $ T.record [
"name">: python "Name",
"as">: T.maybe $ python "Name"]
-- dotted_as_names:
-- | ','.dotted_as_name+
--
-- dotted_as_name:
-- | dotted_name ['as' NAME ]
dottedAsName :: Binding
dottedAsName = def "DottedAsName" $ T.record [
"name">: python "DottedName",
"as">: T.maybe $ python "Name"]
-- dotted_name:
-- | dotted_name '.' NAME
-- | NAME
dottedName :: Binding
dottedName = def "DottedName" $ T.wrap $ nonemptyList $ python "Name"
--
-- # COMPOUND STATEMENTS
-- # ===================
--
-- # Common elements
-- # ---------------
--
-- block:
-- | NEWLINE INDENT statements DEDENT
-- | simple_stmts
block :: Binding
block = def "Block" $ T.union [
-- Statements in indented blocks are grouped in Hydra, so these groups can be separated by a double newline.
"indented">: nonemptyList $ nonemptyList $ python "Statement",
"simple">: nonemptyList $ python "SimpleStatement"]
-- decorators: ('@' named_expression NEWLINE )+
decorators :: Binding
decorators = def "Decorators" $ T.wrap $ nonemptyList $ python "NamedExpression"
-- # Class definitions
-- # -----------------
--
-- class_def:
-- | decorators class_def_raw
-- | class_def_raw
classDefinition :: Binding
classDefinition = def "ClassDefinition" $ T.record [
"decorators">: T.maybe $ python "Decorators",
"name">: python "Name",
"typeParams">: T.list $ python "TypeParameter",
"arguments">: T.maybe $ python "Args",
"body">: python "Block"]
-- class_def_raw:
-- | 'class' NAME [type_params] ['(' [arguments] ')' ] ':' block
--
-- # Function definitions
-- # --------------------
--
-- function_def:
-- | decorators function_def_raw
-- | function_def_raw
functionDefinition :: Binding
functionDefinition = def "FunctionDefinition" $ T.record [
"decorators">: T.maybe $ python "Decorators",
"raw">: python "FunctionDefRaw"]
-- function_def_raw:
-- | 'def' NAME [type_params] '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
-- | 'async' 'def' NAME [type_params] '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
functionDefRaw :: Binding
functionDefRaw = def "FunctionDefRaw" $ T.record [
"async">: T.boolean,
"name">: python "Name",
"typeParams">: T.list $ python "TypeParameter",
"params">: T.maybe $ python "Parameters",
"returnType">: T.maybe $ python "Expression",
"funcTypeComment">: T.maybe $ python "FuncTypeComment",
"block">: python "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
parameters :: Binding
parameters = def "Parameters" $ T.union [
"slashNoDefault">: python "SlashNoDefaultParameters",
"slashWithDefault">: python "SlashWithDefaultParameters",
"paramNoDefault">: python "ParamNoDefaultParameters",
"paramWithDefault">: python "ParamWithDefaultParameters",
"starEtc">: python "StarEtc"]
slashNoDefaultParameters :: Binding
slashNoDefaultParameters = def "SlashNoDefaultParameters" $ T.record [
"slash">: python "SlashNoDefault",
"paramNoDefault">: T.list $ python "ParamNoDefault",
"paramWithDefault">: T.list $ python "ParamWithDefault",
"starEtc">: T.maybe $ python "StarEtc"]
slashWithDefaultParameters :: Binding
slashWithDefaultParameters = def "SlashWithDefaultParameters" $ T.record [
"paramNoDefault">: T.list $ python "ParamNoDefault",
"paramWithDefault">: T.list $ python "ParamWithDefault",
"starEtc">: T.maybe $ python "StarEtc"]
paramNoDefaultParameters :: Binding
paramNoDefaultParameters = def "ParamNoDefaultParameters" $ T.record [
"paramNoDefault">: nonemptyList $ python "ParamNoDefault",
"paramWithDefault">: T.list $ python "ParamWithDefault",
"starEtc">: T.maybe $ python "StarEtc"]
paramWithDefaultParameters :: Binding
paramWithDefaultParameters = def "ParamWithDefaultParameters" $ T.record [
"paramWithDefault">: nonemptyList $ python "ParamWithDefault",
"starEtc">: T.maybe $ python "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+ '/' &')'
slashNoDefault :: Binding
slashNoDefault = def "SlashNoDefault" $ T.wrap $ nonemptyList $ python "ParamNoDefault"
-- slash_with_default:
-- | param_no_default* param_with_default+ '/' ','
-- | param_no_default* param_with_default+ '/' &')'
slashWithDefault :: Binding
slashWithDefault = def "SlashWithDefault" $ T.record [
"paramNoDefault">: T.list $ python "ParamNoDefault",
"paramWithDefault">: nonemptyList $ python "ParamWithDefault"]
-- star_etc:
-- | '*' param_no_default param_maybe_default* [kwds]
-- | '*' param_no_default_star_annotation param_maybe_default* [kwds]
-- | '*' ',' param_maybe_default+ [kwds]
-- | kwds
starEtc :: Binding
starEtc = def "StarEtc" $ T.union [
"starNoDefault">: python "NoDefaultStarEtc",
"starNoDefaultStarAnnotation">: python "NoDefaultStarAnnotationStarEtc",
"starComma">: python "CommaStarEtc",
"keywords">: python "Keywords"]
noDefaultStarEtc :: Binding
noDefaultStarEtc = def "NoDefaultStarEtc" $ T.record [
"paramNoDefault">: python "ParamNoDefault",
"paramMaybeDefault">: T.list $ python "ParamMaybeDefault",
"keywords">: T.maybe $ python "Keywords"]
noDefaultStarAnnotationStarEtc :: Binding
noDefaultStarAnnotationStarEtc = def "NoDefaultStarAnnotationStarEtc" $ T.record [
"paramNoDefaultStarAnnotation">: python "ParamNoDefaultStarAnnotation",
"paramMaybeDefault">: T.list $ python "ParamMaybeDefault",
"keywords">: T.maybe $ python "Keywords"]
commaStarEtc :: Binding
commaStarEtc = def "CommaStarEtc" $ T.record [
"paramMaybeDefault">: nonemptyList $ python "ParamMaybeDefault",
"keywords">: T.maybe $ python "Keywords"]
-- kwds:
-- | '**' param_no_default
keywords :: Binding
keywords = def "Keywords" $ T.wrap $ python "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? &')'
paramNoDefault :: Binding
paramNoDefault = def "ParamNoDefault" $ T.record [
"param">: python "Param",
"typeComment">: T.maybe $ python "TypeComment"]
-- param_no_default_star_annotation:
-- | param_star_annotation ',' TYPE_COMMENT?
-- | param_star_annotation TYPE_COMMENT? &')'
paramNoDefaultStarAnnotation :: Binding
paramNoDefaultStarAnnotation = def "ParamNoDefaultStarAnnotation" $ T.record [
"paramStarAnnotation">: python "ParamStarAnnotation",
"typeComment">: T.maybe $ python "TypeComment"]
-- param_with_default:
-- | param default ',' TYPE_COMMENT?
-- | param default TYPE_COMMENT? &')'
paramWithDefault :: Binding
paramWithDefault = def "ParamWithDefault" $ T.record [
"param">: python "Param",
"default">: python "Default",
"typeComment">: T.maybe $ python "TypeComment"]
-- param_maybe_default:
-- | param default? ',' TYPE_COMMENT?
-- | param default? TYPE_COMMENT? &')'
paramMaybeDefault :: Binding
paramMaybeDefault = def "ParamMaybeDefault" $ T.record [
"param">: python "Param",
"default">: T.maybe $ python "Default",
"typeComment">: T.maybe $ python "TypeComment"]
-- param: NAME annotation?
param :: Binding
param = def "Param" $ T.record [
"name">: python "Name",
"annotation">: T.maybe $ python "Annotation"]
-- param_star_annotation: NAME star_annotation
paramStarAnnotation :: Binding
paramStarAnnotation = def "ParamStarAnnotation" $ T.record [
"name">: python "Name",
"annotation">: python "StarAnnotation"]
-- annotation: ':' expression
annotation :: Binding
annotation = def "Annotation" $ T.wrap $ python "Expression"
-- star_annotation: ':' star_expression
starAnnotation :: Binding
starAnnotation = def "StarAnnotation" $ T.wrap $ python "StarExpression"
-- default: '=' expression | invalid_default
default_ :: Binding
default_ = def "Default" $ T.wrap $ python "Expression"
-- # If statement
-- # ------------
--
-- if_stmt:
-- | 'if' named_expression ':' block elif_stmt
-- | 'if' named_expression ':' block [else_block]
ifStatement :: Binding
ifStatement = def "IfStatement" $ T.record [
"condition">: python "NamedExpression",
"body">: python "Block",
"continuation">: T.maybe $ python "IfTail"]
ifTail :: Binding
ifTail = def "IfTail" $ T.union [
"elif">: python "IfStatement",
"else">: python "Block"]
-- elif_stmt:
-- | 'elif' named_expression ':' block elif_stmt
-- | 'elif' named_expression ':' block [else_block]
-- else_block:
-- | 'else' ':' block
--
-- # While statement
-- # ---------------
--
-- while_stmt:
-- | 'while' named_expression ':' block [else_block]
whileStatement :: Binding
whileStatement = def "WhileStatement" $ T.record [
"condition">: python "NamedExpression",
"body">: python "Block",
"else">: T.maybe $ python "Block"]
-- # 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]
forStatement :: Binding
forStatement = def "ForStatement" $ T.record [
"async">: T.boolean,
"targets">: nonemptyList $ python "StarTarget",
"expressions">: nonemptyList $ python "StarExpression",
"typeComment">: T.maybe $ python "TypeComment",
"body">: python "Block",
"else">: T.maybe $ python "Block"]
-- # With statement
-- # --------------
--
-- with_stmt:
-- | 'with' '(' ','.with_item+ ','? ')' ':' [TYPE_COMMENT] block
-- | 'with' ','.with_item+ ':' [TYPE_COMMENT] block
-- | 'async' 'with' '(' ','.with_item+ ','? ')' ':' block
-- | 'async' 'with' ','.with_item+ ':' [TYPE_COMMENT] block
withStatement :: Binding
withStatement = def "WithStatement" $ T.record [
"async">: T.boolean,
"items">: nonemptyList $ python "WithItem",
"typeComment">: T.maybe $ python "TypeComment",
"body">: python "Block"]
-- with_item:
-- | expression 'as' star_target &(',' | ')' | ':')
-- | expression
withItem :: Binding
withItem = def "WithItem" $ T.record [
"expression">: python "Expression",
"as">: T.maybe $ python "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]
tryStatement :: Binding
tryStatement = def "TryStatement" $ T.union [
"finally">: python "TryFinallyStatement",
"except">: python "TryExceptStatement",
"exceptStar">: python "TryExceptStarStatement"]
tryFinallyStatement :: Binding
tryFinallyStatement = def "TryFinallyStatement" $ T.record [
"body">: python "Block",
"finally">: python "Block"]
tryExceptStatement :: Binding
tryExceptStatement = def "TryExceptStatement" $ T.record [
"body">: python "Block",
"excepts">: nonemptyList $ python "ExceptBlock",
"else">: T.maybe $ python "Block",
"finally">: T.maybe $ python "Block"]
tryExceptStarStatement :: Binding
tryExceptStarStatement = def "TryExceptStarStatement" $ T.record [
"body">: python "Block",
"excepts">: nonemptyList $ python "ExceptStarBlock",
"else">: T.maybe $ python "Block",
"finally">: T.maybe $ python "Block"]
-- # Except statement
-- # ----------------
--
-- except_block:
-- | 'except' expression ['as' NAME ] ':' block
-- | 'except' ':' block
exceptBlock :: Binding
exceptBlock = def "ExceptBlock" $ T.record [
"expression">: T.maybe $ python "ExceptExpression",
"body">: python "Block"]
exceptExpression :: Binding
exceptExpression = def "ExceptExpression" $ T.record [
"expression">: python "Expression",
"as">: T.maybe $ python "Name"]
-- except_star_block:
-- | 'except' '*' expression ['as' NAME ] ':' block
exceptStarBlock :: Binding
exceptStarBlock = def "ExceptStarBlock" $ T.record [
"expression">: python "Expression",
"as">: T.maybe $ python "Name",
"body">: python "Block"]
-- finally_block:
-- | 'finally' ':' block
--
-- # Match statement
-- # ---------------
--
-- match_stmt:
-- | "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
matchStatement :: Binding
matchStatement = def "MatchStatement" $ T.record [
"subject">: python "SubjectExpression",
"cases">: nonemptyList $ python "CaseBlock"]
-- subject_expr:
-- | star_named_expression ',' star_named_expressions?
-- | named_expression
subjectExpression :: Binding
subjectExpression = def "SubjectExpression" $ T.union [
"tuple">: nonemptyList $ python "StarNamedExpression",
"simple">: python "NamedExpression"]
-- case_block:
-- | "case" patterns guard? ':' block
caseBlock :: Binding
caseBlock = def "CaseBlock" $ T.record [
"patterns">: python "Patterns",
"guard">: T.maybe $ python "Guard",
"body">: python "Block"]
-- guard: 'if' named_expression
guard :: Binding
guard = def "Guard" $ T.wrap $ python "NamedExpression"
-- patterns:
-- | open_sequence_pattern
-- | pattern
patterns :: Binding
patterns = def "Patterns" $ T.union [
"sequence">: python "OpenSequencePattern",
"pattern">: python "Pattern"]
-- pattern:
-- | as_pattern
-- | or_pattern
pattern_ :: Binding
pattern_ = def "Pattern" $ T.union [
"as">: python "AsPattern",
"or">: python "OrPattern"]
-- as_pattern:
-- | or_pattern 'as' pattern_capture_target
asPattern :: Binding
asPattern = def "AsPattern" $ T.record [
"pattern">: python "OrPattern",
"as">: python "PatternCaptureTarget"]
-- or_pattern:
-- | '|'.closed_pattern+
orPattern :: Binding
orPattern = def "OrPattern" $ T.wrap $ nonemptyList $ python "ClosedPattern"
-- closed_pattern:
-- | literal_pattern
-- | capture_pattern
-- | wildcard_pattern
-- | value_pattern
-- | group_pattern
-- | sequence_pattern
-- | mapping_pattern
-- | class_pattern
closedPattern :: Binding
closedPattern = def "ClosedPattern" $ T.union [
"literal">: python "LiteralExpression",
"capture">: python "CapturePattern",
"wildcard">: T.unit,
"value">: python "ValuePattern",
"group">: python "GroupPattern",
"sequence">: python "SequencePattern",
"mapping">: python "MappingPattern",
"class">: python "ClassPattern"]
-- # Literal patterns are used for equality and identity constraints
-- literal_pattern:
-- | signed_number !('+' | '-')
-- | complex_number
-- | strings
-- | 'None'
-- | 'True'
-- | 'False'
-- Note: identical to literal_expr
-- # Literal expressions are used to restrict permitted mapping pattern keys
-- literal_expr:
-- | signed_number !('+' | '-')
-- | complex_number
-- | strings
-- | 'None'
-- | 'True'
-- | 'False'
literalExpression :: Binding
literalExpression = def "LiteralExpression" $ T.union [
"number">: python "SignedNumber",
"complex">: python "ComplexNumber",
"string">: T.string,
"none">: T.unit,
"true">: T.unit,
"false">: T.unit]
-- complex_number:
-- | signed_real_number '+' imaginary_number
-- | signed_real_number '-' imaginary_number
complexNumber :: Binding
complexNumber = def "ComplexNumber" $ T.record [
"real">: python "SignedRealNumber",
"plusOrMinus">: python "PlusOrMinus",
"imaginary">: python "ImaginaryNumber"]
plusOrMinus :: Binding
plusOrMinus = def "PlusOrMinus" $ T.enum ["plus", "minus"]
-- signed_number:
-- | NUMBER
-- | '-' NUMBER
signedNumber :: Binding
signedNumber = def "SignedNumber" $ T.union [
"sign">: python "PlusOrMinus",
"number">: python "Number"]
-- signed_real_number:
-- | real_number
-- | '-' real_number
signedRealNumber :: Binding
signedRealNumber = def "SignedRealNumber" $ T.union [
"sign">: python "PlusOrMinus",
"number">: python "RealNumber"]
-- real_number:
-- | NUMBER
realNumber :: Binding
realNumber = def "RealNumber" $ T.wrap $ python "Number"
-- imaginary_number:
-- | NUMBER
imaginaryNumber :: Binding
imaginaryNumber = def "ImaginaryNumber" $ T.wrap $ python "Number"
-- capture_pattern:
-- | pattern_capture_target
capturePattern :: Binding
capturePattern = def "CapturePattern" $ T.wrap $ python "PatternCaptureTarget"
-- pattern_capture_target:
-- | !"_" NAME !('.' | '(' | '=')
patternCaptureTarget :: Binding
patternCaptureTarget = def "PatternCaptureTarget" $ T.wrap $ python "Name"
-- wildcard_pattern:
-- | "_"
--
-- value_pattern:
-- | attr !('.' | '(' | '=')
valuePattern :: Binding
valuePattern = def "ValuePattern" $ T.wrap $ python "Attribute"
-- attr:
-- | name_or_attr '.' NAME
attribute :: Binding
attribute = def "Attribute" $ T.wrap $ nonemptyList $ python "Name" -- Actually list with length >= 2
-- name_or_attr:
-- | attr
-- | NAME
nameOrAttribute :: Binding
nameOrAttribute = def "NameOrAttribute" $ T.wrap $ nonemptyList $ python "Name"
-- group_pattern:
-- | '(' pattern ')'
groupPattern :: Binding
groupPattern = def "GroupPattern" $ T.wrap $ python "Pattern"
-- sequence_pattern:
-- | '[' maybe_sequence_pattern? ']'
-- | '(' open_sequence_pattern? ')'
sequencePattern :: Binding
sequencePattern = def "SequencePattern" $ T.union [
"list">: T.maybe $ python "MaybeSequencePattern",
"tuple">: T.maybe $ python "OpenSequencePattern"]
-- open_sequence_pattern:
-- | maybe_star_pattern ',' maybe_sequence_pattern?
openSequencePattern :: Binding
openSequencePattern = def "OpenSequencePattern" $ T.record [
"head">: python "MaybeStarPattern",
"tail">: T.maybe $ python "MaybeSequencePattern"]
-- maybe_sequence_pattern:
-- | ','.maybe_star_pattern+ ','?
maybeSequencePattern :: Binding
maybeSequencePattern = def "MaybeSequencePattern" $ T.wrap $ nonemptyList $ python "MaybeStarPattern"
-- maybe_star_pattern:
-- | star_pattern
-- | pattern
maybeStarPattern :: Binding
maybeStarPattern = def "MaybeStarPattern" $ T.union [
"star">: python "StarPattern",
"pattern">: python "Pattern"]
-- star_pattern:
-- | '*' pattern_capture_target
-- | '*' wildcard_pattern
starPattern :: Binding
starPattern = def "StarPattern" $ T.union [
"capture">: python "PatternCaptureTarget",
"wildcard">: T.unit]
-- mapping_pattern:
-- | '{' '}'
-- | '{' double_star_pattern ','? '}'
-- | '{' items_pattern ',' double_star_pattern ','? '}'
-- | '{' items_pattern ','? '}'
mappingPattern :: Binding
mappingPattern = def "MappingPattern" $ T.record [
"items">: T.maybe $ python "ItemsPattern",
"doubleStar">: T.maybe $ python "DoubleStarPattern"]
-- items_pattern:
-- | ','.key_value_pattern+
itemsPattern :: Binding
itemsPattern = def "ItemsPattern" $ T.wrap $ nonemptyList $ python "KeyValuePattern"
-- key_value_pattern:
-- | (literal_expr | attr) ':' pattern
keyValuePattern :: Binding
keyValuePattern = def "KeyValuePattern" $ T.record [
"key">: python "LiteralExpressionOrAttribute",
"value">: python "Pattern"]
literalExpressionOrAttribute :: Binding
literalExpressionOrAttribute = def "LiteralExpressionOrAttribute" $ T.union [
"literal">: python "LiteralExpression",
"attribute">: python "Attribute"]
-- double_star_pattern:
-- | '**' pattern_capture_target
doubleStarPattern :: Binding
doubleStarPattern = def "DoubleStarPattern" $ T.wrap $ python "PatternCaptureTarget"
-- class_pattern:
-- | name_or_attr '(' ')'
-- | name_or_attr '(' positional_patterns ','? ')'
-- | name_or_attr '(' keyword_patterns ','? ')'
-- | name_or_attr '(' positional_patterns ',' keyword_patterns ','? ')'
classPattern :: Binding
classPattern = def "ClassPattern" $ T.record [
"nameOrAttribute">: python "NameOrAttribute",
"positionalPatterns">: T.maybe $ python "PositionalPatterns",
"keywordPatterns">: T.maybe $ python "KeywordPatterns"]
-- positional_patterns:
-- | ','.pattern+
positionalPatterns :: Binding
positionalPatterns = def "PositionalPatterns" $ T.wrap $ nonemptyList $ python "Pattern"
-- keyword_patterns:
-- | ','.keyword_pattern+
keywordPatterns :: Binding
keywordPatterns = def "KeywordPatterns" $ T.wrap $ nonemptyList $ python "KeywordPattern"
-- keyword_pattern:
-- | NAME '=' pattern
keywordPattern :: Binding
keywordPattern = def "KeywordPattern" $ T.record [
"name">: python "Name",
"pattern">: python "Pattern"]
-- # Type statement
-- # ---------------
--
-- type_alias:
-- | "type" NAME [type_params] '=' expression
typeAlias :: Binding
typeAlias = def "TypeAlias" $ T.record [
"name">: python "Name",
"typeParams">: T.list $ python "TypeParameter",
"expression">: python "Expression"]
-- # Type parameter declaration
-- # --------------------------
--
-- type_params:
-- | invalid_type_params
-- | '[' type_param_seq ']'
--
-- type_param_seq: ','.type_param+ [',']
--
-- type_param:
-- | NAME [type_param_bound] [type_param_default]
-- | '*' NAME [type_param_starred_default]
-- | '**' NAME [type_param_default]
typeParameter :: Binding
typeParameter = def "TypeParameter" $ T.union [
"simple">: python "SimpleTypeParameter",
"star">: python "StarTypeParameter",
"doubleStar">: python "DoubleStarTypeParameter"]
simpleTypeParameter :: Binding
simpleTypeParameter = def "SimpleTypeParameter" $ T.record [
"name">: python "Name",
"bound">: T.maybe $ python "Expression",
"default">: T.maybe $ python "Expression"]
starTypeParameter :: Binding
starTypeParameter = def "StarTypeParameter" $ T.record [
"name">: python "Name",
"default">: T.maybe $ python "StarExpression"]
doubleStarTypeParameter :: Binding
doubleStarTypeParameter = def "DoubleStarTypeParameter" $ T.record [
"name">: python "Name",
"default">: T.maybe $ python "Expression"]
-- type_param_bound: ':' expression
-- type_param_default: '=' expression
-- type_param_starred_default: '=' star_expression
--
-- # EXPRESSIONS
-- # -----------
--
-- expressions:
-- | expression (',' expression )+ [',']
-- | expression ','
-- | expression
--
-- expression:
-- | disjunction 'if' disjunction 'else' expression
-- | disjunction
-- | lambdef
expression :: Binding
expression = def "Expression" $ T.union [
"conditional">: python "Conditional",
"simple">: python "Disjunction",
"lambda">: python "Lambda"]
conditional :: Binding
conditional = def "Conditional" $ T.record [
"body">: python "Disjunction",
"if">: python "Disjunction",
"else">: python "Expression"]
-- yield_expr:
-- | 'yield' 'from' expression
-- | 'yield' [star_expressions]
yieldExpression :: Binding
yieldExpression = def "YieldExpression" $ T.union [
"from">: python "Expression",
"simple">: T.list $ python "StarExpression"]
-- star_expressions:
-- | star_expression (',' star_expression )+ [',']
-- | star_expression ','
-- | star_expression
--
-- star_expression:
-- | '*' bitwise_or
-- | expression
starExpression :: Binding
starExpression = def "StarExpression" $ T.union [
"star">: python "BitwiseOr",
"simple">: python "Expression"]
-- star_named_expressions: ','.star_named_expression+ [',']
starNamedExpressions :: Binding
starNamedExpressions = def "StarNamedExpressions" $ T.wrap $ nonemptyList $ python "StarNamedExpression"
-- star_named_expression:
-- | '*' bitwise_or
-- | named_expression
starNamedExpression :: Binding
starNamedExpression = def "StarNamedExpression" $ T.union [
"star">: python "BitwiseOr",
"simple">: python "NamedExpression"]
-- assignment_expression:
-- | NAME ':=' ~ expression
assignmentExpression :: Binding
assignmentExpression = def "AssignmentExpression" $ T.record [
"name">: python "Name",
"expression">: python "Expression"]
-- named_expression:
-- | assignment_expression
-- | expression !':='
namedExpression :: Binding
namedExpression = def "NamedExpression" $ T.union [
"assignment">: python "AssignmentExpression",
"simple">: python "Expression"]
-- disjunction:
-- | conjunction ('or' conjunction )+
-- | conjunction
disjunction :: Binding
disjunction = def "Disjunction" $ T.wrap $ nonemptyList $ python "Conjunction"
-- conjunction:
-- | inversion ('and' inversion )+
-- | inversion
conjunction :: Binding
conjunction = def "Conjunction" $ T.wrap $ nonemptyList $ python "Inversion"
-- inversion:
-- | 'not' inversion
-- | comparison
inversion :: Binding
inversion = def "Inversion" $ T.union [
"not">: python "Inversion",
"simple">: python "Comparison"]
-- # Comparison operators
-- # --------------------
--
-- comparison:
-- | bitwise_or compare_op_bitwise_or_pair+
-- | bitwise_or
comparison :: Binding
comparison = def "Comparison" $ T.record [
"lhs">: python "BitwiseOr",
"rhs">: T.list $ python "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
compareOpBitwiseOrPair :: Binding
compareOpBitwiseOrPair = def "CompareOpBitwiseOrPair" $ T.record [
"operator">: python "CompareOp",
"rhs">: python "BitwiseOr"]
compareOp :: Binding
compareOp = def "CompareOp" $ T.enum [
"eq", "noteq", "lte", "lt", "gte", "gt", "notin", "in", "isnot", "is"]
-- eq_bitwise_or: '==' bitwise_or
-- noteq_bitwise_or:
-- | ('!=' ) bitwise_or
-- lte_bitwise_or: '<=' bitwise_or
-- lt_bitwise_or: '<' bitwise_or
-- gte_bitwise_or: '>=' bitwise_or
-- gt_bitwise_or: '>' bitwise_or
-- notin_bitwise_or: 'not' 'in' bitwise_or
-- in_bitwise_or: 'in' bitwise_or
-- isnot_bitwise_or: 'is' 'not' bitwise_or
-- is_bitwise_or: 'is' bitwise_or
--
-- # Bitwise operators
-- # -----------------
--
-- bitwise_or:
-- | bitwise_or '|' bitwise_xor
-- | bitwise_xor
bitwiseOr :: Binding
bitwiseOr = def "BitwiseOr" $ T.record [
"lhs">: T.maybe $ python "BitwiseOr",
"rhs">: python "BitwiseXor"]
-- bitwise_xor:
-- | bitwise_xor '^' bitwise_and
-- | bitwise_and
bitwiseXor :: Binding
bitwiseXor = def "BitwiseXor" $ T.record [
"lhs">: T.maybe $ python "BitwiseXor",
"rhs">: python "BitwiseAnd"]
-- bitwise_and:
-- | bitwise_and '&' shift_expr
-- | shift_expr
bitwiseAnd :: Binding
bitwiseAnd = def "BitwiseAnd" $ T.record [
"lhs">: T.maybe $ python "BitwiseAnd",
"rhs">: python "ShiftExpression"]
-- shift_expr:
-- | shift_expr '<<' sum
-- | shift_expr '>>' sum
-- | sum
shiftExpression :: Binding
shiftExpression = def "ShiftExpression" $ T.record [
"lhs">: T.maybe $ python "ShiftLhs",
"rhs">: python "Sum"]
shiftLhs :: Binding
shiftLhs = def "ShiftLhs" $ T.record [
"operand">: python "ShiftExpression",
"operator">: python "ShiftOp"]
shiftOp :: Binding
shiftOp = def "ShiftOp" $ T.enum [
"left", "right"]
-- # Arithmetic operators
-- # --------------------
--
-- sum:
-- | sum '+' term
-- | sum '-' term
-- | term
sum_ :: Binding
sum_ = def "Sum" $ T.record [
"lhs">: T.maybe $ python "SumLhs",
"rhs">: python "Term"]
sumLhs :: Binding
sumLhs = def "SumLhs" $ T.record [
"operand">: python "Sum",
"operator">: python "SumOp"]
sumOp :: Binding
sumOp = def "SumOp" $ T.enum [
"add", "sub"]
-- term:
-- | term '*' factor
-- | term '/' factor
-- | term '//' factor
-- | term '%' factor
-- | term '@' factor
-- | factor
term :: Binding
term = def "Term" $ T.record [
"lhs">: T.maybe $ python "TermLhs",
"rhs">: python "Factor"]
termLhs :: Binding
termLhs = def "TermLhs" $ T.record [
"operand">: python "Term",
"operator">: python "TermOp"]
termOp :: Binding
termOp = def "TermOp" $ T.enum [
"mul", "div", "floordiv", "mod", "matmul"]
-- factor:
-- | '+' factor
-- | '-' factor
-- | '~' factor
-- | power
factor :: Binding
factor = def "Factor" $ T.union [
"positive">: python "Factor",
"negative">: python "Factor",
"complement">: python "Factor",
"simple">: python "Power"]
-- power:
-- | await_primary '**' factor
-- | await_primary
power :: Binding
power = def "Power" $ T.record [
"lhs">: python "AwaitPrimary",
"rhs">: T.maybe $ python "Factor"]
-- # Primary elements
-- # ----------------
--
-- # Primary elements are things like "obj.something.something", "obj[something]", "obj(something)", "obj" ...
--
-- await_primary:
-- | 'await' primary
-- | primary
awaitPrimary :: Binding
awaitPrimary = def "AwaitPrimary" $ T.record [
"await">: T.boolean,
"primary">: python "Primary"]
-- primary:
-- | primary '.' NAME
-- | primary genexp
-- | primary '(' [arguments] ')'
-- | primary '[' slices ']'
-- | atom
primary :: Binding
primary = def "Primary" $ T.union [
"simple">: python "Atom",
"compound">: python "PrimaryWithRhs"]
primaryWithRhs :: Binding
primaryWithRhs = def "PrimaryWithRhs" $ T.record [
"primary">: python "Primary",
"rhs">: python "PrimaryRhs"]
primaryRhs :: Binding
primaryRhs = def "PrimaryRhs" $ T.union [
"project">: python "Name",
"genexp">: python "Genexp",
"call">: python "Args",
"slices">: python "Slices"]
-- slices:
-- | slice !','
-- | ','.(slice | starred_expression)+ [',']
slices :: Binding
slices = def "Slices" $ T.record [
"head">: python "Slice",
"tail">: T.list $ python "SliceOrStarredExpression"]
sliceOrStarredExpression :: Binding
sliceOrStarredExpression = def "SliceOrStarredExpression" $ T.union [
"slice">: python "Slice",
"starred">: python "StarredExpression"]
-- slice:
-- | [expression] ':' [expression] [':' [expression] ]
-- | named_expression
slice :: Binding
slice = def "Slice" $ T.union [
"named">: python "NamedExpression",
"slice_">: python "SliceExpression"]
sliceExpression :: Binding
sliceExpression = def "SliceExpression" $ T.record [
"start">: T.maybe $ python "Expression",
"stop">: T.maybe $ python "Expression",
"step">: T.maybe $ python "Expression"]
-- atom:
-- | NAME
-- | 'True'
-- | 'False'
-- | 'None'
-- | strings
-- | NUMBER
-- | (tuple | group | genexp)
-- | (list | listcomp)
-- | (dict | set | dictcomp | setcomp)
-- | '...'
atom :: Binding
atom = def "Atom" $ T.union [
"name">: python "Name",
"true">: T.unit,
"false">: T.unit,
"none">: T.unit,
"string">: python "String",
"number">: python "Number",
"tuple">: python "Tuple",
"group">: python "Group",
"genexp">: python "Genexp",
"list">: python "List",
"listcomp">: python "Listcomp",
"dict">: python "Dict",
"set">: python "Set",
"dictcomp">: python "Dictcomp",
"setcomp">: python "Setcomp",
"ellipsis">: T.unit]
-- group:
-- | '(' (yield_expr | named_expression) ')'
group :: Binding
group = def "Group" $ T.union [
"yield">: python "YieldExpression",
"expression">: python "NamedExpression"]
-- # Lambda functions
-- # ----------------
--
-- lambdef:
-- | 'lambda' [lambda_params] ':' expression
lambda_ :: Binding
lambda_ = def "Lambda" $ T.record [
"params">: python "LambdaParameters",
"body">: python "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
lambdaParameters :: Binding
lambdaParameters = def "LambdaParameters" $ T.record [
"slashNoDefault">: T.maybe $ python "LambdaSlashNoDefault",
"paramNoDefault">: T.list $ python "LambdaParamNoDefault",
"paramWithDefault">: T.list $ python "LambdaParamWithDefault",
"starEtc">: T.maybe $ python "LambdaStarEtc"]
-- lambda_slash_no_default:
-- | lambda_param_no_default+ '/' ','
-- | lambda_param_no_default+ '/' &':'
lambdaSlashNoDefault :: Binding
lambdaSlashNoDefault = def "LambdaSlashNoDefault" $ T.record [
"parameters">: T.list $ python "LambdaParamNoDefault"]
-- lambda_slash_with_default:
-- | lambda_param_no_default* lambda_param_with_default+ '/' ','
-- | lambda_param_no_default* lambda_param_with_default+ '/' &':'
lambdaSlashWithDefault :: Binding
lambdaSlashWithDefault = def "LambdaSlashWithDefault" $ T.record [
"paramNoDefault">: T.list $ python "LambdaParamNoDefault",
"paramWithDefault">: nonemptyList $ python "LambdaParamWithDefault"]
-- lambda_star_etc:
-- | '*' lambda_param_no_default lambda_param_maybe_default* [lambda_kwds]
-- | '*' ',' lambda_param_maybe_default+ [lambda_kwds]
-- | lambda_kwds
lambdaStarEtc :: Binding
lambdaStarEtc = def "LambdaStarEtc" $ T.union [
"star">: T.boolean,
"paramNoDefault">: python "LambdaParamNoDefault",
"paramMaybeDefault">: T.list $ python "LambdaParamMaybeDefault",
"kwds">: python "LambdaKwds"]
-- lambda_kwds:
-- | '**' lambda_param_no_default
lambdaKwds :: Binding
lambdaKwds = def "LambdaKwds" $ T.wrap $ python "LambdaParamNoDefault"
-- lambda_param_no_default:
-- | lambda_param ','
-- | lambda_param &':'
lambdaParamNoDefault :: Binding
lambdaParamNoDefault = def "LambdaParamNoDefault" $ T.wrap $ python "Name"
-- lambda_param_with_default:
-- | lambda_param default ','
-- | lambda_param default &':'
lambdaParamWithDefault :: Binding
lambdaParamWithDefault = def "LambdaParamWithDefault" $ T.record [
"param">: python "Name",
"default">: T.maybe $ python "Default"]
-- lambda_param_maybe_default:
-- | lambda_param default? ','
-- | lambda_param default? &':'
lambdaParamMaybeDefault :: Binding
lambdaParamMaybeDefault = def "LambdaParamMaybeDefault" $ T.record [
"param">: python "Name",
"default">: T.maybe $ python "Default"]
-- lambda_param: NAME
--
-- # LITERALS
-- # ========
--
-- fstring_middle:
-- | fstring_replacement_field
-- | FSTRING_MIDDLE
-- fstring_replacement_field:
-- | '{' annotated_rhs '='? [fstring_conversion] [fstring_full_format_spec] '}'
-- fstring_conversion:
-- | "!" NAME
-- fstring_full_format_spec:
-- | ':' fstring_format_spec*
-- fstring_format_spec:
-- | FSTRING_MIDDLE
-- | fstring_replacement_field
-- fstring:
-- | FSTRING_START fstring_middle* FSTRING_END
--
-- string: STRING
-- strings: (fstring|string)+
--
-- list:
-- | '[' [star_named_expressions] ']'
list :: Binding
list = def "List" $ T.wrap $ T.list $ python "StarNamedExpression"
-- tuple:
-- | '(' [star_named_expression ',' [star_named_expressions] ] ')'
tuple :: Binding
tuple = def "Tuple" $ T.wrap $ T.list $ python "StarNamedExpression"
-- set: '{' star_named_expressions '}'
set :: Binding
set = def "Set" $ T.wrap $ nonemptyList $ python "StarNamedExpression"
-- # Dicts
-- # -----
--
-- dict:
-- | '{' [double_starred_kvpairs] '}'
dict :: Binding
dict = def "Dict" $ T.wrap $ T.list $ python "DoubleStarredKvpair"
-- double_starred_kvpairs: ','.double_starred_kvpair+ [',']
--
-- double_starred_kvpair:
-- | '**' bitwise_or
-- | kvpair
doubleStarredKvpair :: Binding
doubleStarredKvpair = def "DoubleStarredKvpair" $ T.union [
"starred">: python "BitwiseOr",
"pair">: python "Kvpair"]
-- kvpair: expression ':' expression
kvpair :: Binding
kvpair = def "Kvpair" $ T.record [
"key">: python "Expression",
"value">: python "Expression"]
-- # Comprehensions & Generators
-- # ---------------------------
--
-- for_if_clauses:
-- | for_if_clause+
forIfClauses :: Binding
forIfClauses = def "ForIfClauses" $ T.wrap $ nonemptyList $ python "ForIfClause"
-- for_if_clause:
-- | 'async' 'for' star_targets 'in' ~ disjunction ('if' disjunction )*
-- | 'for' star_targets 'in' ~ disjunction ('if' disjunction )*
forIfClause :: Binding
forIfClause = def "ForIfClause" $ T.record [
"async">: T.boolean,
"targets">: nonemptyList $ python "StarTarget",
"in">: python "Disjunction",
"ifs">: T.list $ python "Disjunction"]
-- listcomp:
-- | '[' named_expression for_if_clauses ']'
listcomp :: Binding
listcomp = def "Listcomp" $ T.record [
"expression">: python "NamedExpression",
"forIfClauses">: python "ForIfClauses"]
-- setcomp:
-- | '{' named_expression for_if_clauses '}'
setcomp :: Binding
setcomp = def "Setcomp" $ T.record [
"expression">: python "NamedExpression",
"forIfClauses">: python "ForIfClauses"]
-- genexp:
-- | '(' ( assignment_expression | expression !':=') for_if_clauses ')'
genexp :: Binding
genexp = def "Genexp" $ T.record [
"head">: python "GenexpHead",
"tail">: python "ForIfClauses"]
genexpHead :: Binding
genexpHead = def "GenexpHead" $ T.union [
"assignment">: python "AssignmentExpression",
"expression">: python "Expression"]
-- dictcomp:
-- | '{' kvpair for_if_clauses '}'
dictcomp :: Binding
dictcomp = def "Dictcomp" $ T.record [
"kvpair">: python "Kvpair",
"forIfClauses">: python "ForIfClauses"]
-- # FUNCTION CALL ARGUMENTS
-- # =======================
--
-- arguments:
-- | args [','] &')'
--
-- args:
-- | ','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ [',' kwargs ]
-- | kwargs
args :: Binding
args = def "Args" $ T.record [
"positional">: T.list $ python "PosArg",
"kwargOrStarred">: T.list $ python "KwargOrStarred",
"kwargOrDoubleStarred">: T.list $ python "KwargOrDoubleStarred"]
posArg :: Binding
posArg = def "PosArg" $ T.union [
"starred">: python "StarredExpression",
"assignment">: python "AssignmentExpression",
"expression">: python "Expression"]
-- kwargs:
-- | ','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+
-- | ','.kwarg_or_starred+
-- | ','.kwarg_or_double_starred+
--
-- starred_expression:
-- | '*' expression
starredExpression :: Binding
starredExpression = def "StarredExpression" $ T.wrap $ python "Expression"
-- kwarg_or_starred:
-- | NAME '=' expression
-- | starred_expression
kwargOrStarred :: Binding
kwargOrStarred = def "KwargOrStarred" $ T.union [
"kwarg">: python "Kwarg",
"starred">: python "StarredExpression"]
kwarg :: Binding
kwarg = def "Kwarg" $ T.record [
"name">: python "Name",
"value">: python "Expression"]
-- kwarg_or_double_starred:
-- | NAME '=' expression
-- | '**' expression
kwargOrDoubleStarred :: Binding
kwargOrDoubleStarred = def "KwargOrDoubleStarred" $ T.union [
"kwarg">: python "Kwarg",
"doubleStarred">: python "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+ [',']
starTargetsListSeq :: Binding
starTargetsListSeq = def "StarTargetsListSeq" $ T.wrap $ nonemptyList $ python "StarTarget"
-- star_targets_tuple_seq:
-- | star_target (',' star_target )+ [',']
-- | star_target ','
starTargetsTupleSeq :: Binding
starTargetsTupleSeq = def "StarTargetsTupleSeq" $ T.wrap $ nonemptyList $ python "StarTarget"
-- star_target:
-- | '*' (!'*' star_target)
-- | target_with_star_atom
starTarget :: Binding
starTarget = def "StarTarget" $ T.union [
"starred">: python "StarTarget",
"unstarred">: python "TargetWithStarAtom"]
-- target_with_star_atom:
-- | t_primary '.' NAME !t_lookahead
-- | t_primary '[' slices ']' !t_lookahead
-- | star_atom
targetWithStarAtom :: Binding
targetWithStarAtom = def "TargetWithStarAtom" $ T.union [
"project">: python "TPrimaryAndName",
"slices">: python "TPrimaryAndSlices",
"atom">: python "StarAtom"]
tPrimaryAndName :: Binding
tPrimaryAndName = def "TPrimaryAndName" $ T.record [
"primary">: python "TPrimary",
"name">: python "Name"]
tPrimaryAndSlices :: Binding
tPrimaryAndSlices = def "TPrimaryAndSlices" $ T.record [
"primary">: python "TPrimary",
"slices">: python "Slices"]
-- star_atom:
-- | NAME
-- | '(' target_with_star_atom ')'
-- | '(' [star_targets_tuple_seq] ')'
-- | '[' [star_targets_list_seq] ']'
starAtom :: Binding
starAtom = def "StarAtom" $ T.union [
"name">: python "Name",
"targetWithStarAtom">: python "TargetWithStarAtom",
"starTargetsTupleSeq">: T.maybe $ python "StarTargetsTupleSeq",
"starTargetsListSeq">: T.maybe $ python "StarTargetsListSeq"]
-- single_target:
-- | single_subscript_attribute_target
-- | NAME
-- | '(' single_target ')'
singleTarget :: Binding
singleTarget = def "SingleTarget" $ T.union [
"subscriptAttributeTarget">: python "SingleSubscriptAttributeTarget",
"name">: python "Name",
"parens">: python "SingleTarget"]
-- single_subscript_attribute_target:
-- | t_primary '.' NAME !t_lookahead
-- | t_primary '[' slices ']' !t_lookahead
singleSubscriptAttributeTarget :: Binding
singleSubscriptAttributeTarget = def "SingleSubscriptAttributeTarget" $ T.union [
"primaryAndName">: python "TPrimaryAndName",
"primaryAndSlices">: python "TPrimaryAndSlices"]
-- 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
tPrimary :: Binding
tPrimary = def "TPrimary" $ T.union [
"primaryAndName">: python "TPrimaryAndName",
"primaryAndSlices">: python "TPrimaryAndSlices",
"primaryAndGenexp">: python "TPrimaryAndGenexp",
"primaryAndArguments">: python "TPrimaryAndArguments",
"atom">: python "Atom"]
tPrimaryAndGenexp :: Binding
tPrimaryAndGenexp = def "TPrimaryAndGenexp" $ T.record [
"primary">: python "TPrimary",
"genexp">: python "Genexp"]
tPrimaryAndArguments :: Binding
tPrimaryAndArguments = def "TPrimaryAndArguments" $ T.record [
"primary">: python "TPrimary",
"arguments">: T.maybe $ python "Args"]
-- t_lookahead: '(' | '[' | '.'
--
-- # Targets for del statements
-- # --------------------------
--
-- del_targets: ','.del_target+ [',']
delTargets :: Binding
delTargets = def "DelTargets" $ T.wrap $ nonemptyList $ python "DelTarget"
-- del_target:
-- | t_primary '.' NAME !t_lookahead
-- | t_primary '[' slices ']' !t_lookahead
-- | del_t_atom
delTarget :: Binding
delTarget = def "DelTarget" $ T.union [
"primaryAndName">: python "TPrimaryAndName",
"primaryAndSlices">: python "TPrimaryAndSlices",
"delTAtom">: python "DelTAtom"]
-- del_t_atom:
-- | NAME
-- | '(' del_target ')'
-- | '(' [del_targets] ')'
-- | '[' [del_targets] ']'
delTAtom :: Binding
delTAtom = def "DelTAtom" $ T.union [
"name">: python "Name",
"target">: python "DelTarget",
"targets">: python "DelTargets"]
-- # TYPING ELEMENTS
-- # ---------------
--
-- # type_expressions allow */** but ignore them
-- type_expressions:
-- | ','.expression+ ',' '*' expression ',' '**' expression
-- | ','.expression+ ',' '*' expression
-- | ','.expression+ ',' '**' expression
-- | '*' expression ',' '**' expression
-- | '*' expression
-- | '**' expression
-- | ','.expression+
typeExpression :: Binding
typeExpression = def "TypeExpression" $ T.union [
"expression">: python "Expression",
"starredExpression">: python "Expression",
"doubleStarredExpression">: python "Expression"]
-- func_type_comment:
-- | NEWLINE TYPE_COMMENT &(NEWLINE INDENT) # Must be followed by indented block
-- | TYPE_COMMENT
funcTypeComment :: Binding
funcTypeComment = def "FuncTypeComment" $ T.wrap $ python "TypeComment"