class CppBuilder(object): def __init__(self): self.writer = CppWriter() self.id_counter = 100 self.declaration_keys = [] self.autonames = [] def get_autoname(self, key, prefix): for k, name in self.autonames: if key == k: return name name = self.new_id(prefix) self.autonames.append((key, name)) return name def build_print_all(self, iterator): self.write_header() iterator.declare(self) self.main_begin() variable = iterator.make_iterator(self) element = self.make_element(iterator.output_type.basic_type) self.writer.line("while ({}.next({}))", variable, element) self.writer.block_begin() self.writer.line("std::cout << {} << std::endl;", element) self.writer.block_end() self.main_end() def build_collect(self, iterator): self.write_header() iterator.declare(self) self.main_begin() variable = iterator.make_iterator(self) element = self.make_element(iterator.output_type.basic_type) self.init_fifo() self.writer.line("while ({}.next({}))", variable, element) self.writer.block_begin() self.writer.line("qit::write(output, {});", element) self.writer.block_end() self.main_end() def init_fifo(self): self.writer.line("assert(argc > 1);") self.writer.line("FILE *output = fopen(argv[1], \"w\");") def write_header(self): self.writer.line("/*") self.writer.line(" QIT generated file") self.writer.line("*/") self.writer.emptyline() self.writer.line("#include <assert.h>") self.writer.line("#include <iostream>") self.writer.line("#include <qit.h>") self.writer.line("#include <stdlib.h>") self.writer.line("#include <time.h>") self.writer.emptyline() def main_begin(self): self.writer.line("int main(int argc, char **argv)") self.writer.block_begin() self.writer.line("srand(time(NULL));") def main_end(self): self.writer.line("return 0;") self.writer.block_end(); def new_id(self, prefix="v"): self.id_counter += 1 return "{}{}".format(prefix, self.id_counter) def make_element(self, basic_type): variable = self.new_id() self.writer.line("{} {};", basic_type.get_element_type(self), variable) return variable ## Method for multiple dispatch of base classes def get_generator_iterator(self, transformation): return "qit::GeneratorIterator<{} >" \ .format(transformation.generator.get_generator_type(self)) def make_basic_iterator(self, iterator, iterators=(), args=()): return self.make_iterator(iterator, tuple(c.make_iterator(self) for c in iterators) + args) def make_iterator(self, iterator, args): variable = self.new_id("i") self.writer.line("{} {}({});", iterator.get_iterator_type(self), variable, ",".join(args)) return variable def make_basic_generator(self, iterator, iterators=(), args=()): return self.make_generator(iterator, tuple(c.make_generator(self) for c in iterators) + args) def make_generator(self, iterator, args): variable = self.new_id("g"); self.writer.line("{} {}({});", iterator.get_generator_type(self), variable, ",".join(args)) return variable def check_declaration_key(self, key): if key in self.declaration_keys: return True self.declaration_keys.append(key) self.writer.line("/* Declaration: {} */", key) return False # Int def get_int_type(self): return "int" # Range def get_range_iterator(self): return "qit::RangeIterator" def get_range_generator(self): return "qit::RangeGenerator" # Take def get_take_iterator(self, take): return "qit::TakeIterator<{} >" \ .format(take.parent_iterator.get_iterator_type(self)) # Map def get_map_iterator(self, map): return "qit::MapIterator<{}, {}, {} >" \ .format(map.parent_iterator.get_iterator_type(self), map.function.return_type.get_element_type(self), map.function.name) # Product def get_product_type(self, product): if product.basic_type.name is None: return self.get_autoname(product.basic_type, "Product") else: return product.name def get_product_iterator(self, iterator): type_name = self.get_product_type(iterator.output_type) return self.get_autoname(iterator, type_name + "Iterator") def get_product_generator(self, generator): type_name = self.get_product_type(generator.output_type) return self.get_autoname(generator, type_name + "Generator") def declare_product_class(self, product): if self.check_declaration_key((product, "class")): return product_type = self.get_product_type(product) self.writer.class_begin(product_type) self.writer.line("public:") ## Constructor for name, t in zip(product.names, product.types): self.writer.line("{} {};", t.basic_type.get_element_type(self), name) # Write self.writer.line("void write(FILE *f)") self.writer.block_begin() for name in product.names: self.writer.line("qit::write(f, {});", name) self.writer.block_end() self.writer.class_end() ## Stream self.writer.line("std::ostream& operator<<(std::ostream& os, const {}& v)", product_type) self.writer.block_begin() self.writer.line("os << \"{{\";") for i, name in enumerate(product.names): if i != 0: self.writer.line("os << \",\";") self.writer.line("os << v.{};", name) self.writer.line("return os << \"}}\";") self.writer.block_end() def declare_product_iterator(self, iterator): if self.check_declaration_key((iterator, "iterator")): return product = iterator.output_type iterator_type = iterator.get_iterator_type(self) element_type = product.get_element_type(self) self.writer.class_begin(iterator_type) self.writer.line("public:") self.writer.line("typedef {} value_type;", element_type) names_iterators = list(zip(product.names, iterator.iterators)) # Attributes for name, i in names_iterators: self.writer.line("{} {};", i.get_iterator_type(self), name) self.writer.line("bool _inited;") # Contructor args = [ "{} &{}".format(i.get_iterator_type(self), name) for name, i in names_iterators ] constructors = [ "{0}({0})".format(name) for name in product.names ] constructors.append("_inited(false)") self.writer.line("{}({}) {} {}", iterator_type, ",".join(args), ":" if constructors else "", ",".join(constructors)) self.writer.block_begin() self.writer.block_end() # Next self.writer.line("bool next({} &v)", element_type) self.writer.block_begin() self.writer.if_begin("_inited") for i, name in enumerate(product.names): self.writer.if_begin("{0}.next(v.{0})", name) self.writer.line("return true;") self.writer.block_end() if i != len(product.names) - 1: self.writer.line("{}.reset();", name) self.writer.line("{0}.next(v.{0});", name) self.writer.line("return false;") self.writer.else_begin() for name in product.names: self.writer.if_begin("!{0}.next(v.{0})", name) self.writer.line("return false;") self.writer.block_end() self.writer.line("_inited = true;") self.writer.line("return true;") self.writer.block_end() self.writer.block_end() # Reset self.writer.line("void reset()") self.writer.block_begin() self.writer.line("_inited = false;") for name in product.names: self.writer.line("{}.reset();", name) self.writer.block_end() self.writer.class_end() def declare_product_generator(self, generator): if self.check_declaration_key((generator, "generator")): return product = generator.output_type generator_type = generator.get_generator_type(self) element_type = product.get_element_type(self) self.writer.class_begin(generator_type) self.writer.line("public:") self.writer.line("typedef {} value_type;", element_type) # Attributes names_generators = list(zip(product.names, generator.generators)) for name, generator in names_generators: self.writer.line("{} {};", generator.get_generator_type(self), name) # Contructor args = [ "{} &{}".format(generator.get_generator_type(self), name) for name, generator in names_generators ] constructors = [ "{0}({0})".format(name) for name in product.names ] self.writer.line("{}({}) {} {}", generator_type, ",".join(args), ":" if constructors else "", ",".join(constructors)) self.writer.block_begin() self.writer.block_end() # Next self.writer.line("void generate({} &v)", element_type) self.writer.block_begin() for name in product.names: self.writer.line("{0}.generate(v.{0});", name) self.writer.block_end() self.writer.class_end() # Sequences def get_sequence_iterator(self, iterator): return "qit::SequenceIterator<{} >".format( iterator.element_iterator.get_iterator_type(self)) def get_sequence_generator(self, iterator): return "qit::SequenceGenerator<{} >".format( iterator.element_generator.get_generator_type(self)) def get_sequence_type(self, sequence): return "std::vector<{} >".format( sequence.element_type.get_element_type(self)) # Function def declare_function(self, function): self.writer.class_begin(function.name) self.writer.line("public:") params = [ "const {} &{}".format(c.get_element_type(self), name) for c, name in function.params ] self.writer.line("{} operator()({})", function.return_type.get_element_type(self), ",".join(params)) self.writer.block_begin() self.writer.text(function.inline_code) self.writer.block_end() self.writer.class_end()
class CppBuilder(object): def __init__(self, env): self.env = env self.writer = CppWriter() self.declaration_keys = [] self.names = {} self.ids = set() self.included_filenames = set() def get_name(self, obj): name = self.names.get(obj) if name is not None: return name obj_name = obj.name name = self.new_id(obj_name) self.names[obj] = name return name def include_filename(self, filename): if filename in self.included_filenames: return self.included_filenames.add(filename) self.writer.line("#include \"{}\"", filename) def get_used_variables(self, exprs, args): variables = frozenset() for expr in exprs: variables = variables.union(expr.get_variables()) prev = frozenset() while prev != variables: prev = variables for v in variables: a = args.get(v) if a is None: raise QitException("Unbound variable '{}'".format(v)) variables = variables.union(a.get_variables()) return variables def build_collect(self, exprs, args): variables = self.get_used_variables(exprs, args) validate_variables(variables) deps = { v: args[v].get_variables() for v in variables } variables = sort_by_deps(deps) write_functions = [ expr.type.write_function for expr in exprs ] self.write_header() for v in variables: args[v].declare_all(self) for expr in exprs: expr.declare_all(self) for f in write_functions: f.declare_all(self) self.main_begin() self.init_fifo() self.init_variables(variables, args) for expr, f in zip(exprs, write_functions): self.writer.line( "{}(output, {});", f.build(self), expr.build(self)) self.writer.line("fclose(output);") self.main_end() def write_expression_into_variable(self, expr): variable = self.new_id() self.writer.line("{} {} = {};", expr.type.build(self), variable, expr.build(self)) return variable def build_object(self, type, args): args = ",".join(a.build(self) for a in args) return "{}({})".format(type.build(self), args) def write_iterator_write_method(self): self.writer.line("QIT_ITERATOR_WRITE_METHOD") def make_sequence_from_iterator(self, iterator): result_variable = self.new_id("result") self.writer.line("{} {};", iterator.output_type.build(self), result_variable) iterator_variable = iterator.make_iterator(self) element = self.make_element(iterator.output_type.basic_type) self.writer.line("while ({}.next({}))", iterator_variable, element) self.writer.block_begin() self.writer.line("{}.push_back({});", result_variable, element) self.writer.block_end() return result_variable def make_element_from_iterator(self, iterator): iterator_variable = iterator.make_iterator(self) element = self.make_element(iterator.output_type.basic_type) self.writer.line("assert({}.next({}));", iterator_variable, element) return element def init_fifo(self): self.writer.line("assert(argc > 1);") self.writer.line("FILE *output = fopen(argv[1], \"w\");") def init_variables(self, variables, args): for variable in variables: value = args[variable] self.writer.line("{} {}({});", variable.type.build(self), variable.build(self), value.build(self)) def write_header(self): self.writer.line("/*") self.writer.line(" QIT generated file") self.writer.line("*/") self.writer.emptyline() self.writer.line("#include <vector>") self.writer.line("#include <deque>") self.writer.line("#include <set>") self.writer.line("#include <map>") self.writer.line("#include <iostream>") self.writer.line("#include <assert.h>") self.writer.line("#include <stdlib.h>") self.writer.line("#include <time.h>") self.writer.line("#include <functional>") self.writer.line("#include <algorithm>") self.writer.line("#include <random>") self.writer.emptyline() self.writer.line("std::default_random_engine QIT_GENERATOR(time(nullptr));") self.writer.line("typedef int32_t qint;") self.writer.emptyline() self.writer.emptyline() def main_begin(self): self.writer.line("int main(int argc, char **argv)") self.writer.block_begin() self.writer.line("srand(time(NULL));") def main_end(self): self.writer.line("return 0;") self.writer.block_end(); def new_id(self, name): prefix = "q_" + name s = "" while prefix[-1].isdigit(): s += prefix[-1] prefix = str(prefix[:-1]) if s: suffix = int(s) + 1 else: suffix = 1 name = prefix + str(suffix) while name in self.ids: suffix += 1 name = prefix + str(suffix) self.ids.add(name) return name ## Method for multiple dispatch of base classes def check_declaration_key(self, key): if key in self.declaration_keys: return True self.declaration_keys.append(key) self.writer.line("/* Declaration: {} */", key) return False # Struct def declare_struct(self, struct): if self.check_declaration_key(struct): return struct_type = struct.build(self) self.writer.class_begin(struct_type) self.writer.line("public:") ## Attributes for name, t in zip(struct.names, struct.types): self.writer.line("{} {};", t.build(self), name) if struct.names: params = ",".join(t.build_param(self, name) for t, name in zip(struct.types, struct.names)) consts = ": " + ",".join("{0}({0})".format(name) for name in struct.names) self.writer.line("{}({}) {} {{}}", struct_type, params, consts) self.writer.line("{}() {{}}", struct_type) # Operator < self.writer.line("bool operator <(const {} &other) const", struct_type) self.writer.block_begin() for name in struct.names: self.writer.if_begin("{0} < other.{0}", name) self.writer.line("return true;") self.writer.block_end() self.writer.if_begin("{0} == other.{0}", name) for name in struct.names: self.writer.block_end() self.writer.line("return false;") self.writer.block_end() # Operator == self.writer.line("bool operator ==(const {} &other) const", struct_type) self.writer.block_begin() if struct.names: self.writer.line("return {};", " && ".join("({0} == other.{0})".format(name) for name in struct.names)) else: self.writer.line("return true;") self.writer.block_end() self.writer.class_end() # Function def build_function_call(self, function_call): function = self.build_function(function_call.function) args = ",".join(e.build(self) for e in function_call.args) return "{}({})".format(function, args) def build_function(self, function, prefix=""): function_name = self.get_name(function) variables = sorted_variables(function.get_variables()) if variables: v = ",".join(prefix + v.build(self) for v in variables) return "({}({}))".format(function_name, v) else: return "{}".format(function_name) def declare_function(self, function): if self.check_declaration_key(function): return function_name = self.get_name(function) variables = function.get_variables() if function.is_external(): self.include_filename(self.env.get_function_filename(function)) if not variables: decl = function.build_declaration(self, function_name) self.writer.line("{}", decl) self.writer.block_begin() function.write_code(self) self.writer.block_end() self.writer.emptyline() return variables = sorted_variables(variables) self.writer.class_begin(function_name) self.writer.line("public:") variables = sorted_variables(variables) self.writer.line("{}({}) : {} {{}}", function_name, ",".join("const {} &{}".format(v.type.build(self), v.build(self)) for v in variables), ",".join("{0}({0})".format(v.build(self)) for v in variables)) self.writer.line("{}", function.build_declaration(self, "operator()")) self.writer.block_begin() function.write_code(self) self.writer.block_end() for variable in variables: self.writer.line("const {} &{};", variable.type.build(self), variable.build(self)); self.writer.class_end() self.writer.emptyline() def write_return_expression(self, expression): self.writer.line("return {};", expression.build(self)) def write_code(self, inline_code, inline_code_vars): if isinstance(inline_code_vars, dict): inline_code_vars = tuple(inline_code_vars.items()) d = {} for name, obj in inline_code_vars: if name.startswith("_"): d[name] = obj else: d[name] = obj.build(self) template = jinja2.Template(inline_code) template.globals.update(b=lambda obj: obj.build(self)) template.globals["_builder"] = self self.writer.text(template.render(d)) def write_function_external_call(self, function): call = "" if function.return_type is not None: call += "return " call += function.name + "(" call += ", ".join([param.name for param in function.params]) # param names self.writer.line(call + ");") def get_function_declaration(self, function): args = ", ".join(p.type.build_param(self, p.name, p.const) for p in function.params) if function.return_type is not None: return_type = function.return_type.build(self) else: return_type = "void" return "{} {}({})".format(return_type, function.name, args)
class CppBuilder(object): def __init__(self, env): self.env = env self.writer = CppWriter() self.id_counter = 100 self.declaration_keys = [] self.autonames = {} self.included_filenames = set() def get_autoname(self, obj): name = self.autonames.get(obj) if name is not None: return name name = self.new_id(obj.autoname_prefix) self.autonames[obj] = name return name def include_filename(self, filename): if filename in self.included_filenames: return self.included_filenames.add(filename) self.writer.line("#include \"{}\"", filename) def build_collect(self, obj, args): write_function = obj.type.write_function self.write_header() obj.declare_all(self) write_function.declare_all(self) self.main_begin() self.init_fifo() self.init_variables(args) self.writer.line( "{}(output, {});", write_function.build(self), obj.build(self)) self.writer.line("fclose(output);") self.main_end() def write_expression_into_variable(self, expr): variable = self.new_id() self.writer.line("{} {} = {};", expr.type.build(self), variable, expr.build(self)) return variable def build_object(self, type, args): args = ",".join(a.build(self) for a in args) return "{}({})".format(type.build(self), args) def write_iterator_write_method(self): self.writer.line("QIT_ITERATOR_WRITE_METHOD") def make_sequence_from_iterator(self, iterator): result_variable = self.new_id("result") self.writer.line("{} {};", iterator.output_type.build(self), result_variable) iterator_variable = iterator.make_iterator(self) element = self.make_element(iterator.output_type.basic_type) self.writer.line("while ({}.next({}))", iterator_variable, element) self.writer.block_begin() self.writer.line("{}.push_back({});", result_variable, element) self.writer.block_end() return result_variable def make_element_from_iterator(self, iterator): iterator_variable = iterator.make_iterator(self) element = self.make_element(iterator.output_type.basic_type) self.writer.line("assert({}.next({}));", iterator_variable, element) return element def init_fifo(self): self.writer.line("assert(argc > 1);") self.writer.line("FILE *output = fopen(argv[1], \"w\");") def init_variables(self, args): for variable, value in sorted(args.items(), key=lambda v: v[0].name): self.writer.line("{} {}({});", variable.type.build(self), variable.name, value.build(self)) def write_header(self): self.writer.line("/*") self.writer.line(" QIT generated file") self.writer.line("*/") self.writer.emptyline() self.writer.line("#include <vector>") self.writer.line("#include <set>") self.writer.line("#include <map>") self.writer.line("#include <iostream>") self.writer.line("#include <assert.h>") self.writer.line("#include <stdlib.h>") self.writer.line("#include <time.h>") self.writer.line("#include <algorithm>") self.writer.line("#include <random>") self.writer.emptyline() self.writer.line("std::default_random_engine QIT_GENERATOR(time(nullptr));") self.writer.line("typedef int32_t qint;") self.writer.emptyline() self.writer.emptyline() def main_begin(self): self.writer.line("int main(int argc, char **argv)") self.writer.block_begin() self.writer.line("srand(time(NULL));") def main_end(self): self.writer.line("return 0;") self.writer.block_end(); def new_id(self, prefix="v"): self.id_counter += 1 return "{}{}".format(prefix, self.id_counter) ## Method for multiple dispatch of base classes def check_declaration_key(self, key): if key in self.declaration_keys: return True self.declaration_keys.append(key) self.writer.line("/* Declaration: {} */", key) return False # Struct def declare_struct(self, struct): if self.check_declaration_key(struct): return struct_type = struct.build(self) self.writer.class_begin(struct_type) self.writer.line("public:") ## Attributes for name, t in zip(struct.names, struct.types): self.writer.line("{} {};", t.build(self), name) if struct.names: params = ",".join(t.build_param(self, name) for t, name in zip(struct.types, struct.names)) consts = ": " + ",".join("{0}({0})".format(name) for name in struct.names) self.writer.line("{}({}) {} {{}}", struct_type, params, consts) self.writer.line("{}() {{}}", struct_type) # Operator < self.writer.line("bool operator <(const {} &other) const", struct_type) self.writer.block_begin() for name in struct.names: self.writer.if_begin("{0} < other.{0}", name) self.writer.line("return true;") self.writer.block_end() self.writer.if_begin("{0} == other.{0}", name) for name in struct.names: self.writer.block_end() self.writer.line("return false;") self.writer.block_end() # Operator == self.writer.line("bool operator ==(const {} &other) const", struct_type) self.writer.block_begin() if struct.names: self.writer.line("return {};", " && ".join("({0} == other.{0})".format(name) for name in struct.names)) else: self.writer.line("return true;") self.writer.block_end() self.writer.class_end() # Function def build_function_call(self, function_call): functor = self.build_functor(function_call.function) args = ",".join(e.build(self) for e in function_call.args) return "{}({})".format(functor, args) def build_functor(self, function): function_name = self.get_autoname(function) variables = sorted_variables(function.get_variables()) if variables: v = ",".join(v.build(self) for v in variables) return "({}({}))".format(function_name, v) else: return "{}()".format(function_name) def declare_function(self, function): if self.check_declaration_key(function): return if function.is_external(): self.include_filename(self.env.get_function_filename(function)) function_name = self.get_autoname(function) self.writer.class_begin(function_name) self.writer.line("public:") variables = function.get_variables() if variables: variables = sorted_variables(variables) self.writer.line("{}({}) : {} {{}}", function_name, ",".join("const {} &{}".format(v.type.build(self), v.name) for v in variables), ",".join("{0}({0})".format(v.name) for v in variables)) params = [ p.type.build_param(self, p.name, p.const) for p in function.params ] self.writer.line("{} operator()({})", function.return_type.build(self) if function.return_type else "void", ",".join(params)) self.writer.block_begin() function.write_code(self) self.writer.block_end() for variable in variables: self.writer.line("const {} &{};", variable.type.build(self), variable.name); self.writer.class_end() def write_return_expression(self, expression): self.writer.line("return {};", expression.build(self)) def write_function_inline_code(self, inline_code, inline_code_vars): d = {} for name, obj in inline_code_vars: if name.startswith("_"): d[name] = obj else: d[name] = obj.build(self) template = jinja2.Template(inline_code) template.globals.update(b=lambda obj: obj.build(self)) self.writer.text(template.render(d)) def write_function_external_call(self, function): call = "" if function.return_type is not None: call += "return " call += function.name + "(" call += ", ".join([param.name for param in function.params]) # param names self.writer.line(call + ");") def get_function_declaration(self, function): args = ", ".join(p.type.build_param(self, p.name, p.const) for p in function.params) if function.return_type is not None: return_type = function.return_type.build(self) else: return_type = "void" return "{} {}({})".format(return_type, function.name, args)