| # |
| # 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 |
| if candidate.name == "void": |
| 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_body(self): |
| text = "" |
| 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 gen_boost_py(self): |
| body = self.gen_boost_py_body() |
| if self.link_type == link_types.derive: |
| text = "\n\t\tclass_<" + self.name + ">(\"Cpp" + self.name + "\"" |
| text += body |
| text += "\n\t\tclass_<" + self.name |
| text += "Wrap, boost::noncopyable" |
| text += ">(\"" + self.name + "\"" |
| text += body |
| else: |
| text = "\n\t\tclass_<" + self.name + ">(\"" + self.name + "\"" |
| text += body |
| 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 |
| glbls = [] |
| |
| 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 |
| |
| class WGlobal: |
| orig_text = None |
| wtype = attr_types.default |
| name = None |
| containing_file = None |
| namespace = "" |
| is_const = False |
| |
| def from_string(str_def, containing_file, line_number, namespace): |
| glbl = WGlobal() |
| glbl.orig_text = str_def |
| glbl.wtype = None |
| glbl.name = "" |
| glbl.containing_file = containing_file |
| glbl.namespace = namespace |
| glbl.is_const = False |
| |
| if not str.startswith(str_def, "extern"): |
| return None |
| str_def = str_def[7:] |
| |
| if str.startswith(str_def, "const "): |
| glbl.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 |
| |
| glbl.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) |
| |
| if glbl.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 |
| |
| glbl.name = str_def[:found] |
| str_def = str_def[found+1:] |
| if glbl.name.find("*") == 0: |
| glbl.name = glbl.name.replace("*", "") |
| glbl.wtype.attr_type = attr_types.star |
| if glbl.name.find("&&") == 0: |
| glbl.name = glbl.name.replace("&&", "") |
| glbl.wtype.attr_type = attr_types.ampamp |
| if glbl.name.find("&") == 0: |
| glbl.name = glbl.name.replace("&", "") |
| glbl.wtype.attr_type = attr_types.amp |
| |
| if(len(str_def.strip()) != 0): |
| return None |
| |
| if len(glbl.name.split(",")) > 1: |
| glbl_list = [] |
| for name in glbl.name.split(","): |
| name = name.strip(); |
| glbl_list.append(WGlobal()) |
| glbl_list[-1].orig_text = glbl.orig_text |
| glbl_list[-1].wtype = glbl.wtype |
| glbl_list[-1].name = name |
| glbl_list[-1].containing_file = glbl.containing_file |
| glbl_list[-1].namespace = glbl.namespace |
| glbl_list[-1].is_const = glbl.is_const |
| return glbl_list |
| |
| return glbl |
| |
| def gen_def(self): |
| text = "\n\t" |
| if self.is_const: |
| text += "const " |
| text += self.wtype.gen_text() + " get_var_py_" + self.name + "()" |
| text += "\n\t{\n\t\t" |
| if self.wtype.attr_type == attr_types.star: |
| text += "if(" + self.namespace + "::" + self.name + " == NULL)\n\t\t\t" |
| text += "throw std::runtime_error(\"" + self.namespace + "::" + self.name + " is NULL\");\n\t\t" |
| if self.wtype.name in known_containers: |
| text += self.wtype.gen_text_cpp() |
| else: |
| if self.is_const: |
| text += "const " |
| 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 += self.namespace + "::" + 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 set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" |
| else: |
| text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" |
| text += "\n\t{" |
| text += ret.gen_translation() |
| text += "\n\t\t" + self.namespace + "::" + self.name + " = " + ret.gen_call() + ";" |
| text += "\n\t}\n" |
| |
| return text; |
| |
| def gen_boost_py(self): |
| text = "\n\t\t\t.add_static_property(\"" + self.name + "\", &" + "YOSYS_PYTHON::get_var_py_" + self.name |
| if not self.is_const: |
| text += ", &YOSYS_PYTHON::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) |
| if candidate == None and class_ == None: |
| candidate = WGlobal.from_string(ugly_line, source.name, i, concat_namespace(namespaces)) |
| if candidate != None: |
| if type(candidate) == list: |
| for c in candidate: |
| glbls.append(c) |
| debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2) |
| else: |
| glbls.append(candidate) |
| debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2) |
| |
| 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 class_ == None: |
| candidate = WGlobal.from_string(line, source.name, i, concat_namespace(namespaces)) |
| if candidate != None: |
| if type(candidate) == list: |
| for c in candidate: |
| glbls.append(c) |
| debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2) |
| else: |
| glbls.append(candidate) |
| debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2) |
| 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) |
| debug(str(len(unowned_functions)) + " global variables", 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> |
| #include <iosfwd> // std::streamsize |
| #include <iostream> |
| #include <boost/iostreams/concepts.hpp> // boost::iostreams::sink |
| #include <boost/iostreams/stream.hpp> |
| USING_YOSYS_NAMESPACE |
| |
| namespace YOSYS_PYTHON { |
| |
| struct YosysStatics{}; |
| """) |
| |
| 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()) |
| |
| for glbl in glbls: |
| wrapper_file.write(glbl.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(); |
| } |
| }; |
| |
| |
| /// source: https://stackoverflow.com/questions/26033781/converting-python-io-object-to-stdostream-when-using-boostpython?noredirect=1&lq=1 |
| /// @brief Type that implements the Boost.IOStream's Sink and Flushable |
| /// concept for writing data to Python object that support: |
| /// n = object.write(str) # n = None or bytes written |
| /// object.flush() # if flush exists, then it is callable |
| class PythonOutputDevice |
| { |
| public: |
| |
| // This class models both the Sink and Flushable concepts. |
| struct category |
| : boost::iostreams::sink_tag, |
| boost::iostreams::flushable_tag |
| {}; |
| |
| explicit |
| PythonOutputDevice(boost::python::object object) |
| : object_(object) |
| {} |
| |
| // Sink concept. |
| public: |
| |
| typedef char char_type; |
| |
| std::streamsize write(const char* buffer, std::streamsize buffer_size) |
| { |
| namespace python = boost::python; |
| // Copy the buffer to a python string. |
| python::str data(buffer, buffer_size); |
| |
| // Invoke write on the python object, passing in the data. The following |
| // is equivalent to: |
| // n = object_.write(data) |
| python::extract<std::streamsize> bytes_written( |
| object_.attr("write")(data)); |
| |
| // Per the Sink concept, return the number of bytes written. If the |
| // Python return value provides a numeric result, then use it. Otherwise, |
| // such as the case of a File object, use the buffer_size. |
| return bytes_written.check() |
| ? bytes_written |
| : buffer_size; |
| } |
| |
| // Flushable concept. |
| public: |
| |
| bool flush() |
| { |
| // If flush exists, then call it. |
| boost::python::object flush = object_.attr("flush"); |
| if (!flush.is_none()) |
| { |
| flush(); |
| } |
| |
| // Always return true. If an error occurs, an exception should be thrown. |
| return true; |
| } |
| |
| private: |
| boost::python::object object_; |
| }; |
| |
| /// @brief Use an auxiliary function to adapt the legacy function. |
| void log_to_stream(boost::python::object object) |
| { |
| // Create an ostream that delegates to the python object. |
| boost::iostreams::stream<PythonOutputDevice>* output = new boost::iostreams::stream<PythonOutputDevice>(object); |
| Yosys::log_streams.insert(Yosys::log_streams.begin(), output); |
| }; |
| |
| |
| BOOST_PYTHON_MODULE(libyosys) |
| { |
| using namespace boost::python; |
| |
| class_<Initializer>("Initializer"); |
| scope().attr("_hidden") = new Initializer(); |
| |
| def("log_to_stream", &log_to_stream); |
| """) |
| |
| 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\n\t\tclass_<YosysStatics>(\"Yosys\")\n") |
| for glbl in glbls: |
| wrapper_file.write(glbl.gen_boost_py()) |
| wrapper_file.write("\t\t;\n") |
| |
| wrapper_file.write("\n\t}\n}\n#endif") |
| |
| def print_includes(): |
| for source in sources: |
| print(source.name + ".pyh") |