From 6c51a7f351b906f8453a965c3c44c420a9a73ef8 Mon Sep 17 00:00:00 2001 From: Joshua Shinavier Date: Mon, 6 Nov 2023 06:03:01 -0800 Subject: [PATCH] Add a Python3 syntax model, based on the official Python BNF. See #80. --- .../src/main/haskell/Hydra/Dsl/Grammars.hs | 8 + .../main/haskell/Hydra/Sources/Tier4/All.hs | 2 + .../Sources/Tier4/Langs/Cypher/OpenCypher.hs | 2 +- .../Sources/Tier4/Langs/Python/Python3.hs | 1399 +++++++++++++++++ 4 files changed, 1410 insertions(+), 1 deletion(-) create mode 100644 hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Python/Python3.hs diff --git a/hydra-haskell/src/main/haskell/Hydra/Dsl/Grammars.hs b/hydra-haskell/src/main/haskell/Hydra/Dsl/Grammars.hs index 52fd9f795..ff735311a 100644 --- a/hydra-haskell/src/main/haskell/Hydra/Dsl/Grammars.hs +++ b/hydra-haskell/src/main/haskell/Hydra/Dsl/Grammars.hs @@ -41,6 +41,14 @@ plus = G.PatternPlus regex :: String -> G.Pattern regex = G.PatternRegex . G.Regex +-- | A helper which matches patterns like "foo.bar.quux" or "one; two; three; four" +sep :: G.Pattern -> G.Pattern -> G.Pattern +sep separator pat = list[pat, star(list[separator, pat])] + +-- | A helper which matches patterns like "foo.bar.quux" or "foo.bar.quux." (i.e. trailing separators are allowed) +sepp :: G.Pattern -> G.Pattern -> G.Pattern +sepp separator pat = list[pat, star(list[separator, pat]), opt(separator)] + star :: G.Pattern -> G.Pattern star = G.PatternStar diff --git a/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/All.hs b/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/All.hs index 35ab2b008..4f5e78018 100644 --- a/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/All.hs +++ b/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/All.hs @@ -19,6 +19,7 @@ import Hydra.Sources.Tier4.Langs.Protobuf.Any import Hydra.Sources.Tier4.Langs.Protobuf.Language import Hydra.Sources.Tier4.Langs.Protobuf.Proto3 import Hydra.Sources.Tier4.Langs.Protobuf.SourceContext +import Hydra.Sources.Tier4.Langs.Python.Python3 import Hydra.Sources.Tier4.Langs.Rdf.Syntax import Hydra.Sources.Tier4.Langs.RelationalModel import Hydra.Sources.Tier4.Langs.Scala.Meta @@ -61,6 +62,7 @@ tier4LangModules = [ protobufAnyModule, protobufLanguageModule, protobufSourceContextModule, + python3Module, rdfSyntaxModule, relationalModelModule, scalaMetaModule, diff --git a/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Cypher/OpenCypher.hs b/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Cypher/OpenCypher.hs index 51ad4627f..24157f545 100644 --- a/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Cypher/OpenCypher.hs +++ b/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Cypher/OpenCypher.hs @@ -13,7 +13,7 @@ cypherNs = Namespace "hydra/langs/cypher/openCypher" cypher = typeref cypherNs openCypherModule :: Module Kv -openCypherModule = Module cypherNs elements [hydraCoreModule] $ +openCypherModule = Module cypherNs elements [] [hydraCoreModule] $ Just "An OpenCypher query model based on the M23 EBNF grammar. See https://opencypher.org/resources." where def = datatype cypherNs diff --git a/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Python/Python3.hs b/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Python/Python3.hs new file mode 100644 index 000000000..bbf0bf90e --- /dev/null +++ b/hydra-haskell/src/main/haskell/Hydra/Sources/Tier4/Langs/Python/Python3.hs @@ -0,0 +1,1399 @@ +{-# 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 Kv +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"]]]