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_FuncDef(self, node) -> typed_ast3.FunctionDef: # pylint: disable=invalid-name """Transform FuncDef.""" assert node.decl is not None name, args, return_type = self.visit(node.decl) param_decls = self.visit(node.param_decls) if param_decls is not None: raise NotImplementedError(_node_debug(node.param_decls), str(param_decls)) body = self.visit(node.body) assert isinstance(body, list) and body _ = self.visit(node.coord) funcdef = typed_ast3.FunctionDef(name=name, args=args, body=fix_stmts_in_body(body), decorator_list=[], returns=return_type) return funcdef
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 _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 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