def visit_RaiseNode(self, node): if self.nopython: result = self._trap(node) else: result = self._raise_exception(node) return ast.Suite(body=result + [nodes.PropagateNode()])
def visit_RaiseNode(self, node): body = [] if self.nopython: self._trap(body, node) else: self._raise_exception(body, node) body.append(nodes.PropagateNode()) return ast.Suite(body=body)
def allocate_struct_on_stack(self, assmnt_node, target): # Allocate struct on stack temp = nodes.TempNode(target.type) assmnt_node.targets[0] = temp.store() assmnt_node.value = self.visit(assmnt_node.value) # Expose LLVM value through SSA (patch the Variable or the # LHS). We need to store the pointer to the struct (the alloca) ssa_assmnt = ast.Assign(targets=[target], value=temp.store()) return ast.Suite(body=[assmnt_node, ssa_assmnt])
def template(s, substitutions): s = textwrap.dedent(s) replaced = [0] def replace(ident): replaced[0] += 1 return '%s%s' % (prefix, ident.group(1)) source = re.sub('{{(.*?)}}', replace, s) tree = ast.parse(source) if replaced: tree = Interpolate(substitutions).visit(tree) return ast.Suite(body=tree.body)
def foldSwitch(node): # Note: condtion.conditional may be killed, as # it is assumed to be a reference. # Constant value cond = node.condition.conditional if existingConstant(cond): value = cond.object.pyobj taken = node.t if value else node.f return ast.Suite([node.condition.preamble, taken]) # Switch does nothing. if not node.t.blocks and not node.f.blocks: return node.condition.preamble return node
def visit_For(self, node): node.iter = self.visit(node.iter) if not isinstance(node.iter, PrangeNode): self.visitchildren(node) return node self.error_check_prange(node) node.target = self.visit(node.target) self.prange += 1 node.body = self.visitlist(node.body) self.prange -= 1 # Create prange closure prange_node = node.iter create_prange_closure(self.env, prange_node, node.body, node.target) # setup glue code pre_loop = rewrite_prange(self.env, prange_node, node.target, self.locals, self.closures) post_loop = perform_reductions(self.context, prange_node) # infer glue code at the right place pre_loop_dont_infer = nodes.dont_infer(pre_loop) pre_loop_infer_now = nodes.infer_now(pre_loop, pre_loop_dont_infer) # infer the type of the struct of privates right after the loop allprivates = set(prange_node.privates) | set(prange_node.reductions) type = prange_node.privates_struct_type infer_privates_struct = VariableTypeInferingNode(allprivates, type) # Signal that we now have additional local variables self.invalidate_locals() return ast.Suite(body=[ pre_loop_dont_infer, node, infer_privates_struct, pre_loop_infer_now, post_loop ])
def visit_Print(self, node): if self.nopython: printfunc = self._print_nopython dst_type = c_string_type else: printfunc = self._print dst_type = object_ result = [] if node.values: print_space = printfunc(nodes.const(" ", dst_type), node.dest) for value in node.values: result.append(printfunc(value, node.dest)) result.append(print_space) if node.nl: result.pop() # pop last space if node.nl: result.append(printfunc(nodes.const("\n", dst_type), node.dest)) return ast.Suite(body=self.visitlist(result))
def visit_For(self, node): while_node = make_while_from_for(node) test = nodes.const(True, bool_) while_node.test = test impl = loopimpl.find_iterator_impl(node) # Get the iterator, loop body, and the item iter = impl.getiter(self.context, node, self.llvm_module) body = impl.body(self.context, node, self.llvm_module) item = impl.next(self.context, node, self.llvm_module) # Coerce item to LHS and assign item = nodes.CoercionNode(item, node.target.type) target_assmnt = ast.Assign(targets=[node.target], value=item) # Update While node body body.insert(0, target_assmnt) while_node.body = body nodes.merge_cfg_in_while(while_node) return ast.Suite(body=[iter, while_node])
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 test_Suite(self): self.verify(ast.Suite([ast.Pass()]), 'pass')
def rewrite_range_iteration(self, node): """ Handle range iteration: for i in range(start, stop, step): ... becomes nsteps = compute_nsteps(start, stop, step) temp = 0 while temp < nsteps: target = start + temp * step ... temp += 1 """ self.generic_visit(node) temp = nodes.TempNode(node.target.type, 'target_temp') nsteps = nodes.TempNode(Py_ssize_t, 'nsteps') start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = [ nodes.CloneableNode(n) for n in (start, stop, step) ] if have_step: compute_nsteps = """ $length = {{stop}} - {{start}} {{nsteps}} = $length / {{step}} if {{nsteps_load}} * {{step}} != $length: #$length % {{step}}: # Test for truncation {{nsteps}} = {{nsteps_load}} + 1 # print "nsteps", {{nsteps_load}} """ else: compute_nsteps = "{{nsteps}} = {{stop}} - {{start}}" if node.orelse: else_clause = "else: {{else_body}}" else: else_clause = "" templ = textwrap.dedent(""" %s {{temp}} = 0 while {{temp_load}} < {{nsteps_load}}: {{target}} = {{start}} + {{temp_load}} * {{step}} {{body}} {{temp}} = {{temp_load}} + 1 %s """) % (textwrap.dedent(compute_nsteps), else_clause) # Leave the bodies empty, they are already analyzed body = ast.Suite(body=[]) else_body = ast.Suite(body=[]) #-------------------------------------------------------------------- # Substitute template and infer types #-------------------------------------------------------------------- result = self.run_template(templ, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load(), temp=temp.store(), temp_load=temp.load(), target=node.target, body=body, else_body=else_body) #-------------------------------------------------------------------- # Patch the body and else clause #-------------------------------------------------------------------- body.body.extend(node.body) else_body.body.extend(node.orelse) while_node = result.body[-1] assert isinstance(while_node, ast.While) target_increment = while_node.body[-1] assert isinstance(target_increment, ast.Assign) # Add target variable increment basic block node.incr_block.body = [target_increment] while_node.body[-1] = node.incr_block #-------------------------------------------------------------------- # Create a While with the ForNode's cfg blocks merged in #-------------------------------------------------------------------- while_node = make_while_loop(while_node) copy_basic_blocks(node, while_node) while_node = nodes.build_while(**vars(while_node)) # Create the place to jump to for 'continue' while_node.continue_block = node.incr_block # Set the new while loop in the templated Suite result.body[-1] = while_node return result
def visit_For(self, node): if node.orelse: raise error.NumbaError(node, 'Else in for-loop is not implemented.') if node.iter.type.is_range: self.generic_visit(node) temp = nodes.TempNode(node.target.type) nsteps = nodes.TempNode(Py_ssize_t) start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = [nodes.CloneableNode(n) for n in (start, stop, step)] if have_step: s1 = self.run_template( """ $length = {{stop}} - {{start}} {{nsteps}} = $length / {{step}} if $length % {{step}}: {{nsteps}} = {{nsteps_load}} + 1 """, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load()) step = step.clone else: s1 = self.run_template( "{{nsteps}} = {{stop}} - {{start}}", start=start, stop=stop, nsteps=nsteps.store()) # Rely on LLVM strength reduction. It's easier this way, or we # need to make the assignment to 'target' conditional for zero # iterations s2 = self.run_template( "{{target}} = {{start}} + {{temp}} * {{step}}", target=node.target, start=start.clone, stop=stop.clone, step=step, temp=temp.load()) body = node.body body.insert(0, s2) zero = nodes.const(0, nsteps.type) one = nodes.const(1, nsteps.type) return ast.Suite([s1, nodes.ForRangeNode(index=temp.load(), target=temp.store(), start=zero, stop=nsteps.load(), step=one, body=body)]) elif node.iter.type.is_array and node.iter.type.ndim == 1: # Convert 1D array iteration to for-range and indexing logger.debug(ast.dump(node)) orig_target = node.target orig_iter = node.iter # replace node.target with a temporary target_name = orig_target.id + '.idx' target_temp = nodes.TempNode(Py_ssize_t) node.target = target_temp.store() # replace node.iter call_func = ast.Name(id='range', ctx=ast.Load()) call_func.type = numba_types.RangeType() call_func.variable = Variable(call_func.type) shape_index = ast.Index(nodes.ConstNode(0, numba_types.Py_ssize_t)) shape_index.type = numba_types.npy_intp stop = ast.Subscript(value=nodes.ShapeAttributeNode(orig_iter), slice=shape_index, ctx=ast.Load()) stop.type = numba_types.intp stop.variable = Variable(stop.type) call_args = [nodes.ConstNode(0, numba_types.Py_ssize_t), nodes.CoercionNode(stop, numba_types.Py_ssize_t), nodes.ConstNode(1, numba_types.Py_ssize_t),] node.iter = ast.Call(func=call_func, args=call_args) node.iter.type = call_func.type node.index = target_temp.load() # add assignment to new target variable at the start of the body index = ast.Index(value=node.index) index.type = target_temp.type subscript = ast.Subscript(value=orig_iter, slice=index, ctx=ast.Load()) subscript.type = orig_iter.variable.type.dtype subscript.variable = Variable(subscript.type) coercion = nodes.CoercionNode(subscript, orig_target.type) assign = ast.Assign(targets=[orig_target], value=subscript) node.body = [assign] + node.body return self.visit(node) else: raise error.NumbaError("Unsupported for loop pattern")
def rewrite_range_iteration(self, node): """ Handle range iteration: for i in range(start, stop, step): ... becomes nsteps = compute_nsteps(start, stop, step) temp = 0 while temp < nsteps: target = start + temp * step ... temp += 1 """ self.generic_visit(node) temp = nodes.TempNode(node.target.type, 'target_temp') nsteps = nodes.TempNode(Py_ssize_t, 'nsteps') start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = map(nodes.CloneableNode, (start, stop, step)) if have_step: templ = textwrap.dedent(""" {{temp}} = 0 {{nsteps}} = ({{stop}} - {{start}} + {{step}} - (1 if {{step}} >= 0 else -1)) / {{step}} while {{temp_load}} < {{nsteps_load}}: {{target}} = {{start}} + {{temp_load}} * {{step}} {{temp}} = {{temp_load}} + 1 {{body}} """) else: templ = textwrap.dedent(""" {{temp}} = {{start}} {{nsteps}} = {{stop}} while {{temp_load}} < {{nsteps_load}}: {{target}} = {{temp_load}} {{temp}} = {{temp_load}} + 1 {{body}} """) if node.orelse: templ += "\nelse: {{else_body}}" # Leave the bodies empty, they are already analyzed body = ast.Suite(body=[]) else_body = ast.Suite(body=[]) #-------------------------------------------------------------------- # Substitute template and infer types #-------------------------------------------------------------------- result = self.run_template(templ, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load(), temp=temp.store(), temp_load=temp.load(), target=node.target, body=body, else_body=else_body) ast.copy_location(result, node) if hasattr(node, 'lineno'): visitor = missing.FixMissingLocations(node.lineno, node.col_offset, override=True) visitor.visit(result) #-------------------------------------------------------------------- # Patch the body and else clause #-------------------------------------------------------------------- body.body.extend(node.body) else_body.body.extend(node.orelse) while_node = result.body[-1] assert isinstance(while_node, ast.While) #-------------------------------------------------------------------- # Create a While with the ForNode's cfg blocks merged in #-------------------------------------------------------------------- while_node = make_while_loop(while_node) copy_basic_blocks(node, while_node) while_node = nodes.build_while(**vars(while_node)) # Create the place to jump to for 'continue' while_node.continue_block = node.cond_block # Set the new while loop in the templated Suite result.body[-1] = while_node return result
def test_empty_init(self): # Jython 2.5.0 did not allow empty constructors for many ast node types # but CPython ast nodes do allow this. For the moment, I don't see a # reason to allow construction of the super types (like ast.AST and # ast.stmt) as well as the op types that are implemented as enums in # Jython (like boolop), but I've left them in but commented out for # now. We may need them in the future since CPython allows this, but # it may fall under implementation detail. #ast.AST() ast.Add() ast.And() ast.Assert() ast.Assign() ast.Attribute() ast.AugAssign() ast.AugLoad() ast.AugStore() ast.BinOp() ast.BitAnd() ast.BitOr() ast.BitXor() ast.BoolOp() ast.Break() ast.Call() ast.ClassDef() ast.Compare() ast.Continue() ast.Del() ast.Delete() ast.Dict() ast.Div() ast.Ellipsis() ast.Eq() ast.Exec() ast.Expr() ast.Expression() ast.ExtSlice() ast.FloorDiv() ast.For() ast.FunctionDef() ast.GeneratorExp() ast.Global() ast.Gt() ast.GtE() ast.If() ast.IfExp() ast.Import() ast.ImportFrom() ast.In() ast.Index() ast.Interactive() ast.Invert() ast.Is() ast.IsNot() ast.LShift() ast.Lambda() ast.List() ast.ListComp() ast.Load() ast.Lt() ast.LtE() ast.Mod() ast.Module() ast.Mult() ast.Name() ast.Not() ast.NotEq() ast.NotIn() ast.Num() ast.Or() ast.Param() ast.Pass() ast.Pow() ast.Print() ast.RShift() ast.Raise() ast.Repr() ast.Return() ast.Slice() ast.Store() ast.Str() ast.Sub() ast.Subscript() ast.Suite() ast.TryExcept() ast.TryFinally() ast.Tuple() ast.UAdd() ast.USub() ast.UnaryOp() ast.While() ast.With() ast.Yield() ast.alias() ast.arguments() #ast.boolop() #ast.cmpop() ast.comprehension() #ast.excepthandler() #ast.expr() #ast.expr_context() ast.keyword()
def register_array_expression(self, node, lhs=None): super(ArrayExpressionRewriteNative, self).register_array_expression( node, lhs) lhs_type = lhs.type if lhs else node.type is_expr = lhs is None if node.type.is_array and lhs_type.ndim < node.type.ndim: # TODO: this is valid in NumPy if the leading dimensions of the # TODO: RHS have extent 1 raise error.NumbaError( node, "Right hand side must have a " "dimensionality <= %d" % lhs_type.ndim) # Create ufunc scalar kernel ufunc_ast, signature, ufunc_builder = self.get_py_ufunc_ast(lhs, node) signature.struct_by_reference = True # Compile ufunc scalar kernel with numba ast.fix_missing_locations(ufunc_ast) func_env, (_, _, _) = pipeline.run_pipeline2( self.env, None, ufunc_ast, signature, function_globals={}, ) # Manual linking lfunc = func_env.lfunc # print lfunc operands = ufunc_builder.operands functions.keep_alive(self.func, lfunc) operands = [nodes.CloneableNode(operand) for operand in operands] if lhs is not None: lhs = nodes.CloneableNode(lhs) broadcast_operands = [lhs] + operands lhs = lhs.clone else: broadcast_operands = operands[:] shape = slicenodes.BroadcastNode(lhs_type, broadcast_operands) operands = [op.clone for op in operands] if lhs is None and self.nopython: raise error.NumbaError( node, "Cannot allocate new memory in nopython context") elif lhs is None: # TODO: determine best output order at runtime shape = shape.cloneable lhs = nodes.ArrayNewEmptyNode(lhs_type, shape.clone, lhs_type.is_f_contig).cloneable # Build minivect wrapper kernel context = NumbaproStaticArgsContext() context.llvm_module = self.env.llvm_context.module # context.debug = True context.optimize_broadcasting = False b = context.astbuilder variables = [b.variable(name_node.type, "op%d" % i) for i, name_node in enumerate([lhs] + operands)] miniargs = [b.funcarg(variable) for variable in variables] body = miniutils.build_kernel_call(lfunc.name, signature, miniargs, b) minikernel = b.function_from_numpy( templating.temp_name("array_expression"), body, miniargs) lminikernel, ctypes_kernel = context.run_simple( minikernel, specializers.StridedSpecializer) # Build call to minivect kernel operands.insert(0, lhs) args = [shape] scalar_args = [] for operand in operands: if operand.type.is_array: data_p = self.array_attr(operand, 'data') data_p = nodes.CoercionNode(data_p, operand.type.dtype.pointer()) if not isinstance(operand, nodes.CloneNode): operand = nodes.CloneNode(operand) strides_p = self.array_attr(operand, 'strides') args.extend((data_p, strides_p)) else: scalar_args.append(operand) args.extend(scalar_args) result = nodes.NativeCallNode(minikernel.type, args, lminikernel) # Use native slicing in array expressions slicenodes.mark_nopython(ast.Suite(body=result.args)) if not is_expr: # a[:] = b[:] * c[:] return result # b[:] * c[:], return new array as expression return nodes.ExpressionNode(stmts=[result], expr=lhs.clone)