def visit_ArrayDecl( # pylint: disable=invalid-name self, node) -> t.Tuple[str, typed_ast3.Subscript]: """Return tuple of: name, st.ndarray[..., ...] for given array type information.""" name, type_ = self.visit(node.type) assert isinstance(name, str) assert isinstance(type_, typed_ast3.AST) dim = self.visit(node.dim) if dim is not None: raise NotImplementedError(_node_debug(node.dim), str(dim)) dim_quals = [self.visit(subnode) for subnode in node.dim_quals] if dim_quals: raise NotImplementedError(_node_debug(node.dim_quals), str(dim_quals)) _ = self.visit(node.coord) return name, 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.ExtSlice(dims=[ typed_ast3.Index(value=typed_ast3.Ellipsis()), typed_ast3.Index(value=type_) # , # typed_ast3.Index(value=typed_ast3.Tuple(n=-1)) ]), ctx=typed_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 visit_For(self, node: ast.For) -> None: # create list to iterate over lst_name = self.context.get_temp_name() assign_node = ast.Assign( targets=[ast.Name(id=lst_name, ctx=ast.Store())], value=node.iter) self.visit(assign_node) lst = self.context[lst_name] index = self.context.get_temp_var(TypeDB.get_type_by_name("int")) length = lst.tp.get_method("len") length_code = length.get_code(self.context, lst).code # construct for statement self.start_line( f"for({index.code}=0; {index.code} < {length_code}; {index.code}++) {{\n" ) self.indent += 4 assign_node = ast.Assign( targets=[node.target], value=ast.Subscript( value=ast.Name(id=lst_name, ctx=ast.Load()), slice=ast.Index(value=ast.Name(id=index.code, ctx=ast.Load())), ctx=ast.Load())) self.visit(assign_node) for statement in node.body: self.visit(statement) self.indent -= 4 self.start_line("}\n") self.all_paths_return = False
def visit_ArrayRef(self, node): # pylint: disable=invalid-name name = self.visit(node.name) subscript = self.visit(node.subscript) _ = self.visit(node.coord) return typed_ast3.Subscript(value=name, slice=typed_ast3.Index(subscript), ctx=typed_ast3.Load())
def _Class(self, node: ET.Element): # pylint: disable=invalid-name context = node.attrib['context'] assert context in self.namespaces, context cls_name = node.attrib['name'] if '<' in cls_name: _LOG.warning('processing template class %s', cls_name) assert '>' in cls_name cls_name, _, rest = cls_name.partition('<') rest = rest[:-1] generic_args = [_.strip() for _ in rest.split(',')] _LOG.warning('found generic args: %s', generic_args) full_name = '{}::{}'.format(self.namespaces[context], cls_name) is_stl_class = full_name in CPP_STL_CLASSES and generic_args value_type = None body = [] for member_id in node.attrib['members'].split(): if not is_stl_class: # TODO: handle non-STL classes too break if member_id not in self.all_types: continue member_type = self.all_types[member_id] if member_type.tag == 'Typedef' and member_type.attrib[ 'name'] == 'value_type': referenced_id = member_type.attrib['type'] assert referenced_id in self.all_types if referenced_id not in self.relevant_types \ and referenced_id not in self._new_relevant_types: self._new_relevant_types[referenced_id] = self.all_types[ referenced_id] _LOG.debug( 'type marked as relevant due to being container value type %s', ET.tostring( self.all_types[referenced_id]).decode().rstrip()) body.append(typed_ast3.Expr(typed_ast3.Str(referenced_id, ''))) value_type = referenced_id ''' if member_id not in self.relevant_types and member_id not in self._new_relevant_types: self._new_relevant_types[member_id] = member_type _LOG.warning('marked %s as relevant type', ET.tostring(member_type).decode().rstrip()) body.append(typed_ast3.Expr(typed_ast3.Str(member_id, ''))) ''' base_class = typed_ast3.parse(CPP_PYTHON_CLASS_PAIRS[full_name], mode='eval').body if is_stl_class: assert value_type is not None base_class = typed_ast3.Subscript( value=base_class, slice=typed_ast3.Index(typed_ast3.Str(value_type, '')), ctx=typed_ast3.Load()) return base_class
def _PointerType(self, node: ET.Element): # pylint: disable=invalid-name id_ = node.attrib['id'] type_ = node.attrib['type'] is_const = type_.endswith('c') if is_const: type_ = type_[:-1] try: base_type = self.fundamental_types[type_] except KeyError: # _LOG.debug() base_type = typed_ast3.Str(type_, '') type_info = typed_ast3.Subscript(value=typed_ast3.Name( id='Pointer', ctx=typed_ast3.Load()), slice=typed_ast3.Index(base_type), ctx=typed_ast3.Load()) if is_const: type_info = typed_ast3.Subscript(value=typed_ast3.Name( id='Const', ctx=typed_ast3.Load()), slice=typed_ast3.Index(type_info), ctx=typed_ast3.Load()) return (id_, type_info)
def visit_ListComp(self, node): from parser.functions import FunctionImplementation # calculate result type if len(node.generators) > 1: raise InvalidOperation( "Only one for statement permitted in comprehensions") comp = node.generators[0] if len(comp.ifs) > 1: raise InvalidOperation( "Only one if statement allowed in List Comprehension") assign_node = ast.Assign(targets=[comp.target], value=ast.Subscript(value=comp.iter, slice=ast.Index( ast.Num(0)))) return_node = ast.Return(value=node.elt) function_node = ast.FunctionDef(name="temp", args=ast.arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[assign_node, return_node]) function_interpreter = FunctionImplementation(function_node, (), self.context) result_type = TypeDB.get_list([function_interpreter.retval.tp]) # create temp list to hold values result = self.context.get_temp_var(result_type) self.prepends.append( f"{result.code} = {result_type.as_literal([])};\n") # create for expression append_node = ast.Expr( ast.Call(func=ast.Attribute(value=ast.Name(id=result.code, ctx=ast.Load()), attr="append", ctx=ast.Load()), args=[node.elt], keywords=[])) if comp.ifs: body = ast.If(test=comp.ifs[0], body=[append_node], orelse=[]) else: body = append_node for_node = ast.For(target=comp.target, iter=comp.iter, body=[body], orelse=[]) self.prepends.append(for_node) return result
def visit_PtrDecl(self, node): # pylint: disable=invalid-name """Return st.Pointer[...] for given pointer type.""" quals = node.quals if quals: _LOG.warning('ignoring unsupported C grammar: %s', quals) name, type_ = self.visit(node.type) assert name is None or isinstance(name, str) assert isinstance(type_, typed_ast3.AST), type(type_) _ = self.visit(node.coord) # assert type_ is not None, _node_str(node) return name, typed_ast3.Subscript( value=typed_ast3.Attribute(value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()), attr='Pointer', ctx=typed_ast3.Load()), slice=typed_ast3.Index(value=type_), ctx=typed_ast3.Load())
def visit_TypeDecl(self, node) -> t.Tuple[str, typed_ast3.Name]: # pylint: disable=invalid-name """Return a tuple: identifier and its type.""" declname = node.declname assert declname is None or isinstance(declname, str) quals = node.quals type_ = self.visit(node.type) assert isinstance(type_, typed_ast3.Name), type(type_) for qual in quals: assert isinstance(qual, str) type_ = typed_ast3.Subscript( value=typed_ast3.Attribute(value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()), attr=qual.title(), ctx=typed_ast3.Load()), slice=typed_ast3.Index(value=type_), ctx=typed_ast3.Load()) _ = self.visit(node.coord) return declname, type_
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 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 make_const(base_type: typed_ast3.AST): return typed_ast3.Subscript(value=typed_ast3.Name(id='Const', ctx=typed_ast3.Load()), slice=typed_ast3.Index(base_type), ctx=typed_ast3.Load())
def make_pointer(base_type: typed_ast3.AST): return typed_ast3.Subscript(value=typed_ast3.Name(id='Pointer', ctx=typed_ast3.Load()), slice=typed_ast3.Index(base_type), ctx=typed_ast3.Load())
def visit_Ellipsis(self, n): # ellipses in Python 2 only exist as a slice index return ast3.Index(ast3.Ellipsis(lineno=-1, col_offset=-1))