added py_wrap_generator
authorBenedikt Tutzer <e1225461@student.tuwien.ac.at>
Thu, 25 Oct 2018 10:27:56 +0000 (12:27 +0200)
committerBenedikt Tutzer <e1225461@student.tuwien.ac.at>
Thu, 25 Oct 2018 10:27:56 +0000 (12:27 +0200)
py_wrap_generator.py [new file with mode: 0644]

diff --git a/py_wrap_generator.py b/py_wrap_generator.py
new file mode 100644 (file)
index 0000000..204b914
--- /dev/null
@@ -0,0 +1,2098 @@
+#
+#  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):
+               text  = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + varname + ".first, " + varname + ".second);"
+               return text
+               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.split(" ")[-1] in primitive_types or types[0].name in enum_names:
+                       text += prefix + "\t" + varname + "___tmp.append(" + 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[1].attr_type == attr_types.star)
+                       text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "___tmp);"
+               elif types[0].name in classnames:
+                       text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));"
+               text += prefix + "}"
+               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\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"
+
+                       if self.link_type != link_types.global_list:
+                               text += "\n\t\t~" + self.name + "()\n\t\t{"
+                               text += "\n\t\t\tdelete(this->ref_obj);\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::Pass::run_register", "Yosys::Module::Pow", "Yosys::Module::Bu0", "Yosys::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 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 = 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 = 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.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{").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 = 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 = 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 = 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 = i + 1
+                               continue
+
+               if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1):
+                       private_segment = True
+                       i = i + 1
+                       continue
+               if class_ != None and line.find("public:") != -1:
+                       private_segment = False
+                       i = 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 = 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 = 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 = i + 1
+                               line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", "                    namespace Yosys{").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 = i + 1
+                       #i = j + 1
+               else:
+                       i = 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_ = 30):
+       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>
+#include <boost/log/exceptions.hpp>
+
+using namespace Yosys;
+
+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();
+                               Yosys::yosys_banner();
+                       }
+               }
+
+               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")