def visit_FunctionDef(self, node): self.fname = node.name tmp = self.prepare_functiondef_context(node) operator_body, formal_types, formal_args = tmp tmp = self.prepare_types(node) dflt_argv, dflt_argt, result_type, callable_type, pure_type = tmp # a function has a call operator to be called # and a default constructor to create instances fscope = "type{0}::".format( "<{0}>".format(", ".join(formal_types)) if formal_types else "") ffscope = "{0}::{1}".format(node.name, fscope) operator_declaration = [ templatize( make_const_function_declaration( self, node, "typename {0}result_type".format(fscope), "operator()", formal_types, formal_args, dflt_argv), formal_types, dflt_argt), EmptyStatement() ] operator_signature = make_const_function_declaration( self, node, "typename {0}result_type".format(ffscope), "{0}::operator()".format(node.name), formal_types, formal_args) ctx = CachedTypeVisitor(self.lctx) operator_local_declarations = ([ Statement("{0} {1}".format( self.types[self.local_names[k]].generate(ctx), k)) for k in self.ldecls ]) dependent_typedefs = ctx.typedefs() operator_definition = FunctionBody( templatize(operator_signature, formal_types), Block(dependent_typedefs + operator_local_declarations + operator_body)) ctx = CachedTypeVisitor() extra_typedefs = ([ Typedef(Value(t.generate(ctx), t.name)) for t in self.types[node][1] ] + [Typedef(Value(result_type.generate(ctx), "result_type"))]) extra_typedefs = ctx.typedefs() + extra_typedefs return_declaration = [ templatize(Struct("type", extra_typedefs), formal_types, dflt_argt) ] topstruct = Struct(node.name, [callable_type, pure_type] + return_declaration + operator_declaration) return [topstruct], [operator_definition]
def visit_FunctionDef(self, node): tmp = self.prepare_functiondef_context(node) operator_body, formal_types, formal_args = tmp tmp = self.prepare_types(node) dflt_argv, dflt_argt, result_type, callable_type, pure_type = tmp # a generator has a call operator that returns the iterator next_name = "__generator__{0}".format(node.name) instanciated_next_name = "{0}{1}".format( next_name, "<{0}>".format(", ".join(formal_types)) if formal_types else "") operator_body.append( Statement("{}: return result_type()".format( CxxGenerator.FinalStatement))) next_declaration = [ FunctionDeclaration(Value("result_type", "next"), []), EmptyStatement() ] # empty statement to force a comma ... # the constructors next_constructors = [ FunctionBody(FunctionDeclaration(Value("", next_name), []), Line(': pythonic::yielder() {}')) ] if formal_types: # If all parameters have a default value, we don't need default # constructor if dflt_argv and all(dflt_argv): next_constructors = list() next_constructors.append( FunctionBody( make_function_declaration(self, node, "", next_name, formal_types, formal_args, dflt_argv), Line(": {0} {{ }}".format(", ".join( ["pythonic::yielder()"] + ["{0}({0})".format(arg) for arg in formal_args]))))) next_iterator = [ FunctionBody(FunctionDeclaration(Value("void", "operator++"), []), Block([Statement("next()")])), FunctionBody( FunctionDeclaration( Value( "typename {0}::result_type".format( instanciated_next_name), "operator*"), [], "const"), Block([ReturnStatement(CxxGenerator.StateValue)])), FunctionBody( FunctionDeclaration( Value( "pythonic::types::generator_iterator<{0}>".format( next_name), "begin"), []), Block([ Statement("next()"), ReturnStatement("pythonic::types::generator_iterator<{0}>" "(*this)".format(next_name)) ])), FunctionBody( FunctionDeclaration( Value( "pythonic::types::generator_iterator<{0}>".format( next_name), "end"), []), Block([ ReturnStatement( "pythonic::types::generator_iterator<{0}>()".format( next_name)) ])) ] next_signature = templatize( FunctionDeclaration( Value( "typename {0}::result_type".format(instanciated_next_name), "{0}::next".format(instanciated_next_name)), []), formal_types) next_body = operator_body # the dispatch table at the entry point next_body.insert( 0, Statement("switch({0}) {{ {1} }}".format( CxxGenerator.StateHolder, " ".join("case {0}: goto {1};".format(num, where) for (num, where) in sorted(self.yields.values(), key=lambda x: x[0]))))) ctx = CachedTypeVisitor(self.lctx) next_members = ([ Statement("{0} {1}".format(ft, fa)) for (ft, fa) in zip(formal_types, formal_args) ] + [ Statement("{0} {1}".format( self.types[self.local_names[k]].generate(ctx), k)) for k in self.ldecls ] + [ Statement("{0} {1}".format(v, k)) for k, v in self.extra_declarations ] + [ Statement("typename {0}::result_type {1}".format( instanciated_next_name, CxxGenerator.StateValue)) ]) extern_typedefs = [ Typedef(Value(t.generate(ctx), t.name)) for t in self.types[node][1] ] iterator_typedef = [ Typedef( Value( "pythonic::types::generator_iterator<{0}>".format( "{0}<{1}>".format(next_name, ", ".join(formal_types) ) if formal_types else next_name), "iterator")), Typedef(Value(result_type.generate(ctx), "value_type")) ] result_typedef = [ Typedef(Value(result_type.generate(ctx), "result_type")) ] extra_typedefs = (ctx.typedefs() + extern_typedefs + iterator_typedef + result_typedef) next_struct = templatize( Struct( next_name, extra_typedefs + next_members + next_constructors + next_iterator + next_declaration, "pythonic::yielder"), formal_types) next_definition = FunctionBody(next_signature, Block(next_body)) operator_declaration = [ templatize( make_const_function_declaration(self, node, instanciated_next_name, "operator()", formal_types, formal_args, dflt_argv), formal_types, dflt_argt), EmptyStatement() ] operator_signature = make_const_function_declaration( self, node, instanciated_next_name, "{0}::operator()".format(node.name), formal_types, formal_args) operator_definition = FunctionBody( templatize(operator_signature, formal_types), Block([ ReturnStatement("{0}({1})".format(instanciated_next_name, ", ".join(formal_args))) ])) topstruct_type = templatize(Struct("type", extra_typedefs), formal_types) topstruct = Struct(node.name, [topstruct_type, callable_type, pure_type] + operator_declaration) return [next_struct, topstruct], [next_definition, operator_definition]
def visit_FunctionDef(self, node): class CachedTypeVisitor: class CachedType: def __init__(self, s): self.s = s def generate(self, _): return self.s def __init__(self, other=None): if other: self.cache = other.cache.copy() self.rcache = other.rcache.copy() self.mapping = other.mapping.copy() else: self.cache = dict() self.rcache = dict() self.mapping = dict() def __call__(self, node): if node not in self.mapping: t = node.generate(self) if t in self.rcache: self.mapping[node] = self.mapping[self.rcache[t]] self.cache[node] = self.cache[self.rcache[t]] else: self.rcache[t] = node self.mapping[node] = len(self.mapping) self.cache[node] = t return CachedTypeVisitor.CachedType("__type{0}".format( self.mapping[node])) def typedefs(self): l = sorted(self.mapping.items(), key=lambda x: x[1]) L = list() visited = set() # the same value must not be typedefed twice for k, v in l: if v not in visited: typename = "__type" + str(v) L.append(Typedef(Value(self.cache[k], typename))) visited.add(v) return L self.fname = node.name # prepare context and visit function body fargs = node.args.args formal_args = [arg.id for arg in fargs] formal_types = ["argument_type" + str(i) for i in range(len(fargs))] self.ldecls = set(self.passmanager.gather(LocalNodeDeclarations, node)) self.local_names = {sym.id: sym for sym in self.ldecls} self.local_names.update({arg.id: arg for arg in fargs}) self.extra_declarations = [] self.lctx = CachedTypeVisitor() # choose one node among all the ones with the same name for each name self.ldecls = set({n.id: n for n in self.ldecls}.values()) # 0 is used as initial_state, thus the +1 self.yields = { k: (1 + v, "yield_point{0}".format(1 + v)) for (v, k) in enumerate(self.passmanager.gather(YieldPoints, node)) } # gather body dump operator_body = [self.visit(stmt) for stmt in node.body] # compute arg dump default_arg_values = ([None] * (len(node.args.args) - len(node.args.defaults)) + [self.visit(n) for n in node.args.defaults]) default_arg_types = ([None] * (len(node.args.args) - len(node.args.defaults)) + [self.types[n] for n in node.args.defaults]) # compute type dump result_type = self.types[node][0] callable_type = Typedef(Value("void", "callable")) pure_type = (Typedef(Value("void", "pure")) if node in self.pure_expressions else EmptyStatement()) def make_function_declaration(rtype, name, ftypes, fargs, defaults=None, attributes=None): if defaults is None: defaults = [None] * len(ftypes) if attributes is None: attributes = [] arguments = list() for i, (t, a, d) in enumerate(zip(ftypes, fargs, defaults)): if self.yields: rvalue_ref = "" elif self.argument_effects[node][i]: rvalue_ref = "&&" else: rvalue_ref = " const &" argument = Value( t + rvalue_ref, "{0}{1}".format(a, "= {0}".format(d) if d else "")) arguments.append(argument) return FunctionDeclaration(Value(rtype, name), arguments, *attributes) def make_const_function_declaration(rtype, name, ftypes, fargs, defaults=None): return make_function_declaration(rtype, name, ftypes, fargs, defaults, ["const"]) if self.yields: # generator case # a generator has a call operator that returns the iterator next_name = "__generator__{0}".format(node.name) instanciated_next_name = "{0}{1}".format( next_name, "<{0}>".format(", ".join(formal_types)) if formal_types else "") operator_body.append( Statement("{0}: return result_type();".format( Cxx.final_statement))) next_declaration = [ FunctionDeclaration(Value("result_type", "next"), []), EmptyStatement() ] # empty statement to force a comma ... # the constructors next_constructors = [ FunctionBody(FunctionDeclaration(Value("", next_name), []), Line(': pythonic::yielder() {}')) ] if formal_types: # If all parameters have a default value, we don't need default # constructor if default_arg_values and all(default_arg_values): next_constructors = list() next_constructors.append( FunctionBody( make_function_declaration("", next_name, formal_types, formal_args, default_arg_values), Line(": {0} {{ }}".format(", ".join( ["pythonic::yielder()"] + ["{0}({0})".format(arg) for arg in formal_args]))))) next_iterator = [ FunctionBody( FunctionDeclaration(Value("void", "operator++"), []), Block([Statement("next()")])), FunctionBody( FunctionDeclaration( Value( "typename {0}::result_type".format( instanciated_next_name), "operator*"), [], "const"), Block([ReturnStatement(Cxx.generator_state_value)])), FunctionBody( FunctionDeclaration( Value( "pythonic::types::generator_iterator<{0}>".format( next_name), "begin"), []), Block([ Statement("next()"), ReturnStatement( "pythonic::types::generator_iterator<{0}>" "(*this)".format(next_name)) ])), FunctionBody( FunctionDeclaration( Value( "pythonic::types::generator_iterator<{0}>".format( next_name), "end"), []), Block([ ReturnStatement( "pythonic::types::generator_iterator<{0}>()". format(next_name)) ])) ] next_signature = templatize( FunctionDeclaration( Value( "typename {0}::result_type".format( instanciated_next_name), "{0}::next".format(instanciated_next_name)), []), formal_types) next_body = operator_body # the dispatch table at the entry point next_body.insert( 0, Statement("switch({0}) {{ {1} }}".format( Cxx.generator_state_holder, " ".join("case {0}: goto {1};".format(num, where) for (num, where) in sorted(self.yields.values(), key=lambda x: x[0]))))) ctx = CachedTypeVisitor(self.lctx) next_members = ([ Statement("{0} {1}".format(ft, fa)) for (ft, fa) in zip(formal_types, formal_args) ] + [ Statement("{0} {1}".format(self.types[k].generate(ctx), k.id)) for k in self.ldecls ] + [ Statement("{0} {1}".format(v, k)) for k, v in self.extra_declarations ] + [ Statement("typename {0}::result_type {1}".format( instanciated_next_name, Cxx.generator_state_value)) ]) extern_typedefs = [ Typedef(Value(t.generate(ctx), t.name)) for t in self.types[node][1] if not t.isweak() ] iterator_typedef = [ Typedef( Value( "pythonic::types::generator_iterator<{0}>".format( "{0}<{1}>".format(next_name, ", ".join( formal_types)) if formal_types else next_name), "iterator")), Typedef(Value(result_type.generate(ctx), "value_type")) ] result_typedef = [ Typedef(Value(result_type.generate(ctx), "result_type")) ] extra_typedefs = (ctx.typedefs() + extern_typedefs + iterator_typedef + result_typedef) next_struct = templatize( Struct( next_name, extra_typedefs + next_members + next_constructors + next_iterator + next_declaration, "pythonic::yielder"), formal_types) next_definition = FunctionBody(next_signature, Block(next_body)) operator_declaration = [ templatize( make_const_function_declaration(instanciated_next_name, "operator()", formal_types, formal_args, default_arg_values), formal_types, default_arg_types), EmptyStatement() ] operator_signature = make_const_function_declaration( instanciated_next_name, "{0}::operator()".format(node.name), formal_types, formal_args) operator_definition = FunctionBody( templatize(operator_signature, formal_types), Block([ ReturnStatement("{0}({1})".format(instanciated_next_name, ", ".join(formal_args))) ])) topstruct_type = templatize(Struct("type", extra_typedefs), formal_types) topstruct = Struct(node.name, [topstruct_type, callable_type, pure_type] + operator_declaration) self.declarations.append(next_struct) self.definitions.append(next_definition) else: # regular function case # a function has a call operator to be called # and a default constructor to create instances fscope = "type{0}::".format("<{0}>".format(", ".join(formal_types)) if formal_types else "") ffscope = "{0}::{1}".format(node.name, fscope) operator_declaration = [ templatize( make_const_function_declaration( "typename {0}result_type".format(fscope), "operator()", formal_types, formal_args, default_arg_values), formal_types, default_arg_types), EmptyStatement() ] operator_signature = make_const_function_declaration( "typename {0}result_type".format(ffscope), "{0}::operator()".format(node.name), formal_types, formal_args) ctx = CachedTypeVisitor(self.lctx) operator_local_declarations = ([ Statement("{0} {1}".format(self.types[k].generate(ctx), k.id)) for k in self.ldecls ] + [ Statement("{0} {1}".format(v, k)) for k, v in self.extra_declarations ]) dependent_typedefs = ctx.typedefs() operator_definition = FunctionBody( templatize(operator_signature, formal_types), Block(dependent_typedefs + operator_local_declarations + operator_body)) ctx = CachedTypeVisitor() extra_typedefs = ([ Typedef(Value(t.generate(ctx), t.name)) for t in self.types[node][1] if not t.isweak() ] + [Typedef(Value(result_type.generate(ctx), "result_type"))]) extra_typedefs = ctx.typedefs() + extra_typedefs return_declaration = [ templatize(Struct("type", extra_typedefs), formal_types, default_arg_types) ] topstruct = Struct(node.name, [callable_type, pure_type] + return_declaration + operator_declaration) self.declarations.append(topstruct) self.definitions.append(operator_definition) return EmptyStatement()