| # | |
| # yosys -- Yosys Open SYnthesis Suite | |
| # | |
| # Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> | |
| # | |
| # Permission to use, copy, modify, and/or distribute this software for any | |
| # purpose with or without fee is hereby granted, provided that the above | |
| # copyright notice and this permission notice appear in all copies. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| # | |
| # Author Benedikt Tutzer | |
| # | |
| import copy | |
| #Map c++ operator Syntax to Python functions | |
| wrappable_operators = { | |
| "<" : "__lt__", | |
| "==": "__eq__", | |
| "!=": "__ne__", | |
| "+" : "__add__", | |
| "-" : "__sub__", | |
| "*" : "__mul__", | |
| "/" : "__div__", | |
| "()": "__call__" | |
| } | |
| #Restrict certain strings from being function names in Python | |
| keyword_aliases = { | |
| "in" : "in_", | |
| "False" : "False_", | |
| "None" : "None_", | |
| "True" : "True_", | |
| "and" : "and_", | |
| "as" : "as_", | |
| "assert" : "assert_", | |
| "break" : "break_", | |
| "class" : "class_", | |
| "continue" : "continue_", | |
| "def" : "def_", | |
| "del" : "del_", | |
| "elif" : "elif_", | |
| "else" : "else_", | |
| "except" : "except_", | |
| "for" : "for_", | |
| "from" : "from_", | |
| "global" : "global_", | |
| "if" : "if_", | |
| "import" : "import_", | |
| "in" : "in_", | |
| "is" : "is_", | |
| "lambda" : "lambda_", | |
| "nonlocal" : "nonlocal_", | |
| "not" : "not_", | |
| "or" : "or_", | |
| "pass" : "pass_", | |
| "raise" : "raise_", | |
| "return" : "return_", | |
| "try" : "try_", | |
| "while" : "while_", | |
| "with" : "with_", | |
| "yield" : "yield_" | |
| } | |
| #These can be used without any explicit conversion | |
| primitive_types = ["void", "bool", "int", "double", "size_t", "std::string", | |
| "string", "State", "char_p"] | |
| from enum import Enum | |
| #Ways to link between Python- and C++ Objects | |
| class link_types(Enum): | |
| global_list = 1 #Manage a global list of objects in C++, the Python | |
| #object contains a key to find the corresponding C++ | |
| #object and a Pointer to the object to verify it is | |
| #still the same, making collisions unlikely to happen | |
| ref_copy = 2 #The Python object contains a copy of the C++ object. | |
| #The C++ object is deleted when the Python object gets | |
| #deleted | |
| pointer = 3 #The Python Object contains a pointer to it's C++ | |
| #counterpart | |
| derive = 4 #The Python-Wrapper is derived from the C++ object. | |
| class attr_types(Enum): | |
| star = "*" | |
| amp = "&" | |
| ampamp = "&&" | |
| default = "" | |
| #For source-files | |
| class Source: | |
| name = "" | |
| classes = [] | |
| def __init__(self, name, classes): | |
| self.name = name | |
| self.classes = classes | |
| #Splits a list by the given delimiter, without splitting strings inside | |
| #pointy-brackets (< and >) | |
| def split_list(str_def, delim): | |
| str_def = str_def.strip() | |
| if len(str_def) == 0: | |
| return [] | |
| if str_def.count(delim) == 0: | |
| return [str_def] | |
| if str_def.count("<") == 0: | |
| return str_def.split(delim) | |
| if str_def.find("<") < str_def.find(" "): | |
| closing = find_closing(str_def[str_def.find("<")+1:], "<", ">") + str_def.find("<") | |
| comma = str_def[closing:].find(delim) | |
| if comma == -1: | |
| return [str_def] | |
| comma = closing + comma | |
| else: | |
| comma = str_def.find(delim) | |
| rest = split_list(str_def[comma+1:], delim) | |
| ret = [str_def[:comma]] | |
| if rest != None and len(rest) != 0: | |
| ret.extend(rest) | |
| return ret | |
| #Represents a Type | |
| class WType: | |
| name = "" | |
| cont = None | |
| attr_type = attr_types.default | |
| def __init__(self, name = "", cont = None, attr_type = attr_types.default): | |
| self.name = name | |
| self.cont = cont | |
| self.attr_type = attr_type | |
| #Python type-string | |
| def gen_text(self): | |
| text = self.name | |
| if self.name in enum_names: | |
| text = enum_by_name(self.name).namespace + "::" + self.name | |
| if self.cont != None: | |
| return known_containers[self.name].typename | |
| return text | |
| #C++ type-string | |
| def gen_text_cpp(self): | |
| postfix = "" | |
| if self.attr_type == attr_types.star: | |
| postfix = "*" | |
| if self.name in primitive_types: | |
| return self.name + postfix | |
| if self.name in enum_names: | |
| return enum_by_name(self.name).namespace + "::" + self.name + postfix | |
| if self.name in classnames: | |
| return class_by_name(self.name).namespace + "::" + self.name + postfix | |
| text = self.name | |
| if self.cont != None: | |
| text += "<" | |
| for a in self.cont.args: | |
| text += a.gen_text_cpp() + ", " | |
| text = text[:-2] | |
| text += ">" | |
| return text | |
| @staticmethod | |
| def from_string(str_def, containing_file, line_number): | |
| str_def = str_def.strip() | |
| if len(str_def) == 0: | |
| return None | |
| str_def = str_def.replace("RTLIL::SigSig", "std::pair<SigSpec, SigSpec>").replace("SigSig", "std::pair<SigSpec, SigSpec>") | |
| t = WType() | |
| t.name = "" | |
| t.cont = None | |
| t.attr_type = attr_types.default | |
| if str_def.find("<") != -1:# and str_def.find("<") < str_def.find(" "): | |
| candidate = WContainer.from_string(str_def, containing_file, line_number) | |
| if candidate == None: | |
| return None | |
| t.name = str_def[:str_def.find("<")] | |
| if t.name.count("*") + t.name.count("&") > 1: | |
| return None | |
| if t.name.count("*") == 1 or str_def[0] == '*' or str_def[-1] == '*': | |
| t.attr_type = attr_types.star | |
| t.name = t.name.replace("*","") | |
| elif t.name.count("&&") == 1: | |
| t.attr_type = attr_types.ampamp | |
| t.name = t.name.replace("&&","") | |
| elif t.name.count("&") == 1 or str_def[0] == '&' or str_def[-1] == '&': | |
| t.attr_type = attr_types.amp | |
| t.name = t.name.replace("&","") | |
| t.cont = candidate | |
| if(t.name not in known_containers): | |
| return None | |
| return t | |
| prefix = "" | |
| if str.startswith(str_def, "unsigned "): | |
| prefix = "unsigned " | |
| str_def = str_def[9:] | |
| while str.startswith(str_def, "long "): | |
| prefix= "long " + prefix | |
| str_def = str_def[5:] | |
| while str.startswith(str_def, "short "): | |
| prefix = "short " + prefix | |
| str_def = str_def[6:] | |
| str_def = str_def.split("::")[-1] | |
| if str_def.count("*") + str_def.count("&") >= 2: | |
| return None | |
| if str_def.count("*") == 1: | |
| t.attr_type = attr_types.star | |
| str_def = str_def.replace("*","") | |
| elif str_def.count("&&") == 1: | |
| t.attr_type = attr_types.ampamp | |
| str_def = str_def.replace("&&","") | |
| elif str_def.count("&") == 1: | |
| t.attr_type = attr_types.amp | |
| str_def = str_def.replace("&","") | |
| if len(str_def) > 0 and str_def.split("::")[-1] not in primitive_types and str_def.split("::")[-1] not in classnames and str_def.split("::")[-1] not in enum_names: | |
| return None | |
| if str_def.count(" ") == 0: | |
| t.name = (prefix + str_def).replace("char_p", "char *") | |
| t.cont = None | |
| return t | |
| return None | |
| #Represents a container-type | |
| class WContainer: | |
| name = "" | |
| args = [] | |
| def from_string(str_def, containing_file, line_number): | |
| if str_def == None or len(str_def) < 4: | |
| return None | |
| cont = WContainer() | |
| cont.name = str_def[:str_def.find("<")] | |
| str_def = str_def[str_def.find("<")+1:find_closing(str_def, "<", ">")] | |
| cont.args = [] | |
| for arg in split_list(str_def, ","): | |
| candidate = WType.from_string(arg.strip(), containing_file, line_number) | |
| if candidate == None: | |
| return None | |
| cont.args.append(candidate) | |
| return cont | |
| #Translators between Python and C++ containers | |
| #Base Type | |
| class Translator: | |
| tmp_cntr = 0 | |
| typename = "DefaultType" | |
| orig_name = "DefaultCpp" | |
| @classmethod | |
| def gen_type(c, types): | |
| return "\nImplement a function that outputs the c++ type of this container here\n" | |
| @classmethod | |
| def translate(c, varname, types, prefix): | |
| return "\nImplement a function translating a python container to a c++ container here\n" | |
| @classmethod | |
| def translate_cpp(c, varname, types, prefix, ref): | |
| return "\nImplement a function translating a c++ container to a python container here\n" | |
| #Translates list-types (vector, pool, set), that only differ in their name and | |
| #the name of the insertion function | |
| class PythonListTranslator(Translator): | |
| typename = "boost::python::list" | |
| insert_name = "Default" | |
| #generate the c++ type string | |
| @classmethod | |
| def gen_type(c, types): | |
| text = c.orig_name + "<" | |
| if types[0].name in primitive_types: | |
| text += types[0].name | |
| elif types[0].name in known_containers: | |
| text += known_containers[types[0].name].gen_type(types[0].cont.args) | |
| else: | |
| text += class_by_name(types[0].name).namespace + "::" + types[0].name | |
| if types[0].attr_type == attr_types.star: | |
| text += "*" | |
| text += ">" | |
| return text | |
| #Generate C++ code to translate from a boost::python::list | |
| @classmethod | |
| def translate(c, varname, types, prefix): | |
| text = prefix + c.gen_type(types) + " " + varname + "___tmp;" | |
| cntr_name = "cntr_" + str(Translator.tmp_cntr) | |
| Translator.tmp_cntr = Translator.tmp_cntr + 1 | |
| text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "); " + cntr_name + "++)" | |
| text += prefix + "{" | |
| tmp_name = "tmp_" + str(Translator.tmp_cntr) | |
| Translator.tmp_cntr = Translator.tmp_cntr + 1 | |
| if types[0].name in known_containers: | |
| text += prefix + "\t" + known_containers[types[0].name].typename + " " + tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "[" + cntr_name + "]);" | |
| text += known_containers[types[0].name].translate(tmp_name, types[0].cont.args, prefix+"\t") | |
| tmp_name = tmp_name + "___tmp" | |
| text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + ");" | |
| elif types[0].name in classnames: | |
| text += prefix + "\t" + types[0].name + "* " + tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "[" + cntr_name + "]);" | |
| if types[0].attr_type == attr_types.star: | |
| text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + "->get_cpp_obj());" | |
| else: | |
| text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(*" + tmp_name + "->get_cpp_obj());" | |
| else: | |
| text += prefix + "\t" + types[0].name + " " + tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "[" + cntr_name + "]);" | |
| text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + ");" | |
| text += prefix + "}" | |
| return text | |
| #Generate C++ code to translate to a boost::python::list | |
| @classmethod | |
| def translate_cpp(c, varname, types, prefix, ref): | |
| text = prefix + c.typename + " " + varname + "___tmp;" | |
| tmp_name = "tmp_" + str(Translator.tmp_cntr) | |
| Translator.tmp_cntr = Translator.tmp_cntr + 1 | |
| if ref: | |
| text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" | |
| else: | |
| text += prefix + "for(auto " + tmp_name + " : " + varname + ")" | |
| text += prefix + "{" | |
| if types[0].name in classnames: | |
| if types[0].attr_type == attr_types.star: | |
| text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));" | |
| else: | |
| text += prefix + "\t" + varname + "___tmp.append(*" + types[0].name + "::get_py_obj(&" + tmp_name + "));" | |
| elif types[0].name in known_containers: | |
| text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[0].attr_type == attr_types.star) | |
| text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + "___tmp);" | |
| else: | |
| text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");" | |
| text += prefix + "}" | |
| return text | |
| #Sub-type for std::set | |
| class SetTranslator(PythonListTranslator): | |
| insert_name = "insert" | |
| orig_name = "std::set" | |
| #Sub-type for std::vector | |
| class VectorTranslator(PythonListTranslator): | |
| insert_name = "push_back" | |
| orig_name = "std::vector" | |
| #Sub-type for pool | |
| class PoolTranslator(PythonListTranslator): | |
| insert_name = "insert" | |
| orig_name = "pool" | |
| #Translates dict-types (dict, std::map), that only differ in their name and | |
| #the name of the insertion function | |
| class PythonDictTranslator(Translator): | |
| typename = "boost::python::dict" | |
| insert_name = "Default" | |
| @classmethod | |
| def gen_type(c, types): | |
| text = c.orig_name + "<" | |
| if types[0].name in primitive_types: | |
| text += types[0].name | |
| elif types[0].name in known_containers: | |
| text += known_containers[types[0].name].gen_type(types[0].cont.args) | |
| else: | |
| text += class_by_name(types[0].name).namespace + "::" + types[0].name | |
| if types[0].attr_type == attr_types.star: | |
| text += "*" | |
| text += ", " | |
| if types[1].name in primitive_types: | |
| text += types[1].name | |
| elif types[1].name in known_containers: | |
| text += known_containers[types[1].name].gen_type(types[1].cont.args) | |
| else: | |
| text += class_by_name(types[1].name).namespace + "::" + types[1].name | |
| if types[1].attr_type == attr_types.star: | |
| text += "*" | |
| text += ">" | |
| return text | |
| #Generate c++ code to translate from a boost::python::dict | |
| @classmethod | |
| def translate(c, varname, types, prefix): | |
| text = prefix + c.gen_type(types) + " " + varname + "___tmp;" | |
| text += prefix + "boost::python::list " + varname + "_keylist = " + varname + ".keys();" | |
| cntr_name = "cntr_" + str(Translator.tmp_cntr) | |
| Translator.tmp_cntr = Translator.tmp_cntr + 1 | |
| text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "_keylist); " + cntr_name + "++)" | |
| text += prefix + "{" | |
| key_tmp_name = "key_tmp_" + str(Translator.tmp_cntr) | |
| val_tmp_name = "val_tmp_" + str(Translator.tmp_cntr) | |
| Translator.tmp_cntr = Translator.tmp_cntr + 1 | |
| if types[0].name in known_containers: | |
| text += prefix + "\t" + known_containers[types[0].name].typename + " " + key_tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "_keylist[ " + cntr_name + " ]);" | |
| text += known_containers[types[0].name].translate(key_tmp_name, types[0].cont.args, prefix+"\t") | |
| key_tmp_name = key_tmp_name + "___tmp" | |
| elif types[0].name in classnames: | |
| text += prefix + "\t" + types[0].name + "* " + key_tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "_keylist[ " + cntr_name + " ]);" | |
| else: | |
| text += prefix + "\t" + types[0].name + " " + key_tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "_keylist[ " + cntr_name + " ]);" | |
| if types[1].name in known_containers: | |
| text += prefix + "\t" + known_containers[types[1].name].typename + " " + val_tmp_name + " = boost::python::extract<" + known_containers[types[1].name].typename + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" | |
| text += known_containers[types[1].name].translate(val_tmp_name, types[1].cont.args, prefix+"\t") | |
| val_tmp_name = val_tmp_name + "___tmp" | |
| elif types[1].name in classnames: | |
| text += prefix + "\t" + types[1].name + "* " + val_tmp_name + " = boost::python::extract<" + types[1].name + "*>(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" | |
| else: | |
| text += prefix + "\t" + types[1].name + " " + val_tmp_name + " = boost::python::extract<" + types[1].name + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" | |
| text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(std::pair<" + types[0].gen_text_cpp() + ", " + types[1].gen_text_cpp() + ">(" | |
| if types[0].name not in classnames: | |
| text += key_tmp_name | |
| else: | |
| if types[0].attr_type != attr_types.star: | |
| text += "*" | |
| text += key_tmp_name + "->get_cpp_obj()" | |
| text += ", " | |
| if types[1].name not in classnames: | |
| text += val_tmp_name | |
| else: | |
| if types[1].attr_type != attr_types.star: | |
| text += "*" | |
| text += val_tmp_name + "->get_cpp_obj()" | |
| text += "));\n" + prefix + "}" | |
| return text | |
| #Generate c++ code to translate to a boost::python::dict | |
| @classmethod | |
| def translate_cpp(c, varname, types, prefix, ref): | |
| text = prefix + c.typename + " " + varname + "___tmp;" | |
| tmp_name = "tmp_" + str(Translator.tmp_cntr) | |
| Translator.tmp_cntr = Translator.tmp_cntr + 1 | |
| if ref: | |
| text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" | |
| else: | |
| text += prefix + "for(auto " + tmp_name + " : " + varname + ")" | |
| text += prefix + "{" | |
| if types[1].name in known_containers: | |
| text += prefix + "\tauto " + tmp_name + "_second = " + tmp_name + ".second;" | |
| text += known_containers[types[1].name].translate_cpp(tmp_name + "_second", types[1].cont.args, prefix + "\t", types[1].attr_type == attr_types.star) | |
| if types[0].name in classnames: | |
| text += prefix + "\t" + varname + "___tmp[" + types[0].name + "::get_py_obj(" + tmp_name + ".first)] = " | |
| elif types[0].name not in known_containers: | |
| text += prefix + "\t" + varname + "___tmp[" + tmp_name + ".first] = " | |
| if types[1].name in classnames: | |
| if types[1].attr_type == attr_types.star: | |
| text += types[1].name + "::get_py_obj(" + tmp_name + ".second);" | |
| else: | |
| text += "*" + types[1].name + "::get_py_obj(&" + tmp_name + ".second);" | |
| elif types[1].name in known_containers: | |
| text += tmp_name + "_second___tmp;" | |
| else: | |
| text += tmp_name + ".second;" | |
| text += prefix + "}" | |
| return text | |
| #Sub-type for dict | |
| class DictTranslator(PythonDictTranslator): | |
| insert_name = "insert" | |
| orig_name = "dict" | |
| #Sub_type for std::map | |
| class MapTranslator(PythonDictTranslator): | |
| insert_name = "insert" | |
| orig_name = "std::map" | |
| #Translator for std::pair. Derived from PythonDictTranslator because the | |
| #gen_type function is the same (because both have two template parameters) | |
| class TupleTranslator(PythonDictTranslator): | |
| typename = "boost::python::tuple" | |
| orig_name = "std::pair" | |
| #Generate c++ code to translate from a boost::python::tuple | |
| @classmethod | |
| def translate(c, varname, types, prefix): | |
| text = prefix + types[0].name + " " + varname + "___tmp_0 = boost::python::extract<" + types[0].name + ">(" + varname + "[0]);" | |
| text += prefix + types[1].name + " " + varname + "___tmp_1 = boost::python::extract<" + types[1].name + ">(" + varname + "[1]);" | |
| text += prefix + TupleTranslator.gen_type(types) + " " + varname + "___tmp(" | |
| if types[0].name.split(" ")[-1] in primitive_types: | |
| text += varname + "___tmp_0, " | |
| else: | |
| text += varname + "___tmp_0.get_cpp_obj(), " | |
| if types[1].name.split(" ")[-1] in primitive_types: | |
| text += varname + "___tmp_1);" | |
| else: | |
| text += varname + "___tmp_1.get_cpp_obj());" | |
| return text | |
| #Generate c++ code to translate to a boost::python::tuple | |
| @classmethod | |
| def translate_cpp(c, varname, types, prefix, ref): | |
| # if the tuple is a pair of SigSpecs (aka SigSig), then we need | |
| # to call get_py_obj() on each item in the tuple | |
| if types[0].name in classnames: | |
| first_var = types[0].name + "::get_py_obj(" + varname + ".first)" | |
| else: | |
| first_var = varname + ".first" | |
| if types[1].name in classnames: | |
| second_var = types[1].name + "::get_py_obj(" + varname + ".second)" | |
| else: | |
| second_var = varname + ".second" | |
| text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");" | |
| return text | |
| #Associate the Translators with their c++ type | |
| known_containers = { | |
| "std::set" : SetTranslator, | |
| "std::vector" : VectorTranslator, | |
| "pool" : PoolTranslator, | |
| "dict" : DictTranslator, | |
| "std::pair" : TupleTranslator, | |
| "std::map" : MapTranslator | |
| } | |
| class Attribute: | |
| wtype = None | |
| varname = None | |
| is_const = False | |
| default_value = None | |
| pos = None | |
| pos_counter = 0 | |
| def __init__(self, wtype, varname, is_const = False, default_value = None): | |
| self.wtype = wtype | |
| self.varname = varname | |
| self.is_const = is_const | |
| self.default_value = None | |
| self.container = None | |
| @staticmethod | |
| def from_string(str_def, containing_file, line_number): | |
| if len(str_def) < 3: | |
| return None | |
| orig = str_def | |
| arg = Attribute(None, None) | |
| prefix = "" | |
| arg.wtype = None | |
| arg.varname = None | |
| arg.is_const = False | |
| arg.default_value = None | |
| arg.container = None | |
| if str.startswith(str_def, "const "): | |
| arg.is_const = True | |
| str_def = str_def[6:] | |
| if str.startswith(str_def, "unsigned "): | |
| prefix = "unsigned " | |
| str_def = str_def[9:] | |
| while str.startswith(str_def, "long "): | |
| prefix= "long " + prefix | |
| str_def = str_def[5:] | |
| while str.startswith(str_def, "short "): | |
| prefix = "short " + prefix | |
| str_def = str_def[6:] | |
| if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "): | |
| closing = find_closing(str_def[str_def.find("<"):], "<", ">") + str_def.find("<") + 1 | |
| arg.wtype = WType.from_string(str_def[:closing].strip(), containing_file, line_number) | |
| str_def = str_def[closing+1:] | |
| else: | |
| if str_def.count(" ") > 0: | |
| arg.wtype = WType.from_string(prefix + str_def[:str_def.find(" ")].strip(), containing_file, line_number) | |
| str_def = str_def[str_def.find(" ")+1:] | |
| else: | |
| arg.wtype = WType.from_string(prefix + str_def.strip(), containing_file, line_number) | |
| str_def = "" | |
| arg.varname = "" | |
| if arg.wtype == None: | |
| return None | |
| if str_def.count("=") == 0: | |
| arg.varname = str_def.strip() | |
| if arg.varname.find(" ") > 0: | |
| return None | |
| else: | |
| arg.varname = str_def[:str_def.find("=")].strip() | |
| if arg.varname.find(" ") > 0: | |
| return None | |
| str_def = str_def[str_def.find("=")+1:].strip() | |
| arg.default_value = str_def[arg.varname.find("=")+1:].strip() | |
| if len(arg.varname) == 0: | |
| arg.varname = None | |
| return arg | |
| if arg.varname[0] == '*': | |
| arg.wtype.attr_type = attr_types.star | |
| arg.varname = arg.varname[1:] | |
| elif arg.varname[0] == '&': | |
| if arg.wtype.attr_type != attr_types.default: | |
| return None | |
| if arg.varname[1] == '&': | |
| arg.wtype.attr_type = attr_types.ampamp | |
| arg.varname = arg.varname[2:] | |
| else: | |
| arg.wtype.attr_type = attr_types.amp | |
| arg.varname = arg.varname[1:] | |
| return arg | |
| #Generates the varname. If the attribute has no name in the header file, | |
| #a name is generated | |
| def gen_varname(self): | |
| if self.varname != None: | |
| return self.varname | |
| if self.wtype.name == "void": | |
| return "" | |
| if self.pos == None: | |
| self.pos = Attribute.pos_counter | |
| Attribute.pos_counter = Attribute.pos_counter + 1 | |
| return "gen_varname_" + str(self.pos) | |
| #Generates the text for the function headers with wrapper types | |
| def gen_listitem(self): | |
| prefix = "" | |
| if self.is_const: | |
| prefix = "const " | |
| if self.wtype.name in classnames: | |
| return prefix + self.wtype.name + "* " + self.gen_varname() | |
| if self.wtype.name in known_containers: | |
| return prefix + known_containers[self.wtype.name].typename + " " + self.gen_varname() | |
| return prefix + self.wtype.name + " " + self.gen_varname() | |
| #Generates the test for the function headers with c++ types | |
| def gen_listitem_cpp(self): | |
| prefix = "" | |
| if self.is_const: | |
| prefix = "const " | |
| infix = "" | |
| if self.wtype.attr_type == attr_types.star: | |
| infix = "*" | |
| elif self.wtype.attr_type == attr_types.amp: | |
| infix = "&" | |
| elif self.wtype.attr_type == attr_types.ampamp: | |
| infix = "&&" | |
| if self.wtype.name in known_containers: | |
| return prefix + known_containers[self.wtype.name].gen_type(self.wtype.cont.args) + " " + infix + self.gen_varname() | |
| if self.wtype.name in classnames: | |
| return prefix + class_by_name(self.wtype.name).namespace + "::" + self.wtype.name + " " + infix + self.gen_varname() | |
| return prefix + self.wtype.name + " " + infix + self.gen_varname() | |
| #Generates the listitem withtout the varname, so the signature can be | |
| #compared | |
| def gen_listitem_hash(self): | |
| prefix = "" | |
| if self.is_const: | |
| prefix = "const " | |
| if self.wtype.name in classnames: | |
| return prefix + self.wtype.name + "* " | |
| if self.wtype.name in known_containers: | |
| return known_containers[self.wtype.name].typename | |
| return prefix + self.wtype.name | |
| #Generate Translation code for the attribute | |
| def gen_translation(self): | |
| if self.wtype.name in known_containers: | |
| return known_containers[self.wtype.name].translate(self.gen_varname(), self.wtype.cont.args, "\n\t\t") | |
| return "" | |
| #Generate Translation code from c++ for the attribute | |
| def gen_translation_cpp(self): | |
| if self.wtype.name in known_containers: | |
| return known_containers[self.wtype.name].translate_cpp(self.gen_varname(), self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) | |
| return "" | |
| #Generate Text for the call | |
| def gen_call(self): | |
| ret = self.gen_varname() | |
| if self.wtype.name in known_containers: | |
| if self.wtype.attr_type == attr_types.star: | |
| return "&" + ret + "___tmp" | |
| return ret + "___tmp" | |
| if self.wtype.name in classnames: | |
| if self.wtype.attr_type != attr_types.star: | |
| ret = "*" + ret | |
| return ret + "->get_cpp_obj()" | |
| if self.wtype.name == "char *" and self.gen_varname() in ["format", "fmt"]: | |
| return "\"%s\", " + self.gen_varname() | |
| if self.wtype.attr_type == attr_types.star: | |
| return "&" + ret | |
| return ret | |
| def gen_call_cpp(self): | |
| ret = self.gen_varname() | |
| if self.wtype.name.split(" ")[-1] in primitive_types or self.wtype.name in enum_names: | |
| if self.wtype.attr_type == attr_types.star: | |
| return "&" + ret | |
| return ret | |
| if self.wtype.name not in classnames: | |
| if self.wtype.attr_type == attr_types.star: | |
| return "&" + ret + "___tmp" | |
| return ret + "___tmp" | |
| if self.wtype.attr_type != attr_types.star: | |
| ret = "*" + ret | |
| return self.wtype.name + "::get_py_obj(" + self.gen_varname() + ")" | |
| #Generate cleanup code | |
| def gen_cleanup(self): | |
| if self.wtype.name in primitive_types or self.wtype.name in classnames or self.wtype.name in enum_names or not self.wtype.attr_type == attr_types.star or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): | |
| return "" | |
| return "\n\t\tdelete " + self.gen_varname() + "___tmp;" | |
| class WClass: | |
| name = None | |
| namespace = None | |
| link_type = None | |
| id_ = None | |
| string_id = None | |
| hash_id = None | |
| needs_clone = False | |
| found_funs = [] | |
| found_vars = [] | |
| found_constrs = [] | |
| def __init__(self, name, link_type, id_, string_id = None, hash_id = None, needs_clone = False): | |
| self.name = name | |
| self.namespace = None | |
| self.link_type = link_type | |
| self.id_ = id_ | |
| self.string_id = string_id | |
| self.hash_id = hash_id | |
| self.needs_clone = needs_clone | |
| self.found_funs = [] | |
| self.found_vars = [] | |
| self.found_constrs = [] | |
| def printable_constrs(self): | |
| ret = 0 | |
| for con in self.found_constrs: | |
| if not con.protected: | |
| ret += 1 | |
| return ret | |
| def gen_decl(self, filename): | |
| long_name = self.namespace + "::" + self.name | |
| text = "\n\t// WRAPPED from " + filename | |
| text += "\n\tstruct " + self.name | |
| if self.link_type == link_types.derive: | |
| text += " : public " + self.namespace + "::" + self.name | |
| text += "\n\t{\n" | |
| if self.link_type != link_types.derive: | |
| text += "\t\t" + long_name + "* ref_obj;\n" | |
| if self.link_type == link_types.ref_copy or self.link_type == link_types.pointer: | |
| text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n" | |
| elif self.link_type == link_types.global_list: | |
| text += "\t\t" + self.id_.wtype.name + " " + self.id_.varname + ";\n" | |
| text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{" | |
| text += "\n\t\t\t" + long_name + "* ret = " + long_name + "::get_all_" + self.name.lower() + "s()->at(this->" + self.id_.varname + ");" | |
| text += "\n\t\t\tif(ret != NULL && ret == this->ref_obj)" | |
| text += "\n\t\t\t\treturn ret;" | |
| text += "\n\t\t\tthrow std::runtime_error(\"" + self.name + "'s c++ object does not exist anymore.\");" | |
| text += "\n\t\t\treturn NULL;" | |
| text += "\n\t\t}\n" | |
| #if self.link_type != link_types.pointer: | |
| text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" | |
| text += "\n\t\t\tif(ref == nullptr){" | |
| text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");" | |
| text += "\n\t\t\t}" | |
| text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" | |
| if self.link_type == link_types.pointer: | |
| text += "\n\t\t\tret->ref_obj = ref;" | |
| if self.link_type == link_types.ref_copy: | |
| if self.needs_clone: | |
| text += "\n\t\t\tret->ref_obj = ref->clone();" | |
| else: | |
| text += "\n\t\t\tret->ref_obj = new "+long_name+"(*ref);" | |
| if self.link_type == link_types.global_list: | |
| text += "\n\t\t\tret->ref_obj = ref;" | |
| text += "\n\t\t\tret->" + self.id_.varname + " = ret->ref_obj->" + self.id_.varname + ";" | |
| text += "\n\t\t\treturn ret;" | |
| text += "\n\t\t}\n" | |
| if self.link_type == link_types.ref_copy: | |
| text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + " ref)\n\t\t{" | |
| text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" | |
| if self.needs_clone: | |
| text += "\n\t\t\tret->ref_obj = ref.clone();" | |
| else: | |
| text += "\n\t\t\tret->ref_obj = new "+long_name+"(ref);" | |
| text += "\n\t\t\treturn ret;" | |
| text += "\n\t\t}\n" | |
| for con in self.found_constrs: | |
| text += con.gen_decl() | |
| for var in self.found_vars: | |
| text += var.gen_decl() | |
| for fun in self.found_funs: | |
| text += fun.gen_decl() | |
| if self.link_type == link_types.derive: | |
| duplicates = {} | |
| for fun in self.found_funs: | |
| if fun.name in duplicates: | |
| fun.gen_alias() | |
| duplicates[fun.name].gen_alias() | |
| else: | |
| duplicates[fun.name] = fun | |
| text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn (" + self.namespace + "::" + self.name +"*)this;\n\t\t}\n" | |
| text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" | |
| text += "\n\t\t\treturn (" + self.name + "*)ref;" | |
| text += "\n\t\t}\n" | |
| for con in self.found_constrs: | |
| text += con.gen_decl_derive() | |
| for var in self.found_vars: | |
| text += var.gen_decl() | |
| for fun in self.found_funs: | |
| text += fun.gen_decl_virtual() | |
| if self.hash_id != None: | |
| text += "\n\t\tunsigned int get_hash_py()" | |
| text += "\n\t\t{" | |
| text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";" | |
| text += "\n\t\t}" | |
| text += "\n\t};\n" | |
| if self.link_type == link_types.derive: | |
| text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">" | |
| text += "\n\t{" | |
| for con in self.found_constrs: | |
| text += con.gen_decl_wrapperclass() | |
| for fun in self.found_funs: | |
| text += fun.gen_default_impl() | |
| text += "\n\t};" | |
| text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)" | |
| text += "\n\t{" | |
| text += "\n\t\tostr << \"" + self.name | |
| if self.string_id != None: | |
| text +=" \\\"\"" | |
| text += " << ref.get_cpp_obj()->" + self.string_id | |
| text += " << \"\\\"\"" | |
| else: | |
| text += " at \" << ref.get_cpp_obj()" | |
| text += ";" | |
| text += "\n\t\treturn ostr;" | |
| text += "\n\t}" | |
| text += "\n" | |
| return text | |
| def gen_funs(self, filename): | |
| text = "" | |
| if self.link_type != link_types.derive: | |
| for con in self.found_constrs: | |
| text += con.gen_def() | |
| for var in self.found_vars: | |
| text += var.gen_def() | |
| for fun in self.found_funs: | |
| text += fun.gen_def() | |
| else: | |
| for var in self.found_vars: | |
| text += var.gen_def() | |
| for fun in self.found_funs: | |
| text += fun.gen_def_virtual() | |
| return text | |
| def gen_boost_py(self): | |
| text = "\n\t\tclass_<" + self.name | |
| if self.link_type == link_types.derive: | |
| text += "Wrap, boost::noncopyable" | |
| text += ">(\"" + self.name + "\"" | |
| if self.printable_constrs() == 0 or not self.contains_default_constr(): | |
| text += ", no_init" | |
| text += ")" | |
| text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))" | |
| text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))" | |
| for con in self.found_constrs: | |
| text += con.gen_boost_py() | |
| for var in self.found_vars: | |
| text += var.gen_boost_py() | |
| static_funs = [] | |
| for fun in self.found_funs: | |
| text += fun.gen_boost_py() | |
| if fun.is_static and fun.alias not in static_funs: | |
| static_funs.append(fun.alias) | |
| for fun in static_funs: | |
| text += "\n\t\t\t.staticmethod(\"" + fun + "\")" | |
| if self.hash_id != None: | |
| text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)" | |
| text += "\n\t\t\t;\n" | |
| return text | |
| def contains_default_constr(self): | |
| for c in self.found_constrs: | |
| if len(c.args) == 0: | |
| return True | |
| return False | |
| #CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE | |
| sources = [ | |
| Source("kernel/celltypes",[ | |
| WClass("CellType", link_types.pointer, None, None, "type.hash()", True), | |
| WClass("CellTypes", link_types.pointer, None, None, None, True) | |
| ] | |
| ), | |
| Source("kernel/consteval",[ | |
| WClass("ConstEval", link_types.pointer, None, None, None, True) | |
| ] | |
| ), | |
| Source("kernel/log",[]), | |
| Source("kernel/register",[ | |
| WClass("Pass", link_types.derive, None, None, None, True), | |
| ] | |
| ), | |
| Source("kernel/rtlil",[ | |
| WClass("IdString", link_types.ref_copy, None, "str()", "hash()"), | |
| WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"), | |
| WClass("AttrObject", link_types.ref_copy, None, None, None), | |
| WClass("Selection", link_types.ref_copy, None, None, None), | |
| WClass("Monitor", link_types.derive, None, None, None), | |
| WClass("CaseRule",link_types.ref_copy, None, None, None, True), | |
| WClass("SwitchRule",link_types.ref_copy, None, None, None, True), | |
| WClass("SyncRule", link_types.ref_copy, None, None, None, True), | |
| WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"), | |
| WClass("SigChunk", link_types.ref_copy, None, None, None), | |
| WClass("SigBit", link_types.ref_copy, None, None, "hash()"), | |
| WClass("SigSpec", link_types.ref_copy, None, None, "hash()"), | |
| WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), | |
| WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), | |
| WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), | |
| WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), | |
| WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()") | |
| ] | |
| ), | |
| #Source("kernel/satgen",[ | |
| # ] | |
| # ), | |
| #Source("libs/ezsat/ezsat",[ | |
| # ] | |
| # ), | |
| #Source("libs/ezsat/ezminisat",[ | |
| # ] | |
| # ), | |
| Source("kernel/sigtools",[ | |
| WClass("SigMap", link_types.pointer, None, None, None, True) | |
| ] | |
| ), | |
| Source("kernel/yosys",[ | |
| ] | |
| ), | |
| Source("kernel/cost",[]) | |
| ] | |
| blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow", "YOSYS_NAMESPACE::Module::Bu0", "YOSYS_NAMESPACE::CaseRule::optimize"] | |
| enum_names = ["State","SyncType","ConstFlags"] | |
| enums = [] #Do not edit | |
| unowned_functions = [] | |
| classnames = [] | |
| for source in sources: | |
| for wclass in source.classes: | |
| classnames.append(wclass.name) | |
| def class_by_name(name): | |
| for source in sources: | |
| for wclass in source.classes: | |
| if wclass.name == name: | |
| return wclass | |
| return None | |
| def enum_by_name(name): | |
| for e in enums: | |
| if e.name == name: | |
| return e | |
| return None | |
| def find_closing(text, open_tok, close_tok): | |
| if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok): | |
| return text.find(close_tok) | |
| return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1 | |
| def unpretty_string(s): | |
| s = s.strip() | |
| while s.find(" ") != -1: | |
| s = s.replace(" "," ") | |
| while s.find("\t") != -1: | |
| s = s.replace("\t"," ") | |
| s = s.replace(" (","(") | |
| return s | |
| class WEnum: | |
| name = None | |
| namespace = None | |
| values = [] | |
| def from_string(str_def, namespace, line_number): | |
| str_def = str_def.strip() | |
| if not str.startswith(str_def, "enum "): | |
| return None | |
| if str_def.count(";") != 1: | |
| return None | |
| str_def = str_def[5:] | |
| enum = WEnum() | |
| split = str_def.split(":") | |
| if(len(split) != 2): | |
| return None | |
| enum.name = split[0].strip() | |
| if enum.name not in enum_names: | |
| return None | |
| str_def = split[1] | |
| if str_def.count("{") != str_def.count("}") != 1: | |
| return None | |
| if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';': | |
| return None | |
| str_def = str_def.split("{")[-1].split("}")[0] | |
| enum.values = [] | |
| for val in str_def.split(','): | |
| enum.values.append(val.strip().split('=')[0].strip()) | |
| enum.namespace = namespace | |
| return enum | |
| def gen_boost_py(self): | |
| text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n" | |
| for value in self.values: | |
| text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n" | |
| text += "\t\t\t;\n" | |
| return text | |
| def __str__(self): | |
| ret = "Enum " + self.namespace + "::" + self.name + "(\n" | |
| for val in self.values: | |
| ret = ret + "\t" + val + "\n" | |
| return ret + ")" | |
| def __repr__(self): | |
| return __str__(self) | |
| class WConstructor: | |
| orig_text = None | |
| args = [] | |
| containing_file = None | |
| member_of = None | |
| duplicate = False | |
| protected = False | |
| def __init__(self, containing_file, class_): | |
| self.orig_text = "Auto generated default constructor" | |
| self.args = [] | |
| self.containing_file = containing_file | |
| self.member_of = class_ | |
| self.protected = False | |
| def from_string(str_def, containing_file, class_, line_number, protected = False): | |
| if class_ == None: | |
| return None | |
| if str_def.count("delete;") > 0: | |
| return None | |
| con = WConstructor(containing_file, class_) | |
| con.orig_text = str_def | |
| con.args = [] | |
| con.duplicate = False | |
| con.protected = protected | |
| if str.startswith(str_def, "inline "): | |
| str_def = str_def[7:] | |
| if not str.startswith(str_def, class_.name + "("): | |
| return None | |
| str_def = str_def[len(class_.name)+1:] | |
| found = find_closing(str_def, "(", ")") | |
| if found == -1: | |
| return None | |
| str_def = str_def[0:found].strip() | |
| if len(str_def) == 0: | |
| return con | |
| for arg in split_list(str_def, ","): | |
| parsed = Attribute.from_string(arg.strip(), containing_file, line_number) | |
| if parsed == None: | |
| return None | |
| con.args.append(parsed) | |
| return con | |
| def gen_decl(self): | |
| if self.duplicate or self.protected: | |
| return "" | |
| text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t\t" + self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ");\n" | |
| return text | |
| def gen_decl_derive(self): | |
| if self.duplicate or self.protected: | |
| return "" | |
| text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t\t" + self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ")" | |
| if len(self.args) == 0: | |
| return text + "{}" | |
| text += " : " | |
| text += self.member_of.namespace + "::" + self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_call() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += "){}\n" | |
| return text | |
| def gen_decl_wrapperclass(self): | |
| if self.duplicate or self.protected: | |
| return "" | |
| text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t\t" + self.member_of.name + "Wrap(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ")" | |
| if len(self.args) == 0: | |
| return text + "{}" | |
| text += " : " | |
| text += self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_call() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += "){}\n" | |
| return text | |
| def gen_decl_hash_py(self): | |
| text = self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem_hash() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ");" | |
| return text | |
| def gen_def(self): | |
| if self.duplicate or self.protected: | |
| return "" | |
| text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text +=")\n\t{" | |
| for arg in self.args: | |
| text += arg.gen_translation() | |
| if self.member_of.link_type != link_types.derive: | |
| text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_call() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| if self.member_of.link_type != link_types.derive: | |
| text += ");" | |
| if self.member_of.link_type == link_types.global_list: | |
| text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";" | |
| for arg in self.args: | |
| text += arg.gen_cleanup() | |
| text += "\n\t}\n" | |
| return text | |
| def gen_boost_py(self): | |
| if self.duplicate or self.protected or len(self.args) == 0: | |
| return "" | |
| text = "\n\t\t\t.def(init" | |
| text += "<" | |
| for a in self.args: | |
| text += a.gen_listitem_hash() + ", " | |
| text = text[0:-2] + ">())" | |
| return text | |
| class WFunction: | |
| orig_text = None | |
| is_static = False | |
| is_inline = False | |
| is_virtual = False | |
| ret_attr_type = attr_types.default | |
| is_operator = False | |
| ret_type = None | |
| name = None | |
| alias = None | |
| args = [] | |
| containing_file = None | |
| member_of = None | |
| duplicate = False | |
| namespace = "" | |
| def from_string(str_def, containing_file, class_, line_number, namespace): | |
| if str_def.count("delete;") > 0: | |
| return None | |
| func = WFunction() | |
| func.is_static = False | |
| func.is_inline = False | |
| func.is_virtual = False | |
| func.ret_attr_type = attr_types.default | |
| func.is_operator = False | |
| func.member_of = None | |
| func.orig_text = str_def | |
| func.args = [] | |
| func.containing_file = containing_file | |
| func.member_of = class_ | |
| func.duplicate = False | |
| func.namespace = namespace | |
| str_def = str_def.replace("operator ","operator") | |
| if str.startswith(str_def, "static "): | |
| func.is_static = True | |
| str_def = str_def[7:] | |
| else: | |
| func.is_static = False | |
| if str.startswith(str_def, "inline "): | |
| func.is_inline = True | |
| str_def = str_def[7:] | |
| else: | |
| func.is_inline = False | |
| if str.startswith(str_def, "virtual "): | |
| func.is_virtual = True | |
| str_def = str_def[8:] | |
| else: | |
| func.is_virtual = False | |
| if str_def.count(" ") == 0: | |
| return None | |
| parts = split_list(str_def.strip(), " ") | |
| prefix = "" | |
| i = 0 | |
| for part in parts: | |
| if part in ["unsigned", "long", "short"]: | |
| prefix += part + " " | |
| i += 1 | |
| else: | |
| break | |
| parts = parts[i:] | |
| if len(parts) <= 1: | |
| return None | |
| func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number) | |
| if func.ret_type == None: | |
| return None | |
| str_def = parts[1] | |
| for part in parts[2:]: | |
| str_def = str_def + " " + part | |
| found = str_def.find("(") | |
| if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")): | |
| return None | |
| func.name = str_def[:found] | |
| str_def = str_def[found:] | |
| if func.name.find("operator") != -1 and str.startswith(str_def, "()("): | |
| func.name += "()" | |
| str_def = str_def[2:] | |
| str_def = str_def[1:] | |
| if func.name.find("operator") != -1: | |
| func.is_operator = True | |
| if func.name.find("*") == 0: | |
| func.name = func.name.replace("*", "") | |
| func.ret_type.attr_type = attr_types.star | |
| if func.name.find("&&") == 0: | |
| func.name = func.name.replace("&&", "") | |
| func.ret_type.attr_type = attr_types.ampamp | |
| if func.name.find("&") == 0: | |
| func.name = func.name.replace("&", "") | |
| func.ret_type.attr_type = attr_types.amp | |
| found = find_closing(str_def, "(", ")") | |
| if found == -1: | |
| return None | |
| str_def = str_def[0:found] | |
| if func.name in blacklist_methods: | |
| return None | |
| if func.namespace != None and func.namespace != "": | |
| if (func.namespace + "::" + func.name) in blacklist_methods: | |
| return None | |
| if func.member_of != None: | |
| if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods: | |
| return None | |
| if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators: | |
| return None | |
| testname = func.name | |
| if func.is_operator: | |
| testname = testname[:testname.find("operator")] | |
| if testname.count(")") != 0 or testname.count("(") != 0 or testname.count("~") != 0 or testname.count(";") != 0 or testname.count(">") != 0 or testname.count("<") != 0 or testname.count("throw") != 0: | |
| return None | |
| func.alias = func.name | |
| if func.name in keyword_aliases: | |
| func.alias = keyword_aliases[func.name] | |
| str_def = str_def[:found].strip() | |
| if(len(str_def) == 0): | |
| return func | |
| for arg in split_list(str_def, ","): | |
| if arg.strip() == "...": | |
| continue | |
| parsed = Attribute.from_string(arg.strip(), containing_file, line_number) | |
| if parsed == None: | |
| return None | |
| func.args.append(parsed) | |
| return func | |
| def gen_alias(self): | |
| self.alias = self.name | |
| for arg in self.args: | |
| self.alias += "__" + arg.wtype.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","") | |
| def gen_decl(self): | |
| if self.duplicate: | |
| return "" | |
| text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t\t" | |
| if self.is_static: | |
| text += "static " | |
| text += self.ret_type.gen_text() + " " + self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() | |
| text += ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ");\n" | |
| return text | |
| def gen_decl_virtual(self): | |
| if self.duplicate: | |
| return "" | |
| if not self.is_virtual: | |
| return self.gen_decl() | |
| text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t\tvirtual " | |
| if self.is_static: | |
| text += "static " | |
| text += self.ret_type.gen_text() + " py_" + self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() | |
| text += ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ")" | |
| if len(self.args) == 0: | |
| text += "{}" | |
| else: | |
| text += "\n\t\t{" | |
| for arg in self.args: | |
| text += "\n\t\t\t(void)" + arg.gen_varname() + ";" | |
| text += "\n\t\t}\n" | |
| text += "\n\t\tvirtual " | |
| if self.is_static: | |
| text += "static " | |
| text += self.ret_type.gen_text() + " " + self.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem_cpp() | |
| text += ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ") YS_OVERRIDE;\n" | |
| return text | |
| def gen_decl_hash_py(self): | |
| text = self.ret_type.gen_text() + " " + self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem_hash() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ");" | |
| return text | |
| def gen_def(self): | |
| if self.duplicate: | |
| return "" | |
| text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t" + self.ret_type.gen_text() + " " | |
| if self.member_of != None: | |
| text += self.member_of.name + "::" | |
| text += self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() | |
| text += ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text +=")\n\t{" | |
| for arg in self.args: | |
| text += arg.gen_translation() | |
| text += "\n\t\t" | |
| if self.ret_type.name != "void": | |
| if self.ret_type.name in known_containers: | |
| text += self.ret_type.gen_text_cpp() | |
| else: | |
| text += self.ret_type.gen_text() | |
| if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star): | |
| text += "*" | |
| text += " ret_ = " | |
| if self.ret_type.name in classnames: | |
| text += self.ret_type.name + "::get_py_obj(" | |
| if self.member_of == None: | |
| text += "::" + self.namespace + "::" + self.alias + "(" | |
| elif self.is_static: | |
| text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" | |
| else: | |
| text += "this->get_cpp_obj()->" + self.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_call() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| if self.ret_type.name in classnames: | |
| text += ")" | |
| text += ");" | |
| for arg in self.args: | |
| text += arg.gen_cleanup() | |
| if self.ret_type.name != "void": | |
| if self.ret_type.name in classnames: | |
| text += "\n\t\treturn *ret_;" | |
| elif self.ret_type.name in known_containers: | |
| text += known_containers[self.ret_type.name].translate_cpp("ret_", self.ret_type.cont.args, "\n\t\t", self.ret_type.attr_type == attr_types.star) | |
| text += "\n\t\treturn ret____tmp;" | |
| else: | |
| text += "\n\t\treturn ret_;" | |
| text += "\n\t}\n" | |
| return text | |
| def gen_def_virtual(self): | |
| if self.duplicate: | |
| return "" | |
| if not self.is_virtual: | |
| return self.gen_def() | |
| text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file | |
| text += "\n\t" | |
| if self.is_static: | |
| text += "static " | |
| text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem_cpp() | |
| text += ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ")\n\t{" | |
| for arg in self.args: | |
| text += arg.gen_translation_cpp() | |
| text += "\n\t\t" | |
| if self.member_of == None: | |
| text += "::" + self.namespace + "::" + self.alias + "(" | |
| elif self.is_static: | |
| text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" | |
| else: | |
| text += "py_" + self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_call_cpp() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| if self.ret_type.name in classnames: | |
| text += ")" | |
| text += ");" | |
| for arg in self.args: | |
| text += arg.gen_cleanup() | |
| text += "\n\t}\n" | |
| return text | |
| def gen_default_impl(self): | |
| if self.duplicate: | |
| return "" | |
| if not self.is_virtual: | |
| return "" | |
| text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| call_string = "py_" + self.alias + "(" | |
| for arg in self.args: | |
| call_string += arg.gen_varname() + ", " | |
| if len(self.args) > 0: | |
| call_string = call_string[0:-2] | |
| call_string += ");" | |
| text += ")\n\t\t{" | |
| text += "\n\t\t\tif(boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))" | |
| text += "\n\t\t\t\t" + call_string | |
| text += "\n\t\t\telse" | |
| text += "\n\t\t\t\t" + self.member_of.name + "::" + call_string | |
| text += "\n\t\t}" | |
| text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "(" | |
| for arg in self.args: | |
| text += arg.gen_listitem() + ", " | |
| if len(self.args) > 0: | |
| text = text[:-2] | |
| text += ")\n\t\t{" | |
| text += "\n\t\t\tthis->" + self.member_of.name + "::" + call_string | |
| text += "\n\t\t}" | |
| return text | |
| def gen_boost_py(self): | |
| if self.duplicate: | |
| return "" | |
| if self.member_of == None: | |
| text = "\n\t\tdef" | |
| else: | |
| text = "\n\t\t\t.def" | |
| if len(self.args) > -1: | |
| if self.ret_type.name in known_containers: | |
| text += "<" + known_containers[self.ret_type.name].typename + " " | |
| else: | |
| text += "<" + self.ret_type.name + " " | |
| if self.member_of == None or self.is_static: | |
| text += "(*)(" | |
| else: | |
| text += "(" + self.member_of.name + "::*)(" | |
| for a in self.args: | |
| text += a.gen_listitem_hash() + ", " | |
| if len(self.args) > 0: | |
| text = text[0:-2] + ")>" | |
| else: | |
| text += "void)>" | |
| if self.is_operator: | |
| text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\"" | |
| else: | |
| if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual: | |
| text += "(\"py_" + self.alias + "\"" | |
| else: | |
| text += "(\"" + self.alias + "\"" | |
| if self.member_of != None: | |
| text += ", &" + self.member_of.name + "::" | |
| if self.member_of.link_type == link_types.derive and self.is_virtual: | |
| text += "py_" + self.alias | |
| text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias | |
| else: | |
| text += self.alias | |
| text += ")" | |
| else: | |
| text += ", " + "YOSYS_PYTHON::" + self.alias + ");" | |
| return text | |
| class WMember: | |
| orig_text = None | |
| wtype = attr_types.default | |
| name = None | |
| containing_file = None | |
| member_of = None | |
| namespace = "" | |
| is_const = False | |
| def from_string(str_def, containing_file, class_, line_number, namespace): | |
| member = WMember() | |
| member.orig_text = str_def | |
| member.wtype = None | |
| member.name = "" | |
| member.containing_file = containing_file | |
| member.member_of = class_ | |
| member.namespace = namespace | |
| member.is_const = False | |
| if str.startswith(str_def, "const "): | |
| member.is_const = True | |
| str_def = str_def[6:] | |
| if str_def.count(" ") == 0: | |
| return None | |
| parts = split_list(str_def.strip(), " ") | |
| prefix = "" | |
| i = 0 | |
| for part in parts: | |
| if part in ["unsigned", "long", "short"]: | |
| prefix += part + " " | |
| i += 1 | |
| else: | |
| break | |
| parts = parts[i:] | |
| if len(parts) <= 1: | |
| return None | |
| member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) | |
| if member.wtype == None: | |
| return None | |
| str_def = parts[1] | |
| for part in parts[2:]: | |
| str_def = str_def + " " + part | |
| if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1: | |
| return None | |
| found = str_def.find(";") | |
| if found == -1: | |
| return None | |
| found_eq = str_def.find("=") | |
| if found_eq != -1: | |
| found = found_eq | |
| member.name = str_def[:found] | |
| str_def = str_def[found+1:] | |
| if member.name.find("*") == 0: | |
| member.name = member.name.replace("*", "") | |
| member.wtype.attr_type = attr_types.star | |
| if member.name.find("&&") == 0: | |
| member.name = member.name.replace("&&", "") | |
| member.wtype.attr_type = attr_types.ampamp | |
| if member.name.find("&") == 0: | |
| member.name = member.name.replace("&", "") | |
| member.wtype.attr_type = attr_types.amp | |
| if(len(str_def.strip()) != 0): | |
| return None | |
| if len(member.name.split(",")) > 1: | |
| member_list = [] | |
| for name in member.name.split(","): | |
| name = name.strip(); | |
| member_list.append(WMember()) | |
| member_list[-1].orig_text = member.orig_text | |
| member_list[-1].wtype = member.wtype | |
| member_list[-1].name = name | |
| member_list[-1].containing_file = member.containing_file | |
| member_list[-1].member_of = member.member_of | |
| member_list[-1].namespace = member.namespace | |
| member_list[-1].is_const = member.is_const | |
| return member_list | |
| return member | |
| def gen_decl(self): | |
| text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n" | |
| if self.is_const: | |
| return text | |
| if self.wtype.name in classnames: | |
| text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n" | |
| else: | |
| text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n" | |
| return text | |
| def gen_def(self): | |
| text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()" | |
| text += "\n\t{\n\t\t" | |
| if self.wtype.attr_type == attr_types.star: | |
| text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t" | |
| text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t" | |
| if self.wtype.name in known_containers: | |
| text += self.wtype.gen_text_cpp() | |
| else: | |
| text += self.wtype.gen_text() | |
| if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): | |
| text += "*" | |
| text += " ret_ = " | |
| if self.wtype.name in classnames: | |
| text += self.wtype.name + "::get_py_obj(" | |
| if self.wtype.attr_type != attr_types.star: | |
| text += "&" | |
| text += "this->get_cpp_obj()->" + self.name | |
| if self.wtype.name in classnames: | |
| text += ")" | |
| text += ";" | |
| if self.wtype.name in classnames: | |
| text += "\n\t\treturn *ret_;" | |
| elif self.wtype.name in known_containers: | |
| text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) | |
| text += "\n\t\treturn ret____tmp;" | |
| else: | |
| text += "\n\t\treturn ret_;" | |
| text += "\n\t}\n" | |
| if self.is_const: | |
| return text | |
| ret = Attribute(self.wtype, "rhs"); | |
| if self.wtype.name in classnames: | |
| text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" | |
| else: | |
| text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" | |
| text += "\n\t{" | |
| text += ret.gen_translation() | |
| text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";" | |
| text += "\n\t}\n" | |
| return text; | |
| def gen_boost_py(self): | |
| text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name | |
| if not self.is_const: | |
| text += ", &" + self.member_of.name + "::set_var_py_" + self.name | |
| text += ")" | |
| return text | |
| def concat_namespace(tuple_list): | |
| if len(tuple_list) == 0: | |
| return "" | |
| ret = "" | |
| for namespace in tuple_list: | |
| ret += "::" + namespace[0] | |
| return ret[2:] | |
| def calc_ident(text): | |
| if len(text) == 0 or text[0] != ' ': | |
| return 0 | |
| return calc_ident(text[1:]) + 1 | |
| def assure_length(text, length, left = False): | |
| if len(text) > length: | |
| return text[:length] | |
| if left: | |
| return text + " "*(length - len(text)) | |
| return " "*(length - len(text)) + text | |
| def parse_header(source): | |
| debug("Parsing " + source.name + ".pyh",1) | |
| source_file = open(source.name + ".pyh", "r") | |
| source_text = [] | |
| in_line = source_file.readline() | |
| namespaces = [] | |
| while(in_line): | |
| if(len(in_line)>1): | |
| source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p ")) | |
| in_line = source_file.readline() | |
| i = 0 | |
| namespaces = [] | |
| class_ = None | |
| private_segment = False | |
| while i < len(source_text): | |
| line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") | |
| ugly_line = unpretty_string(line) | |
| if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: | |
| namespace_name = ugly_line[10:].replace("{","").strip() | |
| namespaces.append((namespace_name, ugly_line.count("{"))) | |
| debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3) | |
| i += 1 | |
| continue | |
| if len(namespaces) != 0: | |
| namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}")) | |
| if namespaces[-1][1] == 0: | |
| debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) | |
| del namespaces[-1] | |
| i += 1 | |
| continue | |
| if class_ == None and (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0: | |
| struct_name = ugly_line.split(" ")[1].split("::")[-1] | |
| impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1] | |
| complete_namespace = concat_namespace(namespaces) | |
| for namespace in impl_namespaces: | |
| complete_namespace += "::" + namespace | |
| debug("\tFound " + struct_name + " in " + complete_namespace,2) | |
| class_ = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line)) | |
| if struct_name in classnames: | |
| class_[0].namespace = complete_namespace | |
| i += 1 | |
| continue | |
| if class_ != None: | |
| class_ = (class_[0], class_[1] + ugly_line.count("{") - ugly_line.count("}")) | |
| if class_[1] == 0: | |
| if class_[0] == None: | |
| debug("\tExiting unknown class", 3) | |
| else: | |
| debug("\tExiting class " + class_[0].name, 3) | |
| class_ = None | |
| private_segment = False | |
| i += 1 | |
| continue | |
| if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1): | |
| private_segment = True | |
| i += 1 | |
| continue | |
| if class_ != None and line.find("public:") != -1: | |
| private_segment = False | |
| i += 1 | |
| continue | |
| candidate = None | |
| if private_segment and class_ != None and class_[0] != None: | |
| candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True) | |
| if candidate != None: | |
| debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) | |
| class_[0].found_constrs.append(candidate) | |
| i += 1 | |
| continue | |
| if not private_segment and (class_ == None or class_[0] != None): | |
| if class_ != None: | |
| candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) | |
| else: | |
| candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) | |
| if candidate != None and candidate.name.find("::") == -1: | |
| if class_ == None: | |
| debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) | |
| unowned_functions.append(candidate) | |
| else: | |
| debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) | |
| class_[0].found_funs.append(candidate) | |
| else: | |
| candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i) | |
| if candidate != None: | |
| enums.append(candidate) | |
| debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) | |
| elif class_ != None and class_[1] == 1: | |
| candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i) | |
| if candidate != None: | |
| debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) | |
| class_[0].found_constrs.append(candidate) | |
| else: | |
| candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) | |
| if candidate != None: | |
| if type(candidate) == list: | |
| for c in candidate: | |
| debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2) | |
| class_[0].found_vars.extend(candidate) | |
| else: | |
| debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2) | |
| class_[0].found_vars.append(candidate) | |
| j = i | |
| line = unpretty_string(line) | |
| while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"): | |
| j += 1 | |
| line = line + "\n" + unpretty_string(source_text[j]) | |
| if class_ != None: | |
| candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) | |
| else: | |
| candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) | |
| if candidate != None and candidate.name.find("::") == -1: | |
| if class_ == None: | |
| debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) | |
| unowned_functions.append(candidate) | |
| else: | |
| debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) | |
| class_[0].found_funs.append(candidate) | |
| continue | |
| candidate = WEnum.from_string(line, concat_namespace(namespaces), i) | |
| if candidate != None: | |
| enums.append(candidate) | |
| debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) | |
| continue | |
| if class_ != None: | |
| candidate = WConstructor.from_string(line, source.name, class_[0], i) | |
| if candidate != None: | |
| debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) | |
| class_[0].found_constrs.append(candidate) | |
| continue | |
| if candidate != None: | |
| while i < j: | |
| i += 1 | |
| line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") | |
| ugly_line = unpretty_string(line) | |
| if len(namespaces) != 0: | |
| namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}")) | |
| if namespaces[-1][1] == 0: | |
| debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) | |
| del namespaces[-1] | |
| if class_ != None: | |
| class_ = (class_[0] , class_[1] + ugly_line.count("{") - ugly_line.count("}")) | |
| if class_[1] == 0: | |
| if class_[0] == None: | |
| debug("\tExiting unknown class", 3) | |
| else: | |
| debug("\tExiting class " + class_[0].name, 3) | |
| class_ = None | |
| private_segment = False | |
| i += 1 | |
| else: | |
| i += 1 | |
| def debug(message, level): | |
| if level <= debug.debug_level: | |
| print(message) | |
| def expand_function(f): | |
| fun_list = [] | |
| arg_list = [] | |
| for arg in f.args: | |
| if arg.default_value != None and (arg.wtype.name.split(" ")[-1] in primitive_types or arg.wtype.name in enum_names or (arg.wtype.name in classnames and arg.default_value == "nullptr")): | |
| fi = copy.deepcopy(f) | |
| fi.args = copy.deepcopy(arg_list) | |
| fun_list.append(fi) | |
| arg_list.append(arg) | |
| fun_list.append(f) | |
| return fun_list | |
| def expand_functions(): | |
| global unowned_functions | |
| new_funs = [] | |
| for fun in unowned_functions: | |
| new_funs.extend(expand_function(fun)) | |
| unowned_functions = new_funs | |
| for source in sources: | |
| for class_ in source.classes: | |
| new_funs = [] | |
| for fun in class_.found_funs: | |
| new_funs.extend(expand_function(fun)) | |
| class_.found_funs = new_funs | |
| def clean_duplicates(): | |
| for source in sources: | |
| for class_ in source.classes: | |
| known_decls = {} | |
| for fun in class_.found_funs: | |
| if fun.gen_decl_hash_py() in known_decls: | |
| debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) | |
| other = known_decls[fun.gen_decl_hash_py()] | |
| other.gen_alias() | |
| fun.gen_alias() | |
| if fun.gen_decl_hash_py() == other.gen_decl_hash_py(): | |
| fun.duplicate = True | |
| debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3) | |
| else: | |
| known_decls[fun.gen_decl_hash_py()] = fun | |
| known_decls = [] | |
| for con in class_.found_constrs: | |
| if con.gen_decl_hash_py() in known_decls: | |
| debug("Multiple declarations of " + con.gen_decl_hash_py(),3) | |
| con.duplicate = True | |
| else: | |
| known_decls.append(con.gen_decl_hash_py()) | |
| known_decls = [] | |
| for fun in unowned_functions: | |
| if fun.gen_decl_hash_py() in known_decls: | |
| debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) | |
| fun.duplicate = True | |
| else: | |
| known_decls.append(fun.gen_decl_hash_py()) | |
| def gen_wrappers(filename, debug_level_ = 0): | |
| debug.debug_level = debug_level_ | |
| for source in sources: | |
| parse_header(source) | |
| expand_functions() | |
| clean_duplicates() | |
| import shutil | |
| import math | |
| col = shutil.get_terminal_size((80,20)).columns | |
| debug("-"*col, 1) | |
| debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1) | |
| debug("-"*col, 1) | |
| for source in sources: | |
| for class_ in source.classes: | |
| debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1) | |
| if len(class_.found_constrs) == 0: | |
| class_.found_constrs.append(WConstructor(source.name, class_)) | |
| debug(str(len(unowned_functions)) + " functions are unowned", 1) | |
| for enum in enums: | |
| debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1) | |
| debug("-"*col, 1) | |
| wrapper_file = open(filename, "w+") | |
| wrapper_file.write( | |
| """/* | |
| * yosys -- Yosys Open SYnthesis Suite | |
| * | |
| * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> | |
| * | |
| * Permission to use, copy, modify, and/or distribute this software for any | |
| * purpose with or without fee is hereby granted, provided that the above | |
| * copyright notice and this permission notice appear in all copies. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| * | |
| * This is a generated file and can be overwritten by make | |
| */ | |
| #ifdef WITH_PYTHON | |
| """) | |
| for source in sources: | |
| wrapper_file.write("#include \""+source.name+".h\"\n") | |
| wrapper_file.write(""" | |
| #include <boost/python/module.hpp> | |
| #include <boost/python/class.hpp> | |
| #include <boost/python/wrapper.hpp> | |
| #include <boost/python/call.hpp> | |
| #include <boost/python.hpp> | |
| USING_YOSYS_NAMESPACE | |
| namespace YOSYS_PYTHON { | |
| """) | |
| for source in sources: | |
| for wclass in source.classes: | |
| wrapper_file.write("\n\tstruct " + wclass.name + ";") | |
| wrapper_file.write("\n") | |
| for source in sources: | |
| for wclass in source.classes: | |
| wrapper_file.write(wclass.gen_decl(source.name)) | |
| wrapper_file.write("\n") | |
| for source in sources: | |
| for wclass in source.classes: | |
| wrapper_file.write(wclass.gen_funs(source.name)) | |
| for fun in unowned_functions: | |
| wrapper_file.write(fun.gen_def()) | |
| wrapper_file.write(""" struct Initializer | |
| { | |
| Initializer() { | |
| if(!Yosys::yosys_already_setup()) | |
| { | |
| Yosys::log_streams.push_back(&std::cout); | |
| Yosys::log_error_stderr = true; | |
| Yosys::yosys_setup(); | |
| } | |
| } | |
| Initializer(Initializer const &) {} | |
| ~Initializer() { | |
| Yosys::yosys_shutdown(); | |
| } | |
| }; | |
| BOOST_PYTHON_MODULE(libyosys) | |
| { | |
| using namespace boost::python; | |
| class_<Initializer>("Initializer"); | |
| scope().attr("_hidden") = new Initializer(); | |
| """) | |
| for enum in enums: | |
| wrapper_file.write(enum.gen_boost_py()) | |
| for source in sources: | |
| for wclass in source.classes: | |
| wrapper_file.write(wclass.gen_boost_py()) | |
| for fun in unowned_functions: | |
| wrapper_file.write(fun.gen_boost_py()) | |
| wrapper_file.write("\n\t}\n}\n#endif") | |
| def print_includes(): | |
| for source in sources: | |
| print(source.name + ".pyh") |