def visit_For(self, n): orelse = n.orelse if orelse: raise InvalidOperationError( "else clauses on for loops are not supported.", n) # This is a fairly limited form of the for-loop, not even the # complete xrange syntax (negative steps will blow your code up) # so we probably want to expand on this somehow. I'm open to # ideas. Or just wait till I implement full-blown range support. # # In the meantime, you can use while loops instead. # insert missing iteration bounds if not specified iter = n.iter if isinstance(iter, _ast.Tuple): elts = iter.elts n_elts = len(elts) if n_elts == 1: start = _ast.Num(n=0) stop = elts[0] step = _ast.Num(n=1) elif n_elts == 2: start = elts[0] stop = elts[1] step = _ast.Num(n=1) elif n_elts == 3: start = elts[0] stop = elts[1] step = elts[2] else: raise InvalidOperationError( "Invalid number of elements specified in for-loop index.", n) else: start = _ast.Num(n=0) stop = iter step = _ast.Num(n=1) target_store = n.target init = self.visit(_ast.Assign(targets=[target_store], value=start)) # to create the guard operation, we need a Load version of the target target_load = astx.copy_node(target_store, ctx=self._Load) guard = self.visit( _ast.Compare(left=target_load, comparators=[stop], ops=[_ast.Lt()])) update_stmt = self.visit( _ast.AugAssign(target=target_store, op=_ast.Add(), value=step)) return astx.copy_node(n, init=init, guard=guard, update_stmt=update_stmt, body=[self.visit(stmt) for stmt in n.body], orelse=[])
def generate_Exec(self, context, node): body = node.body context.stmts.append((body.s, "\n")) context.body.append(astx.copy_node(node, body=astx.copy_node(body), globals=[], locals=[] ))
def generate_If(self, context, node): test = context.visit(node.test) context.stmts.append(("if (", test.code, ") {\n", context.tab)) parent_body = context.body body = context.body = [] for stmt in node.body: context.visit(stmt) context.body = parent_body orelse = node.orelse num_else = len(orelse) if num_else == 0: context.stmts.append((context.untab, "}\n")) new_orelse = [] elif num_else == 1: context.stmts.append((context.untab, "} else ", context.tab)) new_orelse = [context.visit(orelse[0])] context.stmts.append(context.untab) else: context.stmts.append((context.untab, "} else {\n", context.tab)) new_orelse = context.body = [] for stmt in orelse: context.visit(stmt) context.body = parent_body context.stmts.append((context.untab, "}\n")) context.body.append( astx.copy_node(node, test=test, body=body, orelse=new_orelse))
def visit_Index(self, node): value = self.visit(node.value) new_node = astx.copy_node(node, value=value) new_node.unresolved_type=value.unresolved_type return new_node
def visit_FunctionDef(self, node): # create context context = self.context = Context(self, self.concrete_fn, self.backend) # resolve return type context.return_type = node.return_type.resolve(context) # visit arguments args = self.visit(node.args) # visit body for stmt in node.body: self.visit(stmt) # generate program item program_item = context.backend.generate_program_item(context) context.program_item = program_item context.program_items.append(program_item) # return final AST return astx.copy_node(node, name=program_item.name, args=args, body=context.body, context=context )
def visit_BoolOp(self, n): op = self.visit(n.op) values = [self.visit(expr) for expr in n.values] return astx.copy_node(n, op=op, values=values, unresolved_type=BoolOpType(op, values))
def visit_Index(self, node): value = self.visit(node.value) return astx.copy_node(node, value=value, code=value.code, clq_type=value.clq_type )
def generate_AugAssign(self, context, node): target = context.visit(node.target) value = context.visit(node.value) op = context.visit(node.op) # TODO: I don't know whats going on here... # add declaration id = target.id local_variables = context.generic_fn.local_variables if id in local_variables: context.backend._add_declaration(context, id, local_variables[id].resolve(context)) # add code context.stmts.append((self.generate_AugAssign_stmt( target.code, op.code, value.code), context.end_stmt)) # add node context.body.append(astx.copy_node(node, target=target, value=value, op=op ))
def visit_AugAssign(self, node): target = node.target op = node.op value = node.value # We temporarily turn augmented assignments into the equivalent binary # operation to determine the unresolved type. orig_ctx = target.ctx target.ctx = _ast.Load() tmp_binop = self.visit(_ast.BinOp(left=target, op=op, right=value)) target.ctx = orig_ctx # visit the target # see visit_Assign self.cur_assignment_type = tmp_binop.unresolved_type target = self.visit(target) self.cur_assignment_type = None return astx.copy_node(node, target=tmp_binop.left, op=tmp_binop.op, value=tmp_binop.right )
def generate_AssignAttribute(self, context, node): target = context.visit(node.targets[0]) value = context.visit(node.value) context.stmts.append((self.generate_Assign_stmt( target.code, value.code), context.end_stmt)) context.body.append( astx.copy_node(node, targets=[target], value=value))
def generate_UnaryOp(self, context, node): op = context.visit(node.op) operand = context.visit(node.operand) code = ("(", op.code, operand.code, ")") return astx.copy_node(node, op=op, operand=operand, code=code)
def generate_Subscript(self, context, node): value = context.visit(node.value) slice = context.visit(node.slice) code = (value.code, "[", slice.code, "]") return astx.copy_node(node, value=value, slice=slice, code=code)
def visit_Call(self, n): if n.keywords: raise InvalidOperationError( "Keyword arguments in concrete_fn calls are not supported.", n) if n.starargs: raise InvalidOperationError( "Starred arguments in concrete_fn calls are not supported.", n) if n.kwargs: raise InvalidOperationError( "kwargs in concrete_fn calls are not supported.", n) func = self.visit(n.func) if isinstance(func, _ast.Num): # for number literals # (special cased because number values should not function this way, # just literals.) args = n.args cl_type = literal_suffixes[args[0].id] #@UndefinedVariable unresolved_type = InlineConstantType(func.n, cl_type) else: args = [self.visit(arg) for arg in n.args] unresolved_type = CallType(func, args) return astx.copy_node(n, func=func, args=args, keywords=[], starargs=None, kwargs=None, unresolved_type=unresolved_type)
def visit_Call(self, n): if n.keywords: raise InvalidOperationError( "Keyword arguments in concrete_fn calls are not supported.", n) if n.starargs: raise InvalidOperationError( "Starred arguments in concrete_fn calls are not supported.", n) if n.kwargs: raise InvalidOperationError( "kwargs in concrete_fn calls are not supported.", n) func = self.visit(n.func) if isinstance(func, _ast.Num): # for number literals # (special cased because number values should not function this way, # just literals.) args = n.args cl_type = literal_suffixes[args[0].id] #@UndefinedVariable unresolved_type = InlineConstantType(func.n, cl_type) else: args = [ self.visit(arg) for arg in n.args ] unresolved_type = CallType(func, args) return astx.copy_node(n, func=func, args=args, keywords=[], starargs=None, kwargs=None, unresolved_type=unresolved_type )
def visit_FunctionDef(self, node): # can't nest functions if self._in_function: raise InvalidOperationError( "Nested function definitions are not supported.", node) self._in_function = True # do all the work self.return_type = None args = self.visit(node.args) body = [ self.visit(stmt) for stmt in node.body ] if self.return_type is None: self.return_type = VoidURT(node) # return a copy of the root node with all the information as # attributes return astx.copy_node(node, name=node.name, args=args, body=body, decorator_list=[], return_type=self.return_type, all_variables=cypy.frozendict(self.all_variables), arguments=cypy.frozendict(self.arguments), local_variables=cypy.frozendict(self.local_variables), free_variables=cypy.frozendict(self.free_variables) )
def visit_UnaryOp(self, n): operand = self.visit(n.operand) op = self.visit(n.op) return astx.copy_node(n, op=op, operand=operand, unresolved_type=UnaryOpType(op, operand))
def visit_Exec(self, n): if n.globals: raise InvalidOperationError("Cannot specify globals with `exec`.", n.globals[0]) if n.locals: raise InvalidOperationError("Cannot specify locals with `exec`.", n.locals[0]) return astx.copy_node(n, globals=[], locals=[])
def generate_BinOp(self, context, node): left = context.visit(node.left) op = context.visit(node.op) right = context.visit(node.right) code = ("(", left.code, " ", op.code, " ", right.code, ")") return astx.copy_node(node, left=left, op=op, right=right, code=code)
def generate_AugAssignAttribute(self, context, node): target = context.visit(node.target) value = context.visit(node.value) op = context.visit(node.op) context.stmts.append((self.generate_AugAssign_stmt( target.code, op.code, value.code), context.end_stmt)) context.body.append( astx.copy_node(node, target=target, value=value, op=op))
def visit_ExtSlice(self, node): dims = node.dims if dims: dims = [self.visit(dim) for dim in dims] return astx.copy_node(node, dims=dims )
def visit_Assign(self, n): value = self.visit(n.value) # cur_assignment_type communicates with visit_Name self.cur_assignment_type = value.unresolved_type targets = [self.visit(target) for target in n.targets] self.cur_assignment_type = None return astx.copy_node(n, targets=targets, value=value)
def generate_BoolOp(self, context, node): left = context.visit(node.values[0]) right = context.visit(node.values[1]) op = context.visit(node.op) code = ("(", left.code, " ", op.code, " ", right.code, ")") return astx.copy_node(node, op=op, values=[left, right], code=code)
def visit_BoolOp(self, n): op = self.visit(n.op) values = [self.visit(expr) for expr in n.values] return astx.copy_node(n, op=op, values=values, unresolved_type=BoolOpType(op, values) )
def visit_UnaryOp(self, node): operand = self.visit(node.operand) op = self.visit(node.op) new_node = astx.copy_node(node, op=op, operand=operand) new_node.unresolved_type = UnaryOpURT(new_node) return new_node
def generate_BinOp(self, context, node): left = context.visit(node.left) op = context.visit(node.op) right = context.visit(node.right) #TODO: generate include? code = ("strcat(", left.code, ",", right.code, ")") return astx.copy_node(node, left=left, op=op, right=right, code=code)
def generate_BinOp(self, context, node): # TODO: abstract this away for all the bin op supporters left = context.visit(node.left) op = context.visit(node.op) right = context.visit(node.right) code = ("(", left.code, " ", op.code, " ", right.code, ")") return astx.copy_node(node, left=left, op=op, right=right, code=code)
def visit_UnaryOp(self, n): operand = self.visit(n.operand) op = self.visit(n.op) return astx.copy_node(n, op=op, operand=operand, unresolved_type=UnaryOpType(op, operand) )
def generate_Compare(self, context, node): left = context.visit(node.left) right = context.visit(node.comparators[0]) op = context.visit(node.ops[0]) code = (left.code, " ", op.code, " ", right.code) return astx.copy_node( node, left=left, ops=[op], comparators=[right], code=code)
def visit_BoolOp(self, node): op = self.visit(node.op) values = [self.visit(expr) for expr in node.values] new_node = astx.copy_node(node, op=op, values=values) new_node.unresolved_type = BoolOpURT(new_node) return new_node
def visit_BinOp(self, n): left = self.visit(n.left) op = self.visit(n.op) right = self.visit(n.right) return astx.copy_node(n, left=left, op=op, right=right, unresolved_type=BinOpType(op, left, right))
def generate_IfExp(self, context, node): test = context.visit(node.test) body = context.visit(node.body) orelse = context.visit(node.orelse) code = ("((", test.code, ") ? (", body.code, ") : (", orelse.code, ")") return astx.copy_node( node, test=test, body=body, orelse=orelse, code=code)
def visit_Attribute(self, n): value = self.visit(n.value) ctx = self.visit(n.ctx) return astx.copy_node(n, value=value, attr=n.attr, ctx=ctx, unresolved_type=AttributeType(value, n.attr))
def visit_While(self, node): if node.orelse: raise InvalidOperationError( "else clauses on while loops are not supported.", node) return astx.copy_node(node, test=self.visit(node.test), body=[self.visit(stmt) for stmt in node.body], orelse=[] )
def visit_Attribute(self, node): value = self.visit(node.value) ctx = self.visit(node.ctx) new_node = astx.copy_node(node, value=value, attr=node.attr, ctx=ctx) new_node.unresolved_type=AttributeURT(new_node) return new_node
def visit_BinOp(self, n): left = self.visit(n.left) op = self.visit(n.op) right = self.visit(n.right) return astx.copy_node(n, left=left, op=op, right=right, unresolved_type=BinOpType(op, left, right) )
def visit_Subscript(self, n): value = self.visit(n.value) slice = self.visit(n.slice) ctx = self.visit(n.ctx) return astx.copy_node(n, value=value, slice=slice, ctx=ctx, unresolved_type=SubscriptType(value, slice))
def visit_While(self, n): orelse = n.orelse if orelse: raise InvalidOperationError( "else clauses on while loops are not supported.", n) return astx.copy_node(n, test=self.visit(n.test), body=[self.visit(stmt) for stmt in n.body], orelse=[])
def visit_Attribute(self, n): value = self.visit(n.value) ctx = self.visit(n.ctx) return astx.copy_node(n, value=value, attr=n.attr, ctx=ctx, unresolved_type=AttributeType(value, n.attr) )
def visit_Compare(self, n): left = self.visit(n.left) ops = [self.visit(op) for op in n.ops] comparators = [self.visit(expr) for expr in n.comparators] return astx.copy_node(n, left=left, ops=ops, comparators=comparators, unresolved_type=CompareType( left, ops, comparators))
def visit_Subscript(self, n): value = self.visit(n.value) slice = self.visit(n.slice) ctx = self.visit(n.ctx) return astx.copy_node(n, value=value, slice=slice, ctx=ctx, unresolved_type=SubscriptType(value, slice) )
def visit_IfExp(self, n): test = self.visit(n.test) body = self.visit(n.body) orelse = self.visit(n.orelse) return astx.copy_node(n, test=test, body=body, orelse=orelse, unresolved_type=MultipleAssignmentType( body.unresolved_type, orelse.unresolved_type))
def visit_Slice(self, n): # here in case a virtual type wants to support it lower = n.lower if lower is not None: lower = self.visit(lower) upper = n.upper if upper is not None: upper = self.visit(upper) step = n.step if step is not None: step = self.visit(step) return astx.copy_node(n, lower=lower, upper=upper, step=step)
def visit_Return(self, n): n_value = n.value if n_value is None: value = None return_type = cl.cl_void else: value = self.visit(n_value) return_type = value.unresolved_type cur_return_type = self.return_type if cur_return_type is None: self.return_type = return_type else: self.return_type = MultipleAssignmentType(cur_return_type, return_type) return astx.copy_node(n, value=value)
def visit_Name(self, n): id = n.id ctx = self.visit(n.ctx) ctx_t = type(ctx) unresolved_type = NameType(id) if ctx_t is _ast.Load: try: _check_valid_varname(id) except: pass else: if id not in self.all_variables: # new free variable self.all_variables[id] = self.free_variables[id] = \ unresolved_type elif ctx_t is _ast.Store: try: current_type = self.all_variables[id] except KeyError: # new local variable _check_valid_varname(id) self.all_variables[id] = self.local_variables[id] = \ self.cur_assignment_type else: if id in self.local_variables: # multiple assignment of a local variable self.local_variables[id] = MultipleAssignmentType( current_type, self.cur_assignment_type) elif id in self.free_variables: raise InvalidOperationError( "Free variable %s cannot be assigned to." % id, n) # assignment is ok to arguments but it won't change its type elif ctx_t is _ast.Param: self.all_variables[id] = self.argument_variables[id] = \ unresolved_type return astx.copy_node(n, id=id, ctx=ctx, unresolved_type=unresolved_type)
def visit_AugAssign(self, n): # We temporarily turn it into the equivalent binary operation to # determine the unresolved type. # 1. have to temporarily turn the target from a store to a load target = n.target orig_ctx = target.ctx target.ctx = self._Load # 2. visit the binary operation value = self.visit(_ast.BinOp(left=target, op=n.op, right=n.value)) # 3. restore original ctx target.ctx = orig_ctx # cur_assignment_type as in Assign self.cur_assignment_type = value.unresolved_type new = astx.copy_node(n, target=self.visit(target), op=value.op, value=value.right) self.cur_assignment_type = None return new
def visit_FunctionDef(self, n): if self.in_function: raise NotImplementedError( "Inner concrete_fn definitions are not supported.") self.in_function = True args = self.visit(n.args) body = [self.visit(stmt) for stmt in n.body] return_type = self.return_type if return_type is None: return_type = cl.cl_void return astx.copy_node( n, name=n.name, args=args, body=body, return_type=return_type, all_variables=cypy.frozendict(self.all_variables), argument_variables=cypy.frozendict(self.argument_variables), local_variables=cypy.frozendict(self.local_variables), free_variables=cypy.frozendict(self.free_variables))
def visit_Str(self, n): return astx.copy_node(n, unresolved_type=InlineConstantType( n.s, cl.cl_char.private_ptr))
def visit_Num(self, n): num = n.n return astx.copy_node(n, unresolved_type=InlineConstantType( num, cl.infer_cl_type(num)))
def visit_Param(self, n): return astx.copy_node(n)
def visit_Store(self, n): return astx.copy_node(n)
def visit_Load(self, n): return astx.copy_node(n)
def visit_Index(self, n): value = self.visit(n.value) return astx.copy_node(n, value=value, unresolved_type=value.unresolved_type)
def visit_ExtSlice(self, n): dims = n.dims if dims: dims = [self.visit(dim) for dim in dims] return astx.copy_node(n, dims=dims)
def visit_Ellipsis(self, n): # here in case a virtual type wants to support it return astx.copy_node(n)
def visit_If(self, n): return astx.copy_node(n, test=self.visit(n.test), body=[self.visit(stmt) for stmt in n.body], orelse=[self.visit(stmt) for stmt in n.orelse])
def visit_Expr(self, n): return astx.copy_node(n, value=self.visit(n.value))
def visit_Break(self, n): return astx.copy_node(n)
def visit_Continue(self, n): return astx.copy_node(n)
def _visit_op(self, n): # all operators are just copied directly return astx.copy_node(n)