def evaluate_call(node: ast3.Call, *, scope: Scope, module_path: catalog.Path) -> Node: if not is_named_tuple_definition(node, scope=scope, module_path=module_path): return node class_name_node, fields_node = node.args def field_to_parameter(field_node: ast3.expr) -> ast3.arg: name_node, annotation_node = field_node.elts return ast3.arg(ast3.literal_eval(name_node), annotation_node) initializer_node = ast3.FunctionDef( '__init__', ast3.arguments([ast3.arg('self', None)] + list(map(field_to_parameter, fields_node.elts)), None, [], [], None, []), [ast3.Pass()], [], None) function_path = evaluate_node(node.func, scope=scope, module_path=module_path) class_def = ast3.ClassDef(ast3.literal_eval(class_name_node), [ast3.Name(str(function_path), ast3.Load())], [], [initializer_node], []) return ast3.fix_missing_locations(ast3.copy_location(class_def, node))
def visit_ParamList(self, node) -> typed_ast3.arguments: # pylint: disable=invalid-name """Transform ParamList.""" params = [self.visit(subnode) for subnode in node.params] # assert all(isinstance(param, tuple) for param in params), params # params = [typed_ast3.arg(arg=param[0], annotation=param[1]) for param in params] assert all(isinstance(param, typed_ast3.AnnAssign) for param in params), params assert all(isinstance(param.target, typed_ast3.Name) for param in params), params params = [typed_ast3.arg(arg=param.target.id, annotation=param.annotation) for param in params] _ = self.visit(node.coord) return typed_ast3.arguments(args=params, vararg=None, kwonlyargs=[], kwarg=None, defaults=[], kw_defaults=[])
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_arguments(self, n): def convert_arg(arg, type_comment): if isinstance(arg, ast27.Name): v = arg.id elif isinstance(arg, ast27.Tuple): v = self.visit(arg) else: raise RuntimeError("'{}' is not a valid argument.".format( ast27.dump(arg))) return ast3.arg(v, None, type_comment, lineno=arg.lineno, col_offset=arg.col_offset) def get_type_comment(i): if i < len(n.type_comments) and n.type_comments[i] is not None: return n.type_comments[i] return None args = [ convert_arg(arg, get_type_comment(i)) for i, arg in enumerate(n.args) ] vararg = None if n.vararg is not None: vararg = ast3.arg(n.vararg, None, get_type_comment(len(args)), lineno=-1, col_offset=-1) kwarg = None if n.kwarg is not None: kwarg = ast3.arg( n.kwarg, None, get_type_comment(len(args) + (0 if n.vararg is None else 1)), lineno=-1, col_offset=-1, ) defaults = self.visit(n.defaults) return ast3.arguments(args, vararg, [], [], kwarg, defaults)
def _FunctionDef(self, t, *, in_class: typed_ast3.ClassDef = None): if t.decorator_list: self._unsupported_syntax(t, 'with decorators') self.write('\n') if in_class: self.leave(write_brace=False) if t.name in self.special_method_names: access = 'public' elif t.name.startswith('__'): access = 'private' elif t.name.startswith('_'): access = 'protected' else: _LOG.warning('unparsing function "%s" as public', t.name) access = 'public' self.fill('{}:'.format(access)) self.enter(write_brace=False) self.fill() if in_class and t.name in self.unsupported_special_method_names: raise NotImplementedError('not supported yet') if not in_class or t.name not in self.constructor_and_destructor_names: if t.returns is None: self.write('void ') else: self.dispatch_type(t.returns) self.write(' ') if in_class and t.name == '__init__': self.write('{}'.format(in_class.name)) elif in_class and t.name == '__del__': self.write('~{}'.format(in_class.name)) else: self.write('{}'.format(t.name)) self.write('(') if in_class: # skip 1st arg _ = t.args args = typed_ast3.arguments(_.args[1:], _.vararg, _.kwonlyargs, _.kwarg, _.defaults, _.kw_defaults) self.dispatch(args) else: self.dispatch(t.args) self.write(')') self.enter() self.dispatch(t.body) self.leave()
def _Function(self, node: ET.Element): # pylint: disable=invalid-name if not self.types.is_relevant(node): raise ContinueIteration() name = node.attrib['name'] arguments = typed_ast3.arguments( args=self.transform_all_subnodes(node), vararg=None, kwonlyargs=[], kwarg=None, defaults=[], kw_defaults=[]) body = [typed_ast3.Expr(value=typed_ast3.Ellipsis())] returns = self.types.resolved_types[node.attrib['returns']] return typed_ast3.FunctionDef(name=name, args=arguments, body=body, decorator_list=[], returns=returns)
def visit_arguments(self, n): def convert_arg(arg, type_comment): if isinstance(arg, ast27.Name): v = arg.id elif isinstance(arg, ast27.Tuple): v = self.visit(arg) else: raise RuntimeError("'{}' is not a valid argument.".format(ast27.dump(arg))) return ast3.arg(v, None, type_comment, lineno=arg.lineno, col_offset=arg.col_offset) def get_type_comment(i): if i < len(n.type_comments) and n.type_comments[i] is not None: return n.type_comments[i] return None args = [convert_arg(arg, get_type_comment(i)) for i, arg in enumerate(n.args)] vararg = None if n.vararg is not None: vararg = ast3.arg(n.vararg, None, get_type_comment(len(args)), lineno=-1, col_offset=-1) kwarg = None if n.kwarg is not None: kwarg = ast3.arg(n.kwarg, None, get_type_comment(len(args) + (0 if n.vararg is None else 1)), lineno=-1, col_offset=-1) defaults = self.visit(n.defaults) return ast3.arguments(args, vararg, [], [], kwarg, defaults)
def test_inline_flash_subset_hydro(self): app_name = 'FLASH-SUBSET' if app_name not in _APPS_ROOT_PATHS and app_name in _APPS_OPTIONAL: self.skipTest('{} directory not found'.format(app_name)) language = Language.find('Fortran') reader = CodeReader() parser = Parser.find(language)() ast_generalizer = AstGeneralizer.find(language)() f_unparser = Unparser.find(language)() py_unparser = Unparser.find(Language.find('Python'))() writer = CodeWriter() dir_name = app_name.lower() results_path = pathlib.Path(RESULTS_ROOT, 'transformations', 'inlining', dir_name) results_path.mkdir(parents=True, exist_ok=True) path_pairs = [ (pathlib.Path('physics/Hydro/HydroMain/unsplit/hy_upwindTransverseFlux_loop.F90'), pathlib.Path('physics/Hydro/HydroMain/unsplit/hy_upwindTransverseFlux.F90'), (1, 1)), (pathlib.Path('physics/Eos/EosMain/Eos_getData_loop1.F90'), pathlib.Path('physics/Eos/EosMain/Eos_getData.F90'), (1, 2))] for inlined_path, target_path, (index, extra_lines) in path_pairs: inlined_path = pathlib.Path(_APPS_ROOT_PATHS[app_name], 'source', inlined_path) target_path = pathlib.Path(_APPS_ROOT_PATHS[app_name], 'source', target_path) output_inlined_path = results_path.joinpath(inlined_path.name) output_target_path = results_path.joinpath(target_path.name) output_path = results_path.joinpath(target_path.with_suffix('').name + '_inlined.F90') inlined_xml = parser.parse('', inlined_path) inlined_xml = inlined_xml.find('.//subroutine') writer.write_file(ET.tostring(inlined_xml, 'utf-8').decode(), output_inlined_path.with_suffix('.xml')) inlined_syntax = ast_generalizer.generalize(inlined_xml) writer.write_file(typed_astunparse.dump(inlined_syntax), output_inlined_path.with_suffix('.ast.py')) writer.write_file(py_unparser.unparse(inlined_syntax), output_inlined_path.with_suffix('.py')) writer.write_file(f_unparser.unparse(inlined_syntax), output_inlined_path.with_suffix('.f95')) target_code = reader.read_file(target_path) target_xml = parser.parse(target_code, target_path) # import ipdb; ipdb.set_trace() target_xml = target_xml.findall('.//call')[index] writer.write_file(ET.tostring(target_xml, 'utf-8').decode(), output_target_path.with_suffix('.xml')) target_syntax = ast_generalizer.generalize(target_xml) writer.write_file(typed_astunparse.dump(target_syntax), output_target_path.with_suffix('.ast.py')) writer.write_file(py_unparser.unparse(target_syntax), output_target_path.with_suffix('.py')) writer.write_file(f_unparser.unparse(target_syntax), output_target_path.with_suffix('.f95')) mock_function = typed_ast3.FunctionDef( 'f', typed_ast3.arguments([], None, [], None, [], []), [typed_ast3.Expr(target_syntax)], [], None, None) output_syntax = inline_syntax(mock_function, inlined_syntax, globals_=globals()) output_syntax = st.augment(typed_ast3.Module(output_syntax.body, []), eval_=False) writer.write_file(typed_astunparse.dump(output_syntax), output_path.with_suffix('.ast.py')) writer.write_file(py_unparser.unparse(output_syntax), output_path.with_suffix('.py')) output_code = f_unparser.unparse(output_syntax) writer.write_file(output_code, output_path.with_suffix('.f95')) _LOG.warning('[%s %s] <- %i', target_xml.attrib['line_begin'], target_xml.attrib['line_end'], len(output_code)) total_code = replace_scope( target_code, int(target_xml.attrib['line_begin']), int(target_xml.attrib['line_end']) + extra_lines, output_code) writer.write_file(total_code, output_path)
def visit_While(self, node: ast3.While) -> VisitorOutput: """Transforms an if statement into what Pytropos understands: For example, it converts:: while question: body into:: if_qstn = TRANSFORMED(question) def while_qst(st): return question def while_(st): body return st st = pt.runWhile(st, while_qstn, while_) """ if node.orelse: raise AstTransformerError( f"Pytropos doesn't support else statement in while loop yet, sorry :(" ) self.generic_visit(node) new_body = node.body.copy() new_body.append( ast3.Return(value=ast3.Name(id='st', ctx=ast3.Load()), )) new_node = [ ast3.FunctionDef( name='while_qst', args=ast3.arguments(args=[ast3.arg(arg='st', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ast3.Return(value=node.test)], decorator_list=[], returns=None, ), ast3.FunctionDef( name='while_', args=ast3.arguments(args=[ast3.arg(arg='st', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=new_body, decorator_list=[], returns=None, ), ast3.Assign(targets=[ast3.Name(id='st', ctx=ast3.Store())], value=ast3.Call( func=ast3.Attribute( value=ast3.Name(id='pt', ctx=ast3.Load()), attr='runWhile', ctx=ast3.Load(), ), args=[ ast3.Name(id='st', ctx=ast3.Load()), ast3.Name(id='while_qst', ctx=ast3.Load()), ast3.Name(id='while_', ctx=ast3.Load()) ], keywords=[], )) ] return new_node # type: ignore
def visit_If(self, node: ast3.If) -> VisitorOutput: """Transforms an if statement into what Pytropos understands: For example, it converts:: if question: body1 else: body2 into:: if_qstn = TRANSFORMED(question) def if_(st): body1 return st def else_(st): body2 return st st = pt.runIf(st, if_qstn, if_, else_) """ self.generic_visit(node) new_body = node.body.copy() new_orelse = node.orelse.copy() orelse = bool(node.orelse) new_body.append( ast3.Return(value=ast3.Name(id='st', ctx=ast3.Load()), )) new_node = [ ast3.Assign(targets=[ast3.Name(id='if_qstn', ctx=ast3.Store())], value=node.test), ast3.FunctionDef( name='if_', args=ast3.arguments(args=[ast3.arg(arg='st', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=new_body, decorator_list=[], returns=None, ), ] if orelse: # adding "return st" new_orelse.append( ast3.Return(value=ast3.Name(id='st', ctx=ast3.Load()), )) new_node.append( ast3.FunctionDef( name='else_', args=ast3.arguments( args=[ast3.arg(arg='st', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=new_orelse, decorator_list=[], returns=None, )) new_node.append( ast3.Assign(targets=[ast3.Name(id='st', ctx=ast3.Store())], value=ast3.Call( func=ast3.Attribute( value=ast3.Name(id='pt', ctx=ast3.Load()), attr='runIf', ctx=ast3.Load(), ), args=[ ast3.Name(id='st', ctx=ast3.Load()), ast3.Name(id='if_qstn', ctx=ast3.Load()), ast3.Name(id='if_', ctx=ast3.Load()), ast3.Name(id='else_', ctx=ast3.Load()) ] if orelse else [ ast3.Name(id='st', ctx=ast3.Load()), ast3.Name(id='if_qstn', ctx=ast3.Load()), ast3.Name(id='if_', ctx=ast3.Load()) ], keywords=[], ))) return new_node # type: ignore
def derived_resources_class(project: Project) -> str: # TODO temporary and ugly solution of circular import import arcor2.resources from arcor2.resources import ResourcesBase tree = Module(body=[]) parameters = [(act.id, clean(act.name)) for aps in project.action_points for act in aps.actions] add_import(tree, arcor2.resources.__name__, ResourcesBase.__name__) derived_cls_name = "Resources" init_body: List = [ Expr(value=Call(func=Attribute(value=Call( func=Name(id='super', ctx=Load()), args=[ Name(id=derived_cls_name, ctx=Load()), Name(id='self', ctx=Load()) ], keywords=[]), attr='__init__', ctx=Load()), args=[Str(s=project.id)], keywords=[])) ] for a_id, a_name in parameters: init_body.append( Assign(targets=[get_name_attr("self", "_" + a_name, Store)], value=Call(func=get_name_attr("self", "parameters"), args=[Str(s=a_id)], keywords=[]))) cls_def = ClassDef( name=derived_cls_name, bases=[Name(id=ResourcesBase.__name__, ctx=Load())], keywords=[], body=[ FunctionDef(name='__init__', args=arguments(args=[arg(arg='self', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=init_body, decorator_list=[], returns=None) ], decorator_list=[]) tree.body.append(cls_def) for a_id, a_name in parameters: cls_def.body.append( FunctionDef( name=a_name, args=arguments( args=[arg(arg='self', annotation=None, type_comment=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Expr(value=Call(func=Attribute(value=Name(id='self', ctx=Load()), attr='print_info', ctx=Load()), args=[ Str(s=a_id, kind=''), get_name_attr('self', '_' + a_name) ], keywords=[])), Return(value=get_name_attr('self', '_' + a_name)) ], decorator_list=[Name(id='property', ctx=Load())], returns=None, type_comment=None)) return tree_to_str(tree)
def global_actions_class(project: Project) -> str: tree = Module(body=[]) tree.body.append( ImportFrom(module='resources', names=[alias(name='Resources', asname=None)], level=0)) cls_def = ClassDef(name='Actions', bases=[], keywords=[], body=[ FunctionDef(name='__init__', args=arguments(args=[ arg(arg='self', annotation=None, type_comment=None), arg(arg='res', annotation=Name(id='Resources', ctx=Load()), type_comment=None) ], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Assign(targets=[ Attribute(value=Name( id='self', ctx=Load()), attr='_res', ctx=Store()) ], value=Name(id='res', ctx=Load()), type_comment=None) ], decorator_list=[], returns=None, type_comment=None) ], decorator_list=[]) for ap in project.action_points: for action in ap.actions: ac_obj, ac_type = action.parse_type() m = FunctionDef( name=clean(action.name), args=arguments( args=[arg(arg='self', annotation=None, type_comment=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Expr(value=Call(func=Attribute(value=Subscript( value=Attribute(value=Attribute(value=Name(id='self', ctx=Load()), attr='_res', ctx=Load()), attr='all_instances', ctx=Load()), slice=Index(value=Str(s=ac_obj, kind='')), ctx=Load()), attr=ac_type, ctx=Load()), args=[ Attribute(value=Attribute(value=Name( id='self', ctx=Load()), attr='_res', ctx=Load()), attr=clean(action.name), ctx=Load()) ], keywords=[])) ], decorator_list=[], returns=None, type_comment=None) cls_def.body.append(m) tree.body.append(cls_def) return tree_to_str(tree)
def global_action_points_class(project: Project) -> str: tree = Module(body=[]) tree.body.append( ImportFrom(module=arcor2.data.common.__name__, names=[alias(name=ActionPoint.__name__, asname=None)], level=0)) tree.body.append( ImportFrom(module='resources', names=[alias(name='Resources', asname=None)], level=0)) cls_def = ClassDef(name='ActionPoints', bases=[], keywords=[], body=[ FunctionDef(name='__init__', args=arguments(args=[ arg(arg='self', annotation=None, type_comment=None), arg(arg='res', annotation=Name(id='Resources', ctx=Load()), type_comment=None) ], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Assign(targets=[ Attribute(value=Name( id='self', ctx=Load()), attr='_res', ctx=Store()) ], value=Name(id='res', ctx=Load()), type_comment=None) ], decorator_list=[], returns=None, type_comment=None) ], decorator_list=[]) for ap in project.action_points: fd = FunctionDef( name=clean(ap.name), # TODO avoid possible collisions args=arguments( args=[arg(arg='self', annotation=None, type_comment=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[ Return(value=Call(func=Attribute(value=Attribute( value=Attribute(value=Name(id='self', ctx=Load()), attr='_res', ctx=Load()), attr='project', ctx=Load()), attr='action_point', ctx=Load()), args=[Str(s=ap.id, kind='')], keywords=[])) ], decorator_list=[Name(id='property', ctx=Load())], returns=Name(id='ActionPoint', ctx=Load()), type_comment=None) cls_def.body.append(fd) tree.body.append(cls_def) return tree_to_str(tree)
def empty_script_tree(add_main_loop: bool = True) -> Module: """ Creates barebones of the script (empty 'main' function). Returns ------- """ main_body: List[stmt] = [] if add_main_loop: main_body.append( While(test=NameConstant(value=True), body=[Pass()], orelse=[])) else: """ put there "pass" in order to make code valid even if there is no other statement (e.g. no object from resources) """ main_body.append(Pass()) # TODO helper function for try ... except tree = Module(body=[ FunctionDef(name='main', args=arguments(args=[ arg(arg='res', annotation=Name(id='Resources', ctx=Load()), type_comment=None) ], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=main_body, decorator_list=[], returns=NameConstant(value=None), type_comment=None), If(test=Compare(left=Name(id='__name__', ctx=Load()), ops=[Eq()], comparators=[Str(s='__main__', kind='')]), body=[ Try(body=[ With(items=[ withitem(context_expr=Call(func=Name(id='Resources', ctx=Load()), args=[], keywords=[]), optional_vars=Name(id='res', ctx=Store())) ], body=[ Expr(value=Call(func=Name(id='main', ctx=Load()), args=[Name(id='res', ctx=Load())], keywords=[])) ], type_comment=None) ], handlers=[ ExceptHandler( type=Name(id='Exception', ctx=Load()), name='e', body=[ Expr(value=Call(func=Name(id='print_exception', ctx=Load()), args=[Name(id='e', ctx=Load())], keywords=[])) ]) ], orelse=[], finalbody=[]) ], orelse=[]) ], type_ignores=[]) add_import(tree, "arcor2.helpers", "print_exception") add_import(tree, "resources", "Resources", try_to_import=False) return tree