mirror of
https://github.com/AdaCore/langkit.git
synced 2026-02-12 12:28:12 -08:00
Instead of using Python's inheritance mechanism to define enum nodes, the new mechanism requires adding enum_node = True to the class' body. Inheritance can now be used to make the enum node derive from any subclass of ASTNode instead ASTNode itself.
692 lines
16 KiB
Python
692 lines
16 KiB
Python
from __future__ import absolute_import, division, print_function
|
|
|
|
from langkit.dsl import ASTNode, Field, T, abstract
|
|
from langkit.envs import EnvSpec, add_to_env, add_env
|
|
from langkit.expressions import Self, Property, No
|
|
from langkit.parsers import Grammar, List, Opt, Or, Pick, _
|
|
from language.lexer import python_lexer as L
|
|
|
|
|
|
def newlines():
|
|
return _(List(P.nl, empty_valid=True))
|
|
|
|
|
|
class PythonNode(ASTNode):
|
|
pass
|
|
|
|
|
|
class VarArgsFlag(PythonNode):
|
|
enum_node = True
|
|
qualifier = True
|
|
|
|
|
|
class KwArgsFlag(PythonNode):
|
|
enum_node = True
|
|
qualifier = True
|
|
|
|
|
|
@abstract
|
|
class Stmt(PythonNode):
|
|
pass
|
|
|
|
|
|
class Decorator(PythonNode):
|
|
dec_name = Field(type=T.Name)
|
|
arg_list = Field(type=T.Arg.list)
|
|
|
|
|
|
class Decorated(Stmt):
|
|
decorators = Field(type=T.Decorator.list)
|
|
defn = Field(type=T.DefStmt)
|
|
|
|
|
|
class FileNode(PythonNode):
|
|
statements = Field(type=T.PythonNode.list)
|
|
|
|
|
|
@abstract
|
|
class DefStmt(Stmt):
|
|
env_spec = EnvSpec(add_env())
|
|
|
|
|
|
class FuncDef(DefStmt):
|
|
name = Field(type=T.Id)
|
|
parameters = Field(type=T.Params)
|
|
body = Field(type=T.PythonNode)
|
|
|
|
|
|
class Params(PythonNode):
|
|
single_params = Field(type=T.SingleParam.list)
|
|
|
|
|
|
class SingleParam(PythonNode):
|
|
is_varargs = Field(type=T.VarArgsFlag)
|
|
is_kwargs = Field(type=T.KwArgsFlag)
|
|
name = Field(type=T.PythonNode)
|
|
default_value = Field(type=T.Expr)
|
|
|
|
env_spec = EnvSpec(
|
|
add_to_env(Self.name.match(
|
|
lambda i=T.Id: T.env_assoc.new(key=i.sym, val=Self).singleton,
|
|
lambda l=T.Id.list: l.map(
|
|
lambda i: T.env_assoc.new(key=i.sym, val=Self)
|
|
),
|
|
lambda _: No(T.env_assoc.array)
|
|
))
|
|
)
|
|
|
|
|
|
class AugAssignStmt(Stmt):
|
|
l_value = Field(type=T.Expr.list)
|
|
op = Field(type=T.Op)
|
|
r_value = Field(type=T.PythonNode)
|
|
|
|
|
|
class AssignStmt(Stmt):
|
|
l_value = Field(type=T.Expr.list)
|
|
r_values = Field(type=T.PythonNode.list)
|
|
|
|
env_spec = EnvSpec(
|
|
add_to_env(Self.l_value.filtermap(
|
|
lambda e: T.env_assoc.new(key=e.cast_or_raise(T.Id).sym, val=Self),
|
|
lambda e: e.is_a(T.Id),
|
|
))
|
|
)
|
|
|
|
|
|
class PrintStmt(Stmt):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class StreamPrintStmt(Stmt):
|
|
stream_expr = Field(type=T.Expr)
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class DelStmt(Stmt):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class PassStmt(Stmt):
|
|
pass
|
|
|
|
|
|
class BreakStmt(Stmt):
|
|
pass
|
|
|
|
|
|
class ContinueStmt(Stmt):
|
|
pass
|
|
|
|
|
|
class ReturnStmt(Stmt):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class RaiseStmt(Stmt):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class ImportName(Stmt):
|
|
imported_names = Field(type=T.PythonNode.list)
|
|
|
|
|
|
class ImportFrom(Stmt):
|
|
rel_name = Field(type=T.PythonNode)
|
|
imported = Field(type=T.PythonNode)
|
|
|
|
|
|
class RelName(PythonNode):
|
|
dots = Field(type=T.Dot.list)
|
|
name = Field(type=T.Name)
|
|
|
|
|
|
class ImportStar(PythonNode):
|
|
pass
|
|
|
|
|
|
class AsNameNode(PythonNode):
|
|
imported = Field(type=T.Expr)
|
|
as_name = Field(type=T.Expr)
|
|
|
|
|
|
@abstract
|
|
class Expr(PythonNode):
|
|
pass
|
|
|
|
|
|
@abstract
|
|
class Name(Expr):
|
|
pass
|
|
|
|
|
|
class DottedName(Name):
|
|
prefix = Field(type=T.Expr)
|
|
suffix = Field(type=T.Id)
|
|
|
|
|
|
class CallExpr(Expr):
|
|
prefix = Field(type=T.Expr)
|
|
suffix = Field(type=T.Arg.list)
|
|
|
|
|
|
class SubscriptExpr(Expr):
|
|
prefix = Field(type=T.Expr)
|
|
suffix = Field(type=T.Expr.list)
|
|
|
|
|
|
class GlobalStmt(Stmt):
|
|
names = Field(type=T.Id.list)
|
|
|
|
|
|
class ExecStmt(Stmt):
|
|
expr = Field(type=T.Expr)
|
|
in_list = Field(type=T.Expr.list)
|
|
|
|
|
|
class AssertStmt(Stmt):
|
|
test_expr = Field(type=T.Expr)
|
|
msg = Field(type=T.Expr)
|
|
|
|
|
|
class ElsePart(PythonNode):
|
|
statements = Field(type=T.PythonNode)
|
|
|
|
|
|
class IfStmt(Stmt):
|
|
cond_test = Field(type=T.Expr)
|
|
statements = Field(type=T.PythonNode)
|
|
elif_branchs = Field(type=T.ElifBranch.list)
|
|
else_part = Field(type=T.ElsePart)
|
|
|
|
|
|
class ElifBranch(Stmt):
|
|
cond_test = Field(type=T.Expr)
|
|
statements = Field(type=T.PythonNode)
|
|
|
|
|
|
class WhileStmt(Stmt):
|
|
cond_test = Field(type=T.Expr)
|
|
statements = Field(type=T.PythonNode)
|
|
else_part = Field(type=T.ElsePart)
|
|
|
|
|
|
class ForStmt(Stmt):
|
|
bindings = Field(type=T.Expr.list)
|
|
expr = Field(type=T.Expr.list)
|
|
statements = Field(type=T.PythonNode)
|
|
else_part = Field(type=T.ElsePart)
|
|
|
|
|
|
class TryStmt(Stmt):
|
|
statements = Field(type=T.PythonNode)
|
|
except_parts = Field(type=T.ExceptPart.list)
|
|
else_part = Field(type=T.ElsePart)
|
|
finally_part = Field(type=T.PythonNode)
|
|
|
|
|
|
class ExceptPart(PythonNode):
|
|
as_name = Field(type=T.AsNameNode)
|
|
statements = Field(type=T.PythonNode)
|
|
|
|
|
|
class WithStmt(Stmt):
|
|
bindings = Field(type=T.AsNameNode.list)
|
|
statements = Field(type=T.PythonNode)
|
|
|
|
|
|
class IfExpr(Expr):
|
|
expr = Field(type=T.Expr)
|
|
cond = Field(type=T.Expr)
|
|
else_expr = Field(type=T.Expr)
|
|
|
|
|
|
class OrOp(Expr):
|
|
left = Field(type=T.Expr)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class AndOp(Expr):
|
|
left = Field(type=T.Expr)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class NotOp(Expr):
|
|
expr = Field(type=T.Expr)
|
|
|
|
|
|
class CompOpKind(PythonNode):
|
|
enum_node = True
|
|
alternatives = [
|
|
'lt', 'gt', 'eq', 'gte', 'lte', 'diamond', 'noteq',
|
|
'in', 'notin', 'is', 'isnot'
|
|
]
|
|
|
|
|
|
class CompOp(Expr):
|
|
left = Field(type=T.Expr)
|
|
op = Field(type=T.CompOpKind)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class OrExpr(Expr):
|
|
left = Field(type=T.Expr)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class XorExpr(Expr):
|
|
left = Field(type=T.Expr)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class AndExpr(Expr):
|
|
left = Field(type=T.Expr)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class Op(PythonNode):
|
|
token_node = True
|
|
|
|
|
|
@abstract
|
|
class BinOp(Expr):
|
|
left = Field(type=T.Expr)
|
|
op = Field(type=T.Op)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class ArithExpr(BinOp):
|
|
pass
|
|
|
|
|
|
class Term(BinOp):
|
|
pass
|
|
|
|
|
|
class ShiftExpr(BinOp):
|
|
pass
|
|
|
|
|
|
class Factor(Expr):
|
|
op = Field(type=T.Op)
|
|
expr = Field(type=T.Expr)
|
|
|
|
|
|
class Power(Expr):
|
|
left = Field(type=T.Expr)
|
|
right = Field(type=T.Expr)
|
|
|
|
|
|
class DictAssoc(PythonNode):
|
|
key = Field(type=T.Expr)
|
|
value = Field(type=T.Expr)
|
|
|
|
|
|
class YieldExpr(Expr):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class ListGen(Expr):
|
|
expr = Field(type=T.Expr)
|
|
comprehension = Field(type=T.CompForL)
|
|
|
|
|
|
class TupleLit(Expr):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class ListComp(Expr):
|
|
expr = Field(type=T.Expr)
|
|
comprehension = Field(type=T.CompForL)
|
|
|
|
|
|
class ListLit(Expr):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class SetComp(Expr):
|
|
expr = Field(type=T.Expr)
|
|
comprehension = Field(type=T.CompFor)
|
|
|
|
|
|
class SetLit(Expr):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class DictComp(Expr):
|
|
assoc = Field(type=T.DictAssoc)
|
|
comprehension = Field(type=T.CompFor)
|
|
|
|
|
|
class DictLit(Expr):
|
|
assocs = Field(type=T.DictAssoc.list)
|
|
|
|
|
|
class InlineEval(Expr):
|
|
exprs = Field(type=T.Expr.list)
|
|
|
|
|
|
class LambdaDef(Expr):
|
|
args = Field(type=T.Params)
|
|
expr = Field(type=T.Expr)
|
|
|
|
|
|
class EllipsisExpr(Expr):
|
|
pass
|
|
|
|
|
|
class SliceExpr(Expr):
|
|
first = Field(type=T.Expr)
|
|
last = Field(type=T.Expr)
|
|
|
|
|
|
class ExtSliceExpr(SliceExpr):
|
|
stride = Field(type=T.Expr)
|
|
|
|
|
|
class ClassDef(DefStmt):
|
|
name = Field(type=T.Id)
|
|
bases = Field(type=T.Expr.list)
|
|
statements = Field(type=T.PythonNode)
|
|
|
|
|
|
@abstract
|
|
class Arg(PythonNode):
|
|
pass
|
|
|
|
|
|
class ArgAssoc(Arg):
|
|
name = Field(type=T.Expr)
|
|
expr = Field(type=T.Expr)
|
|
|
|
|
|
class ArgGen(Arg):
|
|
expr = Field(type=T.Expr)
|
|
comprehension = Field(type=T.CompFor)
|
|
|
|
|
|
class VarArgs(Arg):
|
|
expr = Field(type=T.Expr)
|
|
|
|
|
|
class KwArgs(Arg):
|
|
expr = Field(type=T.Expr)
|
|
|
|
|
|
@abstract
|
|
class Comprehension(PythonNode):
|
|
pass
|
|
|
|
|
|
class CompFor(Comprehension):
|
|
exprs = Field(type=T.Expr.list)
|
|
target = Field(type=T.Expr)
|
|
comp = Field(type=T.PythonNode)
|
|
|
|
|
|
class CompForL(Comprehension):
|
|
exprs = Field(type=T.Expr.list)
|
|
target = Field(type=T.Expr.list)
|
|
comp = Field(type=T.PythonNode)
|
|
|
|
|
|
class CompIf(PythonNode):
|
|
test = Field(type=T.Expr)
|
|
comp = Field(type=T.PythonNode)
|
|
|
|
|
|
def TrailList(el, sep, empty_valid=False):
|
|
return Pick(List(el, sep=sep, empty_valid=empty_valid), Opt(sep))
|
|
|
|
|
|
class Id(Name):
|
|
token_node = True
|
|
|
|
sym = Property(
|
|
Self.symbol, doc="Shortcut to get the symbol of this node"
|
|
)
|
|
|
|
|
|
class NumberLit(Expr):
|
|
token_node = True
|
|
|
|
|
|
class StringLit(Expr):
|
|
token_node = True
|
|
|
|
|
|
class ConcatStringLit(Expr):
|
|
first_str = Field(type=T.StringLit)
|
|
subsequent_str = Field(type=T.StringLit.list)
|
|
|
|
|
|
class Dot(Expr):
|
|
pass
|
|
|
|
|
|
class NL(PythonNode):
|
|
pass
|
|
|
|
|
|
python_grammar = Grammar('main_rule')
|
|
P = python_grammar
|
|
|
|
python_grammar.add_rules(
|
|
name=Id(L.Identifier),
|
|
number=NumberLit(L.Number),
|
|
string=StringLit(L.String),
|
|
cat_string=ConcatStringLit(P.string, List(P.string)),
|
|
nl=NL(L.Newline),
|
|
main_rule=FileNode(
|
|
List(newlines(), P.stmt, newlines()), L.Termination
|
|
),
|
|
decorator=Decorator(
|
|
'@', P.dotted_name, Opt('(', P.arg_list, ')'), L.Newline
|
|
),
|
|
decorators=List(P.decorator),
|
|
decorated=Decorated(P.decorators, Or(P.class_def, P.func_def)),
|
|
func_def=FuncDef('def', P.name, P.parameters, ':', P.suite),
|
|
parameters=Pick('(', Opt(P.varargslist), ')'),
|
|
varargslist=Params(
|
|
List(
|
|
SingleParam(
|
|
Opt('*').as_bool(VarArgsFlag), Opt('**').as_bool(KwArgsFlag),
|
|
P.fpdef, Opt('=', P.test)
|
|
),
|
|
empty_valid=True, sep=","
|
|
),
|
|
),
|
|
fpdef=Or(P.name, Pick('(', P.name_list, ')')),
|
|
name_list=TrailList(P.name, sep=','),
|
|
stmt=Or(P.simple_stmt, P.compound_stmt),
|
|
simple_stmt=Pick(Or(P.small_stmt, TrailList(P.small_stmt, sep=';')),
|
|
L.Newline),
|
|
small_stmt=(
|
|
P.expr_stmt | P.print_stmt | P.del_stmt | P.pass_stmt | P.flow_stmt
|
|
| P.import_stmt | P.global_stmt | P.exec_stmt | P.assert_stmt
|
|
),
|
|
expr_stmt=Or(
|
|
AugAssignStmt(
|
|
P.test_list,
|
|
Op(Or('+=', '-=', '*=', '/=', '%=', '&=',
|
|
'|=', '^=', '<<=', '>>=', '**=', '//=')),
|
|
Or(P.yield_expr, P.test_list)
|
|
),
|
|
AssignStmt(
|
|
P.test_list, List(Pick('=', Or(P.yield_expr, P.test_list)))
|
|
),
|
|
P.test_list
|
|
),
|
|
print_stmt=Or(
|
|
PrintStmt('print', P.test_list),
|
|
StreamPrintStmt('print', '>>', P.test, ',', P.test_list)
|
|
),
|
|
del_stmt=DelStmt('del', P.expr_list),
|
|
pass_stmt=PassStmt('pass'),
|
|
flow_stmt=Or(
|
|
P.break_stmt, P.continue_stmt, P.return_stmt, P.raise_stmt,
|
|
P.yield_stmt
|
|
),
|
|
break_stmt=BreakStmt('break'),
|
|
continue_stmt=ContinueStmt('continue'),
|
|
return_stmt=ReturnStmt('return', Opt(P.test_list)),
|
|
yield_stmt=P.yield_expr,
|
|
raise_stmt=RaiseStmt('raise', Opt(P.test_list)),
|
|
import_stmt=Or(P.import_name, P.import_from),
|
|
import_name=ImportName('import', P.dotted_as_names),
|
|
dot=Dot('.'),
|
|
import_from=ImportFrom(
|
|
'from',
|
|
Or(P.dotted_name, RelName(List(P.dot), Opt(P.dotted_name))),
|
|
'import',
|
|
Or(ImportStar('*'),
|
|
Pick('(', P.import_as_names, ')'),
|
|
P.import_as_names),
|
|
),
|
|
as_name=AsNameNode(P.name, 'as', P.name),
|
|
dotted_as_name=AsNameNode(P.dotted_name, 'as', P.name),
|
|
import_as_names=TrailList(Or(P.as_name, P.name), sep=','),
|
|
dotted_as_names=TrailList(Or(P.dotted_as_name, P.dotted_name), sep=','),
|
|
dotted_name=DottedName(P.dotted_name, '.', P.name) | P.name,
|
|
global_stmt=GlobalStmt('global', P.name_list),
|
|
exec_stmt=ExecStmt('exec', P.expr, Opt('in', P.test_list)),
|
|
assert_stmt=AssertStmt('assert', P.test, Opt(',', P.test)),
|
|
compound_stmt=(
|
|
P.if_stmt | P.while_stmt | P.for_stmt | P.try_stmt |
|
|
P.with_stmt | P.func_def | P.class_def | P.decorated
|
|
),
|
|
else_part=ElsePart('else', ':', P.suite),
|
|
|
|
if_stmt=IfStmt(
|
|
'if', P.test, ':', P.suite,
|
|
List('elif', ElifBranch(P.test, ':', P.suite), empty_valid=True),
|
|
Opt(P.else_part)
|
|
),
|
|
|
|
while_stmt=WhileStmt('while', P.test, ':', P.suite, Opt(P.else_part)),
|
|
|
|
for_stmt=ForStmt(
|
|
'for', P.expr_list, 'in', P.test_list, ':', P.suite,
|
|
Opt(P.else_part)
|
|
),
|
|
|
|
try_stmt=TryStmt(
|
|
'try', ':', P.suite,
|
|
|
|
List(ExceptPart(
|
|
'except', Opt(AsNameNode(P.test, Opt('as', P.test))), ':',
|
|
P.suite
|
|
), empty_valid=True),
|
|
|
|
Opt(P.else_part),
|
|
Opt('finally', ':', P.suite),
|
|
),
|
|
|
|
with_stmt=WithStmt('with', List(P.with_item, sep=','), ":", P.suite),
|
|
|
|
with_item=AsNameNode(P.test, Opt('as', P.expr)),
|
|
|
|
suite=Or(
|
|
Pick(newlines(), L.Indent,
|
|
List(newlines(), P.stmt, newlines()),
|
|
L.Dedent),
|
|
P.simple_stmt,
|
|
),
|
|
test=Or(
|
|
P.lambdef,
|
|
IfExpr(P.or_test, 'if', P.or_test, 'else', P.test),
|
|
P.or_test,
|
|
),
|
|
or_test=Or(OrOp(P.or_test, 'or', P.and_test), P.and_test),
|
|
and_test=Or(AndOp(P.and_test, 'and', P.not_test), P.not_test),
|
|
not_test=Or(NotOp('not', P.not_test), P.comparison),
|
|
comparison=Or(
|
|
CompOp(
|
|
P.comparison,
|
|
CompOpKind.alt_lt('<')
|
|
| CompOpKind.alt_gt('>')
|
|
| CompOpKind.alt_eq('==')
|
|
| CompOpKind.alt_gte('>=')
|
|
| CompOpKind.alt_lte('<=')
|
|
| CompOpKind.alt_diamond('<>')
|
|
| CompOpKind.alt_noteq('!=')
|
|
| CompOpKind.alt_in('in')
|
|
| CompOpKind.alt_notin('not', 'in')
|
|
| CompOpKind.alt_isnot('is', 'not')
|
|
| CompOpKind.alt_is('is'),
|
|
P.expr
|
|
),
|
|
P.expr
|
|
),
|
|
expr=Or(OrExpr(P.expr, '|', P.xor_expr), P.xor_expr),
|
|
xor_expr=Or(XorExpr(P.xor_expr, '^', P.and_expr), P.and_expr),
|
|
and_expr=Or(AndExpr(P.and_expr, '&', P.shift_expr), P.shift_expr),
|
|
shift_expr=Or(
|
|
ShiftExpr(P.shift_expr, Op(Or('<<', '>>')), P.arith_expr),
|
|
P.arith_expr
|
|
),
|
|
arith_expr=Or(ArithExpr(P.arith_expr, Op(Or('+', '-')), P.term), P.term),
|
|
term=Or(Term(P.term, Op(Or('*', '/', '%', '//')), P.factor), P.factor),
|
|
factor=Or(Factor(Op(Or('+', '-', '~')), P.factor), P.power),
|
|
power=Or(Power(P.atom_expr, '**', P.factor), P.atom_expr),
|
|
|
|
atom_expr=Or(
|
|
DottedName(P.atom_expr, ".", P.name),
|
|
CallExpr(P.atom_expr, '(', P.arg_list, ')'),
|
|
SubscriptExpr(P.atom_expr, '[', P.subscript_list, ']'),
|
|
P.atom
|
|
),
|
|
|
|
dict_assoc=DictAssoc(P.test, ':', P.test),
|
|
yield_expr=YieldExpr('yield', Opt(P.test_list)),
|
|
atom=Or(
|
|
Pick('(', P.yield_expr, ')'),
|
|
ListGen('(', P.test, P.list_for, ')'),
|
|
TupleLit('(', Opt(P.test_list), ')'),
|
|
ListComp('[', P.test, P.list_for, ']'),
|
|
ListLit('[', P.empty_test_list, ']'),
|
|
SetComp('{', P.test, P.comp_for, '}'),
|
|
P.set_lit,
|
|
DictComp('{', P.dict_assoc, P.comp_for, '}'),
|
|
DictLit('{', TrailList(P.dict_assoc, sep=','), '}'),
|
|
InlineEval('`', P.test_list, '`'),
|
|
P.name,
|
|
P.number,
|
|
P.cat_string,
|
|
P.string
|
|
),
|
|
set_lit=SetLit('{', P.empty_test_list, '}'),
|
|
lambdef=LambdaDef('lambda', P.varargslist, ':', P.test),
|
|
subscript_list=TrailList(P.subscript, sep=","),
|
|
subscript=Or(
|
|
EllipsisExpr('.', '.', '.'),
|
|
ExtSliceExpr(Opt(P.test), ':', Opt(P.test), ':', Opt(P.test)),
|
|
SliceExpr(Opt(P.test), ':', Opt(P.test)),
|
|
P.test,
|
|
),
|
|
expr_list=TrailList(P.expr, ','),
|
|
test_list=TrailList(P.test, ','),
|
|
empty_test_list=TrailList(P.test, ',', empty_valid=True),
|
|
class_def=ClassDef(
|
|
'class', P.name, Opt('(', Opt(P.test_list), ')'), ':', P.suite
|
|
),
|
|
arg_list=TrailList(Or(
|
|
ArgGen(P.test, P.comp_for),
|
|
ArgAssoc(Opt(P.test, '='), P.test),
|
|
VarArgs('*', P.test),
|
|
KwArgs('**', P.test),
|
|
), sep=",", empty_valid=True),
|
|
|
|
list_iter=Or(P.list_for, P.list_if),
|
|
list_for=CompForL(
|
|
'for', P.expr_list, 'in', P.test_list, Opt(P.list_iter)
|
|
),
|
|
list_if=CompIf('if', P.test, Opt(P.list_iter)),
|
|
|
|
comp_iter=Or(P.comp_for, P.comp_if),
|
|
comp_for=CompFor(
|
|
'for', P.expr_list, 'in', P.or_test, Opt(P.comp_iter)
|
|
),
|
|
comp_if=CompIf('if', P.test, Opt(P.comp_iter))
|
|
)
|