def pos_as_tuple(node: Union[ast3.expr, ast3.stmt]) -> Optional[ast3.Tuple]: if not hasattr(node, 'lineno'): return None return ast3.Tuple(elts=[ ast3.Tuple(elts=[ast3.Num(node.lineno), ast3.Num(node.col_offset)], ctx=ast3.Load()), ast3.Name(id='fn', ctx=ast3.Load()) ], ctx=ast3.Load())
def visit_Attribute(self, node: ast3.Attribute) -> VisitorOutput: """Transforms accessing to an attribute to be handled as PythonValues do For example, it converts:: expr.val into:: expr.attr['val'] or:: expr.attr[('val', pos)]""" self.generic_visit(node) pos = pos_as_tuple(node) if pos is not None: varname = ast3.Tuple(elts=[ast3.Str(s=node.attr), pos], ctx=ast3.Load()) # type: ast3.expr else: varname = ast3.Str(s=node.attr) return ast3.Subscript( value=ast3.Attribute( value=node.value, attr='attr', ctx=ast3.Load(), ), slice=ast3.Index(value=varname, ), ctx=node.ctx, )
def make_st_ndarray(data_type: typed_ast3.AST, dimensions_or_sizes: t.Union[int, list]) -> typed_ast3.Subscript: """Create a typed_ast node equivalent to: st.ndarray[dimensions, data_type, sizes].""" if isinstance(dimensions_or_sizes, int): dimensions = dimensions_or_sizes sizes = None else: dimensions = len(dimensions_or_sizes) sizes = [make_expression_from_slice(size) for size in dimensions_or_sizes] return typed_ast3.Subscript( value=typed_ast3.Attribute( value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()), attr='ndarray', ctx=typed_ast3.Load()), slice=typed_ast3.Index(value=typed_ast3.Tuple( elts=[typed_ast3.Num(n=dimensions), data_type] + [ typed_ast3.Tuple(elts=sizes, ctx=typed_ast3.Load())] if sizes else [], ctx=typed_ast3.Load())), ctx=typed_ast3.Load())
def dispatch_var_type(self, tree): code = horast.unparse(tree) stripped_code = code.strip() if stripped_code in PYTHON_FORTRAN_TYPE_PAIRS: type_name, precision = PYTHON_FORTRAN_TYPE_PAIRS[stripped_code] self.write(type_name) if precision is not None: self.write('*') self.write(str(precision)) elif _match_array(tree): sli = tree.slice assert isinstance(sli, typed_ast3.Index), typed_astunparse.dump(tree) assert isinstance(sli.value, typed_ast3.Tuple) assert len(sli.value.elts) in (2, 3), sli.value.elts elts = sli.value.elts self.dispatch_var_type(elts[1]) self.write(', ') self.write('dimension(') if len(sli.value.elts) == 2: self.write(':') else: if not self._context_input_args: self.dispatch(elts[2]) else: assert isinstance(elts[2], typed_ast3.Tuple) _LOG.warning('coercing indices of %i dims to 0-based', len(elts[2].elts)) # _LOG.warning('coercing indices of %s in %s to 0-based', arg.arg, t.name) tup_elts = [] for elt in elts[2].elts: if isinstance(elt, typed_ast3.Num): assert isinstance(elt.n, int) upper = typed_ast3.Num(n=elt.n - 1) else: assert isinstance(elt, typed_ast3.Name) upper = typed_ast3.BinOp(left=elt, op=typed_ast3.Sub(), right=typed_ast3.Num(n=1)) tup_elts.append( typed_ast3.Slice(lower=typed_ast3.Num(n=0), upper=upper, step=None)) tup = typed_ast3.Tuple(elts=tup_elts, ctx=typed_ast3.Load()) self.dispatch(tup) self.write(')') elif _match_io(tree): self.write('integer') elif isinstance(tree, typed_ast3.Call) and isinstance(tree.func, typed_ast3.Name) \ and tree.func.id == 'type': self.dispatch(tree) else: raise NotImplementedError('not yet implemented: {}'.format( typed_astunparse.dump(tree)))
def make_expression_from_slice( slice_: t.Union[typed_ast3.Index, typed_ast3.Slice, typed_ast3.ExtSlice]) -> typed_ast3.AST: """Transform code like '0:n:2' into a valid expression that is as simple as possible.""" assert isinstance(slice_, ( typed_ast3.Index, typed_ast3.Slice, typed_ast3.ExtSlice)), type(slice_) if isinstance(slice_, typed_ast3.Index): return slice_.value if isinstance(slice_, typed_ast3.Slice): lower, upper, step = slice_.lower, slice_.upper, slice_.step if lower is None and upper is not None and step is None: return upper return make_call_from_slice(slice_) assert isinstance(slice_, typed_ast3.ExtSlice) elts = [make_expression_from_slice(dim) for dim in slice_.dims] return typed_ast3.Tuple(elts=elts, ctx=typed_ast3.Load())
def visit_Name(self, node: ast3.Name) -> VisitorOutput: """Transforms a name lookup into a dictionary lookup. For example, it converts:: var into:: st[('var', ...)] """ pos = pos_as_tuple(node) if pos is not None: varname = ast3.Tuple(elts=[ast3.Str(s=node.id), pos], ctx=ast3.Load()) # type: ast3.expr else: varname = ast3.Str(s=node.id) return ast3.Subscript(value=ast3.Name(id='st', ctx=ast3.Load()), slice=ast3.Index(value=varname), ctx=node.ctx)
def visit_ImportFrom(self, node: ast3.ImportFrom) -> VisitorOutput: """Defines how to import (from) modules (supported and nonsupported) For example, it converts:: from numpy import array from numpy import * from somelib import var, othervar as var2 from otherlib import * into:: from pytropos.libs_checking import numpy_module st['array'] = numpy_module.attr['array', pos...] from pytropos.libs_checking import numpy_module st.importStar(numpy_module) st['var'] = pt.Top st['var2'] = pt.Top st.importStar() """ libs: 'List[ast3.AST]' = [] if node.module in self._supported_modules: module_name = self._supported_modules[node.module] # from pytropos.libs_checking import module_name libs.append( ast3.ImportFrom( module='pytropos.libs_checking', names=[ast3.alias(name=module_name, asname=None)], level=0, )) if node.names[0].name == '*': # st.importStar(module_name) libs.append( ast3.Expr(value=ast3.Call( func=ast3.Attribute( value=ast3.Name(id='st', ctx=ast3.Load()), attr='importStar', ctx=ast3.Load(), ), args=[ast3.Name(id=module_name, ctx=ast3.Load())], keywords=[], ), )) else: for alias in node.names: # st['asname'] = modname.attr['name'] pos = pos_as_tuple(node) if pos is not None: attrname = ast3.Tuple( elts=[ast3.Str(s=alias.name), pos], ctx=ast3.Load()) # type: ast3.expr else: attrname = ast3.Str(s=alias.name) libs.append( ast3.Assign( targets=[ ast3.Subscript( value=ast3.Name(id='st', ctx=ast3.Load()), slice=ast3.Index(value=ast3.Str( s=alias.asname if alias. asname else alias.name), ), ctx=ast3.Store(), ), ], value=ast3.Subscript( value=ast3.Attribute( value=ast3.Name(id=module_name, ctx=ast3.Load()), attr='attr', ctx=ast3.Load(), ), slice=ast3.Index(value=attrname, ), ctx=ast3.Load(), ), )) else: if node.names[0].name == '*': # st.importStar() libs.append( ast3.Expr(value=ast3.Call( func=ast3.Attribute( value=ast3.Name(id='st', ctx=ast3.Load()), attr='importStar', ctx=ast3.Load(), ), args=[], keywords=[], ), )) else: libs.extend( ast3.parse( # type: ignore '\n'.join([ "st['{asname}'] = pt.Top".format( asname=alias.asname if alias.asname else alias. name) for alias in node.names ])).body) return libs
def visit_Call(self, node: ast3.Call) -> VisitorOutput: """Transforms a call to be handled by Pytropos For example, it converts:: func(3, b, *c, d=2) into:: func.call(st, Args((pt.int(3), st['b']), st['c'], {'d': pt.int(2)}), pos=...)""" self.generic_visit(node) args = [] # type: List[ast3.expr] starred = None # type: Optional[ast3.expr] kwargs_keys = [] # type: List[ast3.expr] kwargs_values = [] # type: List[ast3.expr] for i, v in enumerate(node.args): if isinstance(v, ast3.Starred): starred = v.value break args.append(v) # In case a starred expresion was found else: # If there is something after the starred expr if len(node.args) > 0 and i < len(node.args) - 1: raise AstTransformerError( f"{self.filename}:{v.lineno}:{v.col_offset}: Fatal Error: " "Only one expression starred is allowed when calling a function" ) for val in node.keywords: if val.arg is None: raise AstTransformerError( f"{self.filename}:{v.lineno}:{v.col_offset}: Fatal Error: " "No kargs parameters is allowed when calling a function") kwargs_keys.append(ast3.Str(s=val.arg)) kwargs_values.append(val.value) new_call_args = [ ast3.Tuple( elts=args, ctx=ast3.Load(), ), ] # type: List[ast3.expr] if kwargs_keys: new_call_args.append( ast3.NameConstant(value=None) if starred is None else starred) new_call_args.append( ast3.Dict(keys=kwargs_keys, values=kwargs_values)) elif starred is not None: new_call_args.append(starred) return ast3.Call( func=ast3.Attribute( value=node.func, attr='call', ctx=ast3.Load(), ), args=[ ast3.Name(id='st', ctx=ast3.Load()), ast3.Call( func=ast3.Attribute( value=ast3.Name(id='pt', ctx=ast3.Load()), attr='Args', ctx=ast3.Load(), ), args=new_call_args, keywords=[], ) ], keywords=[ ast3.keyword(arg='pos', value=pos_as_tuple(node), ctx=ast3.Load()) ], )