def operator(mod): op = ast.Add() if mod == 'or': op = ast.Or() if mod == '|': op = ast.Or() if mod == '||': op = ast.Or() if mod == 'and': op = ast.And() if mod == '&': op = ast.And() if mod == '&&': op = ast.And() if mod == 'plus': op = ast.Add() if mod == '+': op = ast.Add() if mod == '-': op = ast.Sub() if mod == 'minus': op = ast.Sub() if mod == 'times': op = ast.Mult() if mod == '*': op = ast.Mult() if mod == '**': op = ast.Pow() if mod == 'divide': op = ast.Div() if mod == 'divided': op = ast.Div() if mod == 'divided by': op = ast.Div() if mod == '/': op = ast.Div() if mod == '//': op = ast.FloorDiv() if mod == 'floor div': op = ast.FloorDiv() if mod == '%': op = ast.Mod() if mod == 'mod': op = ast.Mod() if mod == 'modulus': op = ast.Mod() if mod == 'modulo': op = ast.Mod() if mod == '^': op = ast.BitXor() if mod == 'xor': op = ast.BitXor() if mod == '<<': op = ast.LShift() if mod == '>>': op = ast.RShift() return op
def binop_action(s, loc, tokens): node = tokens[0] for op_char, right in tokens[1:]: if op_char == '+': op = ast.Add() elif op_char == '-': op = ast.Sub() elif op_char == '*': op = ast.Mult() elif op_char == '/': op = ast.Div() elif op_char == '%': op = ast.Mod() elif op_char == '<<': op = ast.LShift() elif op_char == '>>': op = ast.RShift() elif op_char == '&': op = ast.BitAnd() elif op_char == '^': op = ast.BitXor() else: # op_char == '|': op = ast.BitOr() node = ast.BinOp(left=node, op=op, right=right, lineno=1, col_offset=0) return node
def get_bin_op(self, s): """Get the BinOp class for s.""" op = None if s == '+': op = ast.Add() elif s == '-': op = ast.Sub() elif s == '*': op = ast.Mult() elif s == '/': op = ast.Div() elif s == '%': op = ast.Mod() elif s == '<<': op = ast.LShift() elif s == '>>': op = ast.RShift() elif s == '&': op = ast.BitAnd() elif s == '^': op = ast.BitXor() elif s == '|': op = ast.BitOr() return op
def __build_unconditional_arg_check(self, argname, argtype): presence_check = ast.Call( func=ast.Name(id='isinstance', ctx=ast.Load()), args=[ast.Name(id=argname, ctx=ast.Load()), argtype], keywords=[], lineno=self.__get_line()) types = [t.id for t in argtype.elts] check_message = ast.BinOp(left=ast.Str( s='Argument \'{}\' must be of type \'{}\'. Received type: \'%s\''. format(argname, types)), op=ast.Mod(), right=ast.Call(func=ast.Name(id='type', ctx=ast.Load()), args=[ ast.Name(id=argname, ctx=ast.Load()) ], keywords=[]), lineno=self.__get_line()) new_ret = ast.Assert(test=presence_check, msg=check_message, lineno=self.__get_line()) return new_ret
def __init__(self, base_node): BaseMutator.__init__(self, base_node) self.original_bin_op = base_node.op if type(base_node.op) in [ ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod, ast.Pow ]: if type(base_node.op) is ast.Add: # Don't perform the mutation for string concatenation (e.g. 'string' + 'concat') if (type(base_node.left) is not ast.Str) and (type( base_node.right) is not ast.Str): self.mutations.append({"op": ast.Sub()}) if type(base_node.op) is ast.Sub: self.mutations.append({"op": ast.Add()}) if type(base_node.op) is ast.Mult: # Don't perform the mutation for string repetition (e.g. 'string' * 50) if (type(base_node.left) is not ast.Str) and (type( base_node.right) is not ast.Str): self.mutations.append({"op": ast.Div()}) if type(base_node.op) is ast.Div: self.mutations.append({"op": ast.Mult()}) if type(base_node.op) is ast.Mod: # Don't perform the mutation for string format (e.g. 'strings are %s' % 'cool') if (type(base_node.left) is not ast.Str) and (type( base_node.right) is not ast.Str): self.mutations.append({"op": ast.Pow()}) if type(base_node.op) is ast.Pow: self.mutations.append({"op": ast.Mod()})
def _create_repr_method(self): """Create the __repr__ method. def __repr__(self) -> str: return ('Attribute(name=%r, value=%r)' % (self.name, self.value)) """ node = ast.FunctionDef( name="__repr__", args=ast.arguments( args=[ast.arg(arg="self", annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[], ), body=[], decorator_list=[], returns=ast.Name(id="str"), ) node.body.append( ast.Return(value=ast.BinOp( left=ast.Str(s="%s(%s)" % ( self.resource.name, ", ".join(f"{attr}=%r" for attr in self.attribute_names), )), op=ast.Mod(), right=ast.Tuple(elts=[ ast.Name(id=f"self.{attr}") for attr in self.attribute_names ]), ))) return node
def visit_Operator(self, node: Operator, *args, **kwargs) -> C.operator: if node == Operator.Add: return C.Add() elif node == Operator.Sub: return C.Sub() elif node == Operator.Mult: return C.Mult() elif node == Operator.MatMult: return C.MatMult() elif node == Operator.Div: return C.Div() elif node == Operator.Mod: return C.Mod() elif node == Operator.Pow: return C.Pow() elif node == Operator.LShift: return C.LShift() elif node == Operator.RShift: return C.RShift() elif node == Operator.BitOr: return C.BitOr() elif node == Operator.BitXor: return C.BitXor() elif node == Operator.BitAnd: return C.BitAnd() elif node == Operator.FloorDiv: return C.FloorDiv() else: raise Exception(f'unknown Operator {node!r}')
def __build_unconditional_arg_check(self, argname, argtype): # checker_str = "assert isinstance({argname}, {typetuple}), \"Argument {argname} must be of type {typetuple}. Received type: %s\" % type({argname})".format( # argname = argname, # typetuple = argtype, # ) # checker = ast.parse(checker_str) # old_ret = checker.body.pop() presence_check = ast.Call(func = ast.Name(id='isinstance', ctx=ast.Load()), args = [ast.Name(id=argname, ctx=ast.Load()), argtype], keywords = [], lineno = self.__get_line()) check_message = ast.BinOp( left = ast.Str(s='Argument {} must be of type ({}). Received type: %s'.format(argname, argtype)), op = ast.Mod(), right = ast.Call(func=ast.Name(id='type', ctx=ast.Load()), args=[ast.Name(id=argname, ctx=ast.Load())], keywords=[]), lineno = self.__get_line()) new_ret = ast.Assert( test = presence_check, msg = check_message, lineno = self.__get_line()) return new_ret
def visit_Str(self, node): replacements = re.findall(r'#{[^}]+}', node.s) if not replacements: return node s = node.s for rep in replacements: s = s.replace(rep, '%s') elements = [ast.parse(rep[2:-1]).body[0].value for rep in replacements] node = ast.BinOp(ast.Str(s), ast.Mod(), make_tuple(*elements)) return node
def pop_format_context(self, expl_expr): current = self.stack.pop() if self.stack: self.explanation_specifiers = self.stack[-1] keys = [ast.Str(key) for key in current.keys()] format_dict = ast.Dict(keys, list(current.values())) form = ast.BinOp(expl_expr, ast.Mod(), format_dict) name = "@py_format" + str(next(self.variable_counter)) self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) return ast.Name(name, ast.Load())
def eval_opo(op, value, v1, v2, v): # Extra args for future use # fmt: off return conde( (eq(op, ast.Add()), eq(value, add)), (eq(op, ast.Sub()), eq(value, sub)), (eq(op, ast.Mult()), eq(value, mul)), ( eq(op, ast.Mod()), neq(v2, 0), # Prevent division by zero eq(value, mod)), )
def test_scalar_bin_op_init(self): ScalarBinOp(self.constant, ast.Add(), self.constant) ScalarBinOp(self.output_element, ast.Add(), self.neighbor) ScalarBinOp(self.output_element, ast.Sub(), self.neighbor) ScalarBinOp(self.output_element, ast.Mult(), self.neighbor) ScalarBinOp(self.output_element, ast.Div(), self.neighbor) ScalarBinOp(self.output_element, ast.FloorDiv(), self.neighbor) ScalarBinOp(self.output_element, ast.Mod(), self.neighbor) for op in [ ast.Mod, ast.Pow, ast.LShift, ast.RShift, ast.BitOr, ast.BitXor, ast.BitAnd ]: with self.assertRaises(AssertionError): ScalarBinOp(self.output_element, op, self.neighbor)
def visit_UnaryOp(self, node): 'Same idea as visit_BinOp' if node in self.constexpr: # evaluation fake_node = ast.Expression( ast.BinOp(node, ast.Mod(), ast.Num(self.mod))) ast.fix_missing_locations(fake_node) code = compile(fake_node, '<constant folding>', 'eval') obj_env = globals().copy() exec code in obj_env value = eval(code, obj_env) new_node = ast.Num(value) return new_node else: return self.generic_visit(node)
def operator_equals(mod): op = ast.Add() if mod == '|=': op = ast.Or() if mod == '||=': op = ast.Or() if mod == '&=': op = ast.And() if mod == '&&=': op = ast.And() if mod == '+=': op = ast.Add() if mod == '-=': op = ast.Sub() if mod == '*=': op = ast.Mult() if mod == '**=': op = ast.Pow() if mod == '/=': op = ast.Div() if mod == '//=': op = ast.FloorDiv() if mod == '%=': op = ast.Mod() if mod == '^=': op = ast.BitXor() if mod == '<<': op = ast.LShift() if mod == '>>': op = ast.RShift() return op
def create_term_node(self, term): last_factor_index = len(term.factors) node = self.to_node(term.factors[0]) if last_factor_index == 0: return node for i in range(1, last_factor_index): if term.operators[i - 1] in ["*", "times"]: node = ast.BinOp(node, ast.Mult(), self.to_node(term.factors[i])) elif term.operators[i - 1] in ["/", "divided by"]: node = ast.BinOp(node, ast.Div(), self.to_node(term.factors[i])) elif term.operators[i - 1] in ["%", "modulo"]: node = ast.BinOp(node, ast.Mod(), self.to_node(term.factors[i])) else: raise return node
def pop_format_context(self, expl_expr): """Format the %-formatted string with current format context. The expl_expr should be an ast.Str instance constructed from the %-placeholders created by .explanation_param(). This will add the required code to format said string to .on_failure and return the ast.Name instance of the formatted string. """ current = self.stack.pop() if self.stack: self.explanation_specifiers = self.stack[-1] keys = [ast.Str(key) for key in current.keys()] format_dict = ast.Dict(keys, list(current.values())) form = ast.BinOp(expl_expr, ast.Mod(), format_dict) name = "@py_format" + str(next(self.variable_counter)) self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form)) return ast.Name(name, ast.Load())
def test_for_expr_args(self): start = ast.BinOp(ast.Num(2), ast.Add(), ast.Num(3)) stop = ast.BinOp(ast.Num(4), ast.Mult(), ast.Num(10)) step = ast.BinOp(ast.Num(3), ast.Mod(), ast.Num(5)) py_ast = ast.For( ast.Name("i", ast.Load()), ast.Call(ast.Name("range", ast.Load()), [start, stop, step], [], None, None), [ast.Name("foo", ast.Load())], [], ) i = SymbolRef("i", Long()) c_ast = For( Assign(i, Add(Constant(2), Constant(3))), Lt(i.copy(), Mul(Constant(4), Constant(10))), AddAssign(i.copy(), Mod(Constant(3), Constant(5))), [SymbolRef("foo")], ) self._check(py_ast, c_ast)
def to_node(self): node = self.left.to_node() if len(self.operator) == 0: return node else: for i in range(len(self.right)): if self.operator[i] in ['*', 'times']: node = ast.BinOp(node, ast.Mult(), self.right[i].to_node()) elif self.operator[i] in ['/', 'divided by']: node = ast.BinOp(node, ast.Div(), self.right[i].to_node()) elif self.operator[i] in ['%', 'modulo']: node = ast.BinOp(node, ast.Mod(), self.right[i].to_node()) elif self.operator[i] == '@': node = ast.BinOp(node, ast.MatMult(), self.right[i].to_node()) elif self.operator[i] == '//': node = ast.BinOp(node, ast.FloorDiv(), self.right[i].to_node()) return node
def __build_conditional_arg_check(self, argname, argtype): target_value = ast.Subscript(value=ast.Name(id='kwargs', ctx=ast.Load()), slice=ast.Index(ast.Str(s=argname)), ctx=ast.Load()) presence_check = ast.Call(func=ast.Name(id='isinstance', ctx=ast.Load()), args=[target_value, argtype], keywords=[], lineno=self.__get_line()) # Assumes that argtype is a ast.Tuple of ast.Name items types = [t.id for t in argtype.elts] check_message = ast.BinOp(left=ast.Str( s='Optional argument \'{}\' must be of type \'{}\'. Received type: \'%s\'' .format(argname, types)), op=ast.Mod(), right=ast.Call(func=ast.Name(id='type', ctx=ast.Load()), args=[target_value], keywords=[]), lineno=self.__get_line()) assert_check = ast.Assert(test=presence_check, msg=check_message, lineno=self.__get_line()) check_body = [assert_check] check = ast.Compare( left=ast.Str(s=argname, ctx=ast.Load()), ops=[ast.In()], comparators=[ast.Name(id='kwargs', ctx=ast.Load())]) new_ret = ast.If(test=check, body=check_body, orelse=[], lineno=self.__get_line()) return new_ret
def resolve_value(value, scope): if isinstance(value, EId): node = ast.Name(id=value.v, ctx=ast.Load()) elif isinstance(value, EInt): node = ast.Num(n=value.v) elif isinstance(value, EList): lst = [resolve_value(a, scope) for a in value.v] node = ast.List(elts=lst, ctx=ast.Load()) elif isinstance(value, EOp): lft, rgt = value.v lft = resolve_value(lft, scope) rgt = resolve_value(rgt, scope) operators = { '+': ast.Add(), '-': ast.Sub(), '*': ast.Mult(), '/': ast.Div(), '%': ast.Mod(), } node = ast.BinOp(left=lft, right=rgt, op=operators[value.t]) elif isinstance(value, ECompare): lft, rgt = value.v lft = resolve_value(lft, scope) rgt = resolve_value(rgt, scope) operators = { '<': ast.Lt(), '>': ast.Gt(), '<=': ast.LtE(), '>=': ast.GtE(), '==': ast.Eq(), } node = ast.Compare(left=lft, ops=[operators[value.t]], comparators=[rgt]) return ast.fix_missing_locations(node)
def BinOp(draw, expression) -> ast.BinOp: op = draw( sampled_from([ ast.Add(), ast.Sub(), ast.Mult(), ast.Div(), ast.FloorDiv(), ast.Mod(), ast.Pow(), ast.LShift(), ast.RShift(), ast.BitOr(), ast.BitXor(), ast.BitOr(), ast.BitAnd(), ast.MatMult() ])) le = draw(lists(expression, min_size=2, max_size=2)) return ast.BinOp(le[0], op, le[1])
def AugAssign(draw): op = draw( sampled_from([ ast.Add(), ast.Sub(), ast.Mult(), ast.Div(), ast.FloorDiv(), ast.Mod(), ast.Pow(), ast.LShift(), ast.RShift(), ast.BitOr(), ast.BitXor(), ast.BitOr(), ast.BitAnd(), ast.MatMult() ])) return ast.AugAssign(target=draw(Name(ast.Store)), op=op, value=draw(expression()))
"divided with": ast.Div(), "divided by": ast.Div(), "divide": ast.Div(), "divide with": ast.Div(), "divide by": ast.Div(), "xor": ast.BitXor(), # "^": ast.BitXor(), "^": ast.Pow(), "^^": ast.Pow(), "**": ast.Pow(), "pow": ast.Pow(), "power": ast.Pow(), "to the": ast.Pow(), "to the power": ast.Pow(), "to the power of": ast.Pow(), "%": ast.Mod(), "mod": ast.Mod(), "modulo": ast.Mod(), "!": ast.Not(), "not": ast.Not(), "&": ast.And(), # BitAnd ENGLISH: a & b ~== a and b "&&": ast.And(), "and": ast.And(), "|": ast.BitOr(), "||": ast.Or(), "or": ast.Or(), "does not equal": ast.NotEq(), "doesn't equal": ast.NotEq(), "not equal": ast.NotEq(), "is not": ast.NotEq(), "isn't": ast.NotEq(),
def as_ast(dct): """See https://docs.python.org/2/library/ast.html""" if dct['ast_type'] == "Module": return ast.Module(dct["body"]) elif dct['ast_type'] == "Interactive": return ast.Interactive(dct["body"]) elif dct['ast_type'] == "Expression": return ast.Expression(dct["body"]) elif dct['ast_type'] == "Suite": return ast.Suite(dct["body"]) elif dct['ast_type'] == "FunctionDef": return ast.FunctionDef(dct["name"], dct["args"], dct["body"], dct["decorator_list"]) elif dct['ast_type'] == "ClassDef": return ast.ClassDef(dct["name"], dct["bases"], dct["body"], dct["decorator_list"]) elif dct['ast_type'] == "Return": return ast.Return(dct["value"]) elif dct['ast_type'] == "Delete": return ast.Delete(dct["targets"]) elif dct['ast_type'] == "Assign": return ast.Assign(dct["targets"], dct["value"]) elif dct['ast_type'] == "AugAssign": return ast.AugAssign(dct["target"], dct["op"], dct["value"]) elif dct['ast_type'] == "Print": return ast.Print(dct["dest"], dct["values"], dct["nl"]) elif dct['ast_type'] == "For": return ast.For(dct["target"], dct["iter"], dct["body"], dct["orelse"]) elif dct['ast_type'] == "While": return ast.While(dct["test"], dct["body"], dct["orelse"]) elif dct['ast_type'] == "If": return ast.If(dct["test"], dct["body"], dct["orelse"]) elif dct['ast_type'] == "With": return ast.With(dct["context_expr"], dct["optional_vars"], dct["body"]) elif dct['ast_type'] == "Raise": return ast.Raise(dct["type"], dct["inst"], dct["tback"]) elif dct['ast_type'] == "TryExcept": return ast.TryExcept(dct["body"], dct["handlers"], dct["orelse"]) elif dct['ast_type'] == "TryFinally": return ast.TryFinally(dct["body"], dct["finalbody"]) elif dct['ast_type'] == "Assert": return ast.Assert(dct["test"], dct["msg"]) elif dct['ast_type'] == "Import": return ast.Import(dct["names"]) elif dct['ast_type'] == "ImportFrom": return ast.ImportFrom(dct["module"], dct["names"], dct["level"]) elif dct['ast_type'] == "Exec": return ast.Exec(dct["body"], dct["globals"], dct["locals"]) elif dct['ast_type'] == "Global": return ast.Global(dct["names"]) elif dct['ast_type'] == "Expr": return ast.Expr(dct["value"]) elif dct['ast_type'] == "Pass": return ast.Pass() elif dct['ast_type'] == "Break": return ast.Break() elif dct['ast_type'] == "Continue": return ast.Continue() elif dct['ast_type'] == "BoolOp": return ast.BoolOp(dct["op"], dct["values"]) elif dct['ast_type'] == "BinOp": return ast.BinOp(dct["left"], dct["op"], dct["right"]) elif dct['ast_type'] == "UnaryOp": return ast.UnaryOp(dct["op"], dct["operand"]) elif dct['ast_type'] == "Lambda": return ast.Lambda(dct["args"], dct["body"]) elif dct['ast_type'] == "IfExp": return ast.IfExp(dct["test"], dct["body"], dct["orelse"]) elif dct['ast_type'] == "Dict": return ast.Dict(dct["keys"], dct["values"]) elif dct['ast_type'] == "Set": return ast.Set(dct["elts"]) elif dct['ast_type'] == "ListComp": return ast.ListComp(dct["elt"], dct["generators"]) elif dct['ast_type'] == "SetComp": return ast.SetComp(dct["elt"], dct["generators"]) elif dct['ast_type'] == "DictComp": return ast.DictComp(dct["key"], dct["value"], dct["generators"]) elif dct['ast_type'] == "GeneratorExp": return ast.GeneratorExp(dct["elt"], dct["generators"]) elif dct['ast_type'] == "Yield": return ast.Yield(dct["value"]) elif dct['ast_type'] == "Compare": return ast.Compare(dct["left"], dct["ops"], dct["comparators"]) elif dct['ast_type'] == "Call": return ast.Call(dct["func"], dct["args"], dct["keywords"], dct["starargs"], dct["kwargs"]) elif dct['ast_type'] == "Repr": return ast.Repr(dct["value"]) elif dct['ast_type'] == "Num": return ast.Num(dct["n"]) elif dct['ast_type'] == "Str": # Converting to ASCII return ast.Str(dct["s"].encode('ascii', 'ignore')) elif dct['ast_type'] == "Attribute": return ast.Attribute(dct["value"], dct["attr"], dct["ctx"]) elif dct['ast_type'] == "Subscript": return ast.Subscript(dct["value"], dct["slice"], dct["ctx"]) elif dct['ast_type'] == "Name": return ast.Name(dct["id"], dct["ctx"]) elif dct['ast_type'] == "List": return ast.List(dct["elts"], dct["ctx"]) elif dct['ast_type'] == "Tuple": return ast.Tuple(dct["elts"], dct["ctx"]) elif dct['ast_type'] == "Load": return ast.Load() elif dct['ast_type'] == "Store": return ast.Store() elif dct['ast_type'] == "Del": return ast.Del() elif dct['ast_type'] == "AugLoad": return ast.AugLoad() elif dct['ast_type'] == "AugStore": return ast.AugStore() elif dct['ast_type'] == "Param": return ast.Param() elif dct['ast_type'] == "Ellipsis": return ast.Ellipsis() elif dct['ast_type'] == "Slice": return ast.Slice(dct["lower"], dct["upper"], dct["step"]) elif dct['ast_type'] == "ExtSlice": return ast.ExtSlice(dct["dims"]) elif dct['ast_type'] == "Index": return ast.Index(dct["value"]) elif dct['ast_type'] == "And": return ast.And() elif dct['ast_type'] == "Or": return ast.Or() elif dct['ast_type'] == "Add": return ast.Add() elif dct['ast_type'] == "Sub": return ast.Sub() elif dct['ast_type'] == "Mult": return ast.Mult() elif dct['ast_type'] == "Div": return ast.Div() elif dct['ast_type'] == "Mod": return ast.Mod() elif dct['ast_type'] == "Pow": return ast.Pow() elif dct['ast_type'] == "LShift": return ast.LShift() elif dct['ast_type'] == "RShift": return ast.RShift() elif dct['ast_type'] == "BitOr": return ast.BitOr() elif dct['ast_type'] == "BitXor": return ast.BitXor() elif dct['ast_type'] == "BitAnd": return ast.BitAnd() elif dct['ast_type'] == "FloorDiv": return ast.FloorDiv() elif dct['ast_type'] == "Invert": return ast.Invert() elif dct['ast_type'] == "Not": return ast.Not() elif dct['ast_type'] == "UAdd": return ast.UAdd() elif dct['ast_type'] == "USub": return ast.USub() elif dct['ast_type'] == "Eq": return ast.Eq() elif dct['ast_type'] == "NotEq": return ast.NotEq() elif dct['ast_type'] == "Lt": return ast.Lt() elif dct['ast_type'] == "LtE": return ast.LtE() elif dct['ast_type'] == "Gt": return ast.Gt() elif dct['ast_type'] == "GtE": return ast.GtE() elif dct['ast_type'] == "Is": return ast.Is() elif dct['ast_type'] == "IsNot": return ast.IsNot() elif dct['ast_type'] == "In": return ast.In() elif dct['ast_type'] == "NotIn": return ast.NotIn() elif dct['ast_type'] == "comprehension": return ast.comprehension(dct["target"], dct["iter"], dct["ifs"]) elif dct['ast_type'] == "ExceptHandler": return ast.ExceptHandler(dct["type"], dct["name"], dct["body"]) elif dct['ast_type'] == "arguments": return ast.arguments(dct["args"], dct["vararg"], dct["kwarg"], dct["defaults"]) elif dct['ast_type'] == "keyword": return ast.keyword(dct["arg"], dct["value"]) elif dct['ast_type'] == "alias": return ast.alias(dct["name"], dct["asname"]) else: return dct
def from_phpast(node): if node is None: return py.Pass(**pos(node)) if isinstance(node, str): return py.Str(node, **pos(node)) if isinstance(node, (int, float)): return py.Num(node, **pos(node)) if isinstance(node, php.Array): if node.nodes: if node.nodes[0].key is not None: keys = [] values = [] for elem in node.nodes: keys.append(from_phpast(elem.key)) values.append(from_phpast(elem.value)) return py.Dict(keys, values, **pos(node)) else: return py.List([from_phpast(x.value) for x in node.nodes], py.Load(**pos(node)), **pos(node)) else: return py.List([], py.Load(**pos(node)), **pos(node)) if isinstance(node, php.InlineHTML): args = [py.Str(node.data, **pos(node))] return py.Call( py.Name('inline_html', py.Load(**pos(node)), **pos(node)), args, [], None, None, **pos(node)) if isinstance(node, php.Echo): return py.Call(py.Name('echo', py.Load(**pos(node)), **pos(node)), list(map(from_phpast, node.nodes)), [], None, None, **pos(node)) if isinstance(node, php.Print): return py.Print(None, [from_phpast(node.node)], True, **pos(node)) if isinstance(node, php.Exit): args = [] if node.expr is not None: args.append(from_phpast(node.expr)) return py.Raise( py.Call(py.Name('Exit', py.Load(**pos(node)), **pos(node)), args, [], None, None, **pos(node)), None, None, **pos(node)) if isinstance(node, php.Return): if node.node is None: return py.Return(None, **pos(node)) else: return py.Return(from_phpast(node.node), **pos(node)) if isinstance(node, php.Break): assert node.node is None, 'level on break not supported' return py.Break(**pos(node)) if isinstance(node, php.Continue): assert node.node is None, 'level on continue not supported' return py.Continue(**pos(node)) if isinstance(node, php.Silence): return from_phpast(node.expr) if isinstance(node, php.Block): return from_phpast(php.If(1, node, [], None, lineno=node.lineno)) if isinstance(node, php.Unset): return py.Delete(list(map(from_phpast, node.nodes)), **pos(node)) if isinstance(node, php.IsSet) and len(node.nodes) == 1: if isinstance(node.nodes[0], php.ArrayOffset): return py.Compare(from_phpast(node.nodes[0].expr), [py.In(**pos(node))], [from_phpast(node.nodes[0].node)], **pos(node)) if isinstance(node.nodes[0], php.ObjectProperty): return py.Call( py.Name('hasattr', py.Load(**pos(node)), **pos(node)), [ from_phpast(node.nodes[0].node), from_phpast(node.nodes[0].name) ], [], None, None, **pos(node)) if isinstance(node.nodes[0], php.Variable): return py.Compare(py.Str( node.nodes[0].name[1:], **pos(node)), [py.In(**pos(node))], [ py.Call(py.Name('vars', py.Load(**pos(node)), **pos(node)), [], [], None, None, **pos(node)) ], **pos(node)) return py.Compare(from_phpast(node.nodes[0]), [py.IsNot(**pos(node))], [py.Name('None', py.Load(**pos(node)), **pos(node))], **pos(node)) if isinstance(node, php.Empty): return from_phpast( php.UnaryOp('!', php.BinaryOp('&&', php.IsSet([node.expr], lineno=node.lineno), node.expr, lineno=node.lineno), lineno=node.lineno)) if isinstance(node, php.Assignment): if (isinstance(node.node, php.ArrayOffset) and node.node.expr is None): return py.Call( py.Attribute(from_phpast(node.node.node), 'append', py.Load(**pos(node)), **pos(node)), [from_phpast(node.expr)], [], None, None, **pos(node)) if (isinstance(node.node, php.ObjectProperty) and isinstance(node.node.name, php.BinaryOp)): return to_stmt( py.Call(py.Name('setattr', py.Load(**pos(node)), **pos(node)), [ from_phpast(node.node.node), from_phpast(node.node.name), from_phpast(node.expr) ], [], None, None, **pos(node))) return py.Assign([store(from_phpast(node.node))], from_phpast(node.expr), **pos(node)) if isinstance(node, php.ListAssignment): return py.Assign([ py.Tuple(list(map(store, list(map(from_phpast, node.nodes)))), py.Store(**pos(node)), **pos(node)) ], from_phpast(node.expr), **pos(node)) if isinstance(node, php.AssignOp): return from_phpast( php.Assignment(node.left, php.BinaryOp(node.op[:-1], node.left, node.right, lineno=node.lineno), False, lineno=node.lineno)) if isinstance(node, (php.PreIncDecOp, php.PostIncDecOp)): return from_phpast( php.Assignment(node.expr, php.BinaryOp(node.op[0], node.expr, 1, lineno=node.lineno), False, lineno=node.lineno)) if isinstance(node, php.ArrayOffset): return py.Subscript(from_phpast(node.node), py.Index(from_phpast(node.expr), **pos(node)), py.Load(**pos(node)), **pos(node)) if isinstance(node, php.ObjectProperty): if isinstance(node.name, (php.Variable, php.BinaryOp)): return py.Call( py.Name('getattr', py.Load(**pos(node)), **pos(node)), [from_phpast(node.node), from_phpast(node.name)], [], None, None, **pos(node)) return py.Attribute(from_phpast(node.node), node.name, py.Load(**pos(node)), **pos(node)) if isinstance(node, php.Constant): name = node.name if name.lower() == 'true': name = 'True' if name.lower() == 'false': name = 'False' if name.lower() == 'null': name = 'None' return py.Name(name, py.Load(**pos(node)), **pos(node)) if isinstance(node, php.Variable): name = node.name[1:] if name == 'this': name = 'self' return py.Name(name, py.Load(**pos(node)), **pos(node)) if isinstance(node, php.Global): return py.Global([var.name[1:] for var in node.nodes], **pos(node)) if isinstance(node, php.Include): once = py.Name('True' if node.once else 'False', py.Load(**pos(node)), **pos(node)) return py.Call(py.Name('include', py.Load(**pos(node)), **pos(node)), [from_phpast(node.expr), once], [], None, None, **pos(node)) if isinstance(node, php.Require): once = py.Name('True' if node.once else 'False', py.Load(**pos(node)), **pos(node)) return py.Call(py.Name('require', py.Load(**pos(node)), **pos(node)), [from_phpast(node.expr), once], [], None, None, **pos(node)) if isinstance(node, php.UnaryOp): op = unary_ops.get(node.op) assert op is not None, "unknown unary operator: '%s'" % node.op op = op(**pos(node)) return py.UnaryOp(op, from_phpast(node.expr), **pos(node)) if isinstance(node, php.BinaryOp): if node.op == '.': pattern, pieces = build_format(node.left, node.right) if pieces: return py.BinOp( py.Str(pattern, **pos(node)), py.Mod(**pos(node)), py.Tuple(list(map(from_phpast, pieces)), py.Load(**pos(node)), **pos(node)), **pos(node)) else: return py.Str(pattern % (), **pos(node)) if node.op in bool_ops: op = bool_ops[node.op](**pos(node)) return py.BoolOp(op, [from_phpast(node.left), from_phpast(node.right)], **pos(node)) if node.op in cmp_ops: op = cmp_ops[node.op](**pos(node)) return py.Compare(from_phpast(node.left), [op], [from_phpast(node.right)], **pos(node)) op = binary_ops.get(node.op) if node.op == 'instanceof': return py.Call( func=py.Name(id='isinstance', ctx=py.Load(**pos(node))), args=[from_phpast(node.left), from_phpast(node.right)], keywords=[], starargs=None, kwargs=None) assert op is not None, "unknown binary operator: '%s'" % node.op op = op(**pos(node)) return py.BinOp(from_phpast(node.left), op, from_phpast(node.right), **pos(node)) if isinstance(node, php.TernaryOp): return py.IfExp(from_phpast(node.expr), from_phpast(node.iftrue), from_phpast(node.iffalse), **pos(node)) if isinstance(node, php.Cast): return py.Call( py.Name(casts.get(node.type, node.type), py.Load(**pos(node)), **pos(node)), [from_phpast(node.expr)], [], None, None, **pos(node)) if isinstance(node, php.If): orelse = [] if node.else_: for else_ in map(from_phpast, deblock(node.else_.node)): orelse.append(to_stmt(else_)) for elseif in reversed(node.elseifs): orelse = [ py.If( from_phpast(elseif.expr), list( map(to_stmt, list(map(from_phpast, deblock(elseif.node))))), orelse, **pos(node)) ] return py.If( from_phpast(node.expr), list(map(to_stmt, list(map(from_phpast, deblock(node.node))))), orelse, **pos(node)) if isinstance(node, php.For): assert node.test is None or len(node.test) == 1, \ 'only a single test is supported in for-loops' return from_phpast( php.Block((node.start or []) + [ php.While(node.test[0] if node.test else 1, php.Block(deblock(node.node) + (node.count or []), lineno=node.lineno), lineno=node.lineno) ], lineno=node.lineno)) if isinstance(node, php.Foreach): if node.keyvar is None: target = py.Name(node.valvar.name[1:], py.Store(**pos(node)), **pos(node)) else: target = py.Tuple([ py.Name(node.keyvar.name[1:], py.Store(**pos(node))), py.Name(node.valvar.name[1:], py.Store(**pos(node))) ], py.Store(**pos(node)), **pos(node)) return py.For( target, from_phpast(node.expr), list(map(to_stmt, list(map(from_phpast, deblock(node.node))))), [], **pos(node)) if isinstance(node, php.While): return py.While( from_phpast(node.expr), list(map(to_stmt, list(map(from_phpast, deblock(node.node))))), [], **pos(node)) if isinstance(node, php.DoWhile): condition = php.If(php.UnaryOp('!', node.expr, lineno=node.lineno), php.Break(None, lineno=node.lineno), [], None, lineno=node.lineno) return from_phpast( php.While(1, php.Block(deblock(node.node) + [condition], lineno=node.lineno), lineno=node.lineno)) if isinstance(node, php.Try): return py.TryExcept( list(map(to_stmt, list(map(from_phpast, node.nodes)))), [ py.ExceptHandler( py.Name(catch.class_, py.Load(**pos(node)), **pos(node)), store(from_phpast(catch.var)), list(map(to_stmt, list(map(from_phpast, catch.nodes)))), **pos(node)) for catch in node.catches ], [], **pos(node)) if isinstance(node, php.Throw): return py.Raise(from_phpast(node.node), None, None, **pos(node)) if isinstance(node, php.Function): args = [] defaults = [] for param in node.params: args.append( py.Name(param.name[1:], py.Param(**pos(node)), **pos(node))) if param.default is not None: defaults.append(from_phpast(param.default)) body = list(map(to_stmt, list(map(from_phpast, node.nodes)))) if not body: body = [py.Pass(**pos(node))] return py.FunctionDef(node.name, py.arguments(args, None, None, defaults), body, [], **pos(node)) if isinstance(node, php.Method): args = [] defaults = [] decorator_list = [] if 'static' in node.modifiers: decorator_list.append( py.Name('classmethod', py.Load(**pos(node)), **pos(node))) args.append(py.Name('cls', py.Param(**pos(node)), **pos(node))) else: args.append(py.Name('self', py.Param(**pos(node)), **pos(node))) for param in node.params: args.append( py.Name(param.name[1:], py.Param(**pos(node)), **pos(node))) if param.default is not None: defaults.append(from_phpast(param.default)) body = list(map(to_stmt, list(map(from_phpast, node.nodes)))) if not body: body = [py.Pass(**pos(node))] return py.FunctionDef(node.name, py.arguments(args, None, None, defaults), body, decorator_list, **pos(node)) if isinstance(node, php.Class): name = node.name bases = [] extends = node.extends or 'object' bases.append(py.Name(extends, py.Load(**pos(node)), **pos(node))) body = list(map(to_stmt, list(map(from_phpast, node.nodes)))) for stmt in body: if (isinstance(stmt, py.FunctionDef) and stmt.name in (name, '__construct')): stmt.name = '__init__' if not body: body = [py.Pass(**pos(node))] return py.ClassDef(name, bases, body, [], **pos(node)) if isinstance(node, (php.ClassConstants, php.ClassVariables)): assert len(node.nodes) == 1, \ 'only one class-level assignment supported per line' if isinstance(node.nodes[0], php.ClassConstant): name = php.Constant(node.nodes[0].name, lineno=node.lineno) else: name = php.Variable(node.nodes[0].name, lineno=node.lineno) initial = node.nodes[0].initial if initial is None: initial = php.Constant('None', lineno=node.lineno) return py.Assign([store(from_phpast(name))], from_phpast(initial), **pos(node)) if isinstance(node, (php.FunctionCall, php.New)): if isinstance(node.name, str): name = py.Name(node.name, py.Load(**pos(node)), **pos(node)) else: name = py.Subscript( py.Call(py.Name('vars', py.Load(**pos(node)), **pos(node)), [], [], None, None, **pos(node)), py.Index(from_phpast(node.name), **pos(node)), py.Load(**pos(node)), **pos(node)) args, kwargs = build_args(node.params) return py.Call(name, args, kwargs, None, None, **pos(node)) if isinstance(node, php.MethodCall): args, kwargs = build_args(node.params) return py.Call( py.Attribute(from_phpast(node.node), node.name, py.Load(**pos(node)), **pos(node)), args, kwargs, None, None, **pos(node)) if isinstance(node, php.StaticMethodCall): class_ = node.class_ if class_ == 'self': class_ = 'cls' args, kwargs = build_args(node.params) return py.Call( py.Attribute(py.Name(class_, py.Load(**pos(node)), **pos(node)), node.name, py.Load(**pos(node)), **pos(node)), args, kwargs, None, None, **pos(node)) if isinstance(node, php.StaticProperty): class_ = node.node name = node.name if isinstance(name, php.Variable): name = name.name[1:] return py.Attribute(py.Name(class_, py.Load(**pos(node)), **pos(node)), name, py.Load(**pos(node)), **pos(node)) return py.Call(py.Name('XXX', py.Load(**pos(node)), **pos(node)), [py.Str(str(node), **pos(node))], [], None, None, **pos(node))
COMMENT = Comment() class Char(object): def __init__(self, str, lineno=0): self.value = str self.lineno = lineno op_ast_map = { '+': ast.Add(), '-': ast.Sub(), '*': ast.Mult(), '/': ast.Div(), '%': ast.Mod(), '**': ast.Pow(), '<<': ast.LShift(), '>>': ast.RShift(), '|': ast.BitOr(), '^^': ast.BitXor(), '&&': ast.BitAnd(), '//': ast.FloorDiv(), '==': ast.Eq(), '!=': ast.NotEq(), '<': ast.Lt(), '<=': ast.LtE(), '>': ast.Gt(), '>=': ast.GtE(), 'is': ast.Is(), 'is_not': ast.IsNot(),
def __mod__(self, other: Union[T, Expr[T]]) -> BinOp[T]: return BinOp(self, ast.Mod(), other)
class LtnsCompiler: def _temp_func_name(self): if not hasattr(self, '_temp'): self._temp = 0 self._temp += 1 return f'_temp_func_{self._temp}' def _temp_var_name(self): if not hasattr(self, '_temp'): self._temp = 0 self._temp += 1 return f'_temp_var_{self._temp}' def _compile_branch(self, branch): result = Result() for x in branch[:-1]: res = self.compile(x) result.stmts += res.stmts result.stmts += [res.expr_statement] res = self.compile(branch[-1]) result.stmts += res.stmts result.expr = res.expr return result def _compile_args(self, args, kwargs): for i, arg in enumerate(args): if arg == '&': vararg = ast.arg(str(args[i + 1], None), None) posarg = args[:i] else: vararg = None posarg = args return ast.arguments( args=[ast.arg(str(x), None) for x in posarg], vararg=vararg, kwonlyargs=[ast.arg(str(x), None) for x in kwargs], kwarg=None, defaults=[], kw_defaults=list(kwargs.values()), ) def compile(self, node): return _model_compiler[type(node)](self, node) @model(LtnsElement) def compile_element(self, element): if element.name in _special_form_compiler: return _special_form_compiler[element.name](self, *element.childs, **element.attributes) func = ast.parse(element.name, mode='eval').body # TODO: handle exception of parsing result = Result() args = [] keywords = [] for child in element.childs: res = self.compile(child) args.append(res.expr) result.stmts += res.stmts for key, value in element.attributes.items(): res = self.compile(value) keywords.append(ast.keyword(arg=str(key), value=res.expr)) result.stmts += res.stmts expr = ast.Call(func=func, args=args, keywords=keywords) result.expr = expr return result @model(LtnsSymbol) def compile_symbol(self, symbol): expr = ast.Name(id=str(symbol), ctx=ast.Load()) return Result(expr=expr) @model(LtnsString) def compile_string(self, string): return Result(expr=ast.Str(str(string))) @model(LtnsKeyword) def compile_keyword(self, keyword): return Result(expr=ast.Call( func=ast.Name(id='LtnsKeyword', ctx=ast.Load()), args=[ast.Str(str(keyword))], )) @model(LtnsInteger) def compile_integer(self, integer): return Result(expr=ast.Num(int(integer))) @model(LtnsFloat) def compile_float_number(self, float_number): return Result(expr=ast.Num(float(float_number))) @model(LtnsComplex) def compile_complex_number(self, complex_number): return Result(expr=ast.Num(complex(complex_number))) @model(LtnsList) def compile_list(self, ltns_list): result = Result() elts = [] for e in ltns_list: res = self.compile(e) elts.append(res.expr) result.stmts += res.stmts expr = ast.List(elts=elts, ctx=ast.Load()) result.expr = expr return result @special('do') def compile_do(self, *body): return self._compile_branch(body) name_op = { 'add*': ast.Add(), 'sub*': ast.Sub(), 'mul*': ast.Mult(), 'div*': ast.Div(), 'mod': ast.Mod(), 'pow': ast.Pow(), 'lshift': ast.LShift(), 'rshift': ast.RShift(), 'bitor': ast.BitOr(), 'bitxor': ast.BitXor(), 'bitand': ast.BitAnd(), } def compile_bin_op(self, a, b, name): result = Result() left = self.compile(a) result.stmts += left.stmts left = left.expr right = self.compile(b) result.stmts += right.stmts right = right.expr expr = ast.BinOp(op=self.name_op[name], left=left, right=right) result.expr = expr return result for name in name_op: _special_form_compiler[name] = partial(compile_bin_op, name=name) @special('if') def compile_if(self, test, then, orelse=None): result = Result() pred = self.compile(test) result.stmts += pred.stmts then_body = self.compile(then) else_body = None if orelse is not None: else_body = self.compile(orelse) if then_body.stmts or else_body.stmts: temp_func_name = self._temp_func_name() temp_var_name = self._temp_var_name() body = then_body.stmts body.append( ast.Assign( targets=[ast.Name(id=temp_var_name, ctx=ast.Store())], value=then_body.expr, )) orelse = else_body.stmts orelse.append( ast.Assign( targets=[ast.Name(id=temp_var_name, ctx=ast.Store())], value=else_body.expr, )) result.stmts.append( ast.FunctionDef( name=temp_func_name, args=ast.arguments( args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[], ), body=[ ast.If(test=pred.expr, body=body, orelse=orelse), ast.Return( value=ast.Name(id=temp_var_name, ctx=ast.Load())), ], decorator_list=[], returns=None, )) result.expr = ast.Call( func=ast.Name(id=temp_func_name, ctx=ast.Load()), args=[], keywords=[], ) return result else: result.expr = ast.IfExp( test=pred.expr, body=then_body.expr, orelse=else_body.expr, ) return result @special('fn*') def compile_fn(self, args, *body, **kwargs): result = Result() body = self._compile_branch(body) args = self._compile_args(args, kwargs) if body.stmts: fdef = ast.FunctionDef() fdef.name = self._temp_func_name() fdef.args = args fdef.body = body.stmts + [ast.Return(body.expr)] fdef.decorator_list = [] fdef.returns = None result.stmts += [fdef] result.expr = ast.Name(id=fdef.name, ctx=ast.Load()) else: result.expr = ast.Lambda(args=args, body=body.expr) return result @special('def') def compile_def(self, *name_value, **def_dict): if len(name_value) % 2 != 0: raise ValueError("length of argument list should be even") result = Result() for name, value in def_dict.items(): name = LtnsSymbol(name) name_value = name_value + (name, value) for i, name in enumerate(name_value[::2]): name = ast.Name(id=str(name), ctx=ast.Store()) value = self.compile(name_value[i * 2 + 1]) result.stmts += [ast.Assign( targets=[name], value=value.expr, )] result.expr = ast.Name(id='None', ctx=ast.Load()) return result
def compile_subtract(p): if len(p) == 2: return ast.UnaryOp(ast.USub(), build_ast(p[1])) elif len(p) == 3: return ast.BinOp(build_ast(p[1]), ast.Sub(), build_ast(p[2])) else: return ast.BinOp(compile_subtract(p[:-1]), ast.Sub(), build_ast(p[-1])) CompileFuncs = { Symbol.new("+"): compile_add, Symbol.new("-"): compile_subtract, Symbol.new("*"): compile_multiply, Symbol.new("/"): compile_divide, Symbol.new("//"): compile_floordivide, Symbol.new("%"): lambda p: ast.BinOp(build_ast(p[1]), ast.Mod(), build_ast(p[2])), Symbol.new("&"): lambda p: ast.BinOp(build_ast(p[1]), ast.BitAnd(), build_ast(p[2])), Symbol.new("**"): lambda p: ast.BinOp(build_ast(p[1]), ast.Pow(), build_ast(p[2])), Symbol.new(">>"): lambda p: ast.BinOp(build_ast(p[1]), ast.RShift(), build_ast(p[2])), Symbol.new("<<"): lambda p: ast.BinOp(build_ast(p[1]), ast.LShift(), build_ast(p[2])), Symbol.new("^"): lambda p: ast.BinOp(build_ast(p[1]), ast.BitXor(), build_ast(p[2])), Symbol.new("<"): lambda p: ast.Compare(build_ast(p[1]), [ast.Lt() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new(">"): lambda p: ast.Compare(build_ast(p[1]), [ast.Gt() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new("<="): lambda p: ast.Compare(build_ast(p[1]), [ast.LtE() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new(">="): lambda p: ast.Compare(build_ast(p[1]), [ast.GtE() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new("=="): compile_equals, Symbol.new("!="): lambda p: ast.Compare(build_ast(p[1]), [ast.NotEq() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new("is"): lambda p: ast.Compare(build_ast(p[1]), [ast.Is() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new("is-not"): lambda p: ast.Compare(build_ast(p[1]), [ast.IsNot() for x in p[1::2]], [build_ast(x) for x in p[2::2]]), Symbol.new("define"): compile_define, Symbol.new("dict-set"): lambda p: ast.Assign([ast.Subscript(build_ast(p[1]), ast.Index(build_ast(p[2])), ast.Store())], build_ast(p[3])),
def __build_function(self, dom_name, full_name, func_params): assert 'name' in func_params func_name = func_params['name'] docstr = self.__build_desc_string(dom_name, func_name, func_params) args = [ast.arg('self', None)] message_params = [] func_body = [] if docstr: func_body.append(ast.Expr(ast.Str("\n"+docstr+"\n\t\t"))) for param in func_params.get("parameters", []): argname = param['name'] param_optional = param.get("optional", False) if param_optional is False: message_params.append(ast.keyword(argname, ast.Name(id=argname, ctx=ast.Load()))) args.append(ast.arg(argname, None)) if self.do_debug_prints: func_body.append(self.__build_debug_print(argname, argname)) param_type = param.get("type", None) if param_type in CHECKS: if param_optional: check = self.__build_conditional_arg_check(argname, CHECKS[param_type]) else: check = self.__build_unconditional_arg_check(argname, CHECKS[param_type]) if check: func_body.append(check) optional_params = [param.get("name") for param in func_params.get("parameters", []) if param.get("optional", False)] func_kwargs = None if len(optional_params): value = ast.List(elts=[ast.Str(s=param, ctx=ast.Store()) for param in optional_params], ctx=ast.Load()) create_list = ast.Assign(targets=[ast.Name(id='expected', ctx=ast.Store())], value=value) func_body.append(create_list) passed_arg_list = ast.Assign(targets=[ast.Name(id='passed_keys', ctx=ast.Store())], value=ast.Call(func=ast.Name(id='list', ctx=ast.Load()), args=[ast.Call(func=ast.Attribute(value=ast.Name(id='kwargs', ctx=ast.Load()), attr='keys', ctx=ast.Load()), args=[], keywords=[])], keywords=[])) func_body.append(passed_arg_list) comprehension = ast.comprehension(target=ast.Name(id='key', ctx=ast.Store()), iter=ast.Name(id='passed_keys', ctx=ast.Load()), ifs=[], is_async=False) comparator = ast.Name(id='expected', ctx=ast.Load()) listcomp = ast.ListComp(elt=ast.Compare(left=ast.Name(id='key', ctx=ast.Load()), ops=[ast.In()], comparators=[comparator]), generators=[comprehension]) check_message = ast.BinOp( left = ast.Str(s="Allowed kwargs are {}. Passed kwargs: %s".format(optional_params)), op = ast.Mod(), right = ast.Name(id='passed_keys', ctx=ast.Load()), lineno = self.__get_line()) kwarg_check = ast.Assert(test=ast.Call(func=ast.Name(id='all', ctx=ast.Load()), args=[listcomp], keywords=[]), msg=check_message) func_body.append(kwarg_check) func_kwargs = ast.Name(id='kwargs', ctx=ast.Load()) fname = "{}.{}".format(dom_name, func_name) fname = ast.Str(s=fname, ctx=ast.Load()) if (sys.version_info[0], sys.version_info[1]) == (3, 5) or \ (sys.version_info[0], sys.version_info[1]) == (3, 6): # More irritating minor semantic differences in the AST between 3.4 and 3.5 if func_kwargs: message_params.append(ast.keyword(arg=None, value=ast.Name(id='kwargs', ctx=ast.Load()))) communicate_call = ast.Call( func=ast.Attribute(value=ast.Name(id='self', ctx=ast.Load()), ctx=ast.Load(), attr='synchronous_command'), args=[fname], keywords=message_params) elif (sys.version_info[0], sys.version_info[1]) == (3,4): communicate_call = ast.Call( func=ast.Attribute(value=ast.Name(id='self', ctx=ast.Load()), ctx=ast.Load(), attr='synchronous_command'), args=[fname], kwargs=func_kwargs, keywords=message_params) else: print("Version:", sys.version_info) raise RuntimeError("This script only functions on python 3.4, 3.5 or 3.6. Active python version {}.{}".format(*sys.version_info)) do_communicate = ast.Assign(targets=[ast.Name(id='subdom_funcs', ctx=ast.Store())], value=communicate_call) func_ret = ast.Return(value=ast.Name(id='subdom_funcs', ctx=ast.Load())) if len(optional_params) and self.do_debug_prints: func_body.append(self.__build_debug_print('kwargs', 'kwargs')) func_body.append(do_communicate) func_body.append(func_ret) if len(optional_params): kwarg = ast.arg(arg='kwargs', annotation=None) else: kwarg = None sig = ast.arguments( args=args, vararg=None, varargannotation=None, kwonlyargs=[], kwarg=kwarg, kwargannotation=None, defaults=[], kw_defaults=[]) func = ast.FunctionDef( name = "{}_{}".format(full_name, func_name), args = sig, body = func_body, decorator_list = [], lineno = self.__get_line(), col_offset = 0, ) return func