PY_WRAPPER_FILE = kernel/python_wrappers
OBJS += $(PY_WRAPPER_FILE).o
PY_GEN_SCRIPT= py_wrap_generator
-PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
+PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
endif
ifeq ($(ENABLE_READLINE),1)
$(Q) mkdir -p $(dir $@)
$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P -
-$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
+$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
$(Q) mkdir -p $(dir $@)
- $(P) python$(PYTHON_VERSION) -c "import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
+ $(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
%.o: %.cpp
$(Q) mkdir -p $(dir $@)
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys
- $(INSTALL_SUDO) cp __init__.py $(PYTHON_DESTDIR)/pyosys
+ $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys
endif
endif
+++ /dev/null
-import os
-import sys
-sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
-
-__all__ = ["libyosys"]
--- /dev/null
+import os
+import sys
+sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
+
+__all__ = ["libyosys"]
--- /dev/null
+#
+# 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"
+
+ for con in self.found_constrs:
+ text += con.gen_decl()
+ for var in self.found_vars:
+ text += var.gen_decl()
+ for fun in self.found_funs:
+ text += fun.gen_decl()
+
+
+ if self.link_type == link_types.derive:
+ duplicates = {}
+ for fun in self.found_funs:
+ if fun.name in duplicates:
+ fun.gen_alias()
+ duplicates[fun.name].gen_alias()
+ else:
+ duplicates[fun.name] = fun
+
+ text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn (" + self.namespace + "::" + self.name +"*)this;\n\t\t}\n"
+ text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{"
+ text += "\n\t\t\treturn (" + self.name + "*)ref;"
+ text += "\n\t\t}\n"
+
+ for con in self.found_constrs:
+ text += con.gen_decl_derive()
+ for var in self.found_vars:
+ text += var.gen_decl()
+ for fun in self.found_funs:
+ text += fun.gen_decl_virtual()
+
+ if self.hash_id != None:
+ text += "\n\t\tunsigned int get_hash_py()"
+ text += "\n\t\t{"
+ text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";"
+ text += "\n\t\t}"
+
+ text += "\n\t};\n"
+
+ if self.link_type == link_types.derive:
+ text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">"
+ text += "\n\t{"
+
+ for con in self.found_constrs:
+ text += con.gen_decl_wrapperclass()
+ for fun in self.found_funs:
+ text += fun.gen_default_impl()
+
+ text += "\n\t};"
+
+ text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)"
+ text += "\n\t{"
+ text += "\n\t\tostr << \"" + self.name
+ if self.string_id != None:
+ text +=" \\\"\""
+ text += " << ref.get_cpp_obj()->" + self.string_id
+ text += " << \"\\\"\""
+ else:
+ text += " at \" << ref.get_cpp_obj()"
+ text += ";"
+ text += "\n\t\treturn ostr;"
+ text += "\n\t}"
+ text += "\n"
+
+ return text
+
+ def gen_funs(self, filename):
+ text = ""
+ if self.link_type != link_types.derive:
+ for con in self.found_constrs:
+ text += con.gen_def()
+ for var in self.found_vars:
+ text += var.gen_def()
+ for fun in self.found_funs:
+ text += fun.gen_def()
+ else:
+ for var in self.found_vars:
+ text += var.gen_def()
+ for fun in self.found_funs:
+ text += fun.gen_def_virtual()
+ return text
+
+ def gen_boost_py(self):
+ text = "\n\t\tclass_<" + self.name
+ if self.link_type == link_types.derive:
+ text += "Wrap, boost::noncopyable"
+ text += ">(\"" + self.name + "\""
+ if self.printable_constrs() == 0 or not self.contains_default_constr():
+ text += ", no_init"
+ text += ")"
+ text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))"
+ text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))"
+ for con in self.found_constrs:
+ text += con.gen_boost_py()
+ for var in self.found_vars:
+ text += var.gen_boost_py()
+ static_funs = []
+ for fun in self.found_funs:
+ text += fun.gen_boost_py()
+ if fun.is_static and fun.alias not in static_funs:
+ static_funs.append(fun.alias)
+ for fun in static_funs:
+ text += "\n\t\t\t.staticmethod(\"" + fun + "\")"
+
+ if self.hash_id != None:
+ text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)"
+ text += "\n\t\t\t;\n"
+ return text
+
+ def contains_default_constr(self):
+ for c in self.found_constrs:
+ if len(c.args) == 0:
+ return True
+ return False
+
+#CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE
+
+sources = [
+ Source("kernel/celltypes",[
+ WClass("CellType", link_types.pointer, None, None, "type.hash()", True),
+ WClass("CellTypes", link_types.pointer, None, None, None, True)
+ ]
+ ),
+ Source("kernel/consteval",[
+ WClass("ConstEval", link_types.pointer, None, None, None, True)
+ ]
+ ),
+ Source("kernel/log",[]),
+ Source("kernel/register",[
+ WClass("Pass", link_types.derive, None, None, None, True),
+ ]
+ ),
+ Source("kernel/rtlil",[
+ WClass("IdString", link_types.ref_copy, None, "str()", "hash()"),
+ WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"),
+ WClass("AttrObject", link_types.ref_copy, None, None, None),
+ WClass("Selection", link_types.ref_copy, None, None, None),
+ WClass("Monitor", link_types.derive, None, None, None),
+ WClass("CaseRule",link_types.ref_copy, None, None, None, True),
+ WClass("SwitchRule",link_types.ref_copy, None, None, None, True),
+ WClass("SyncRule", link_types.ref_copy, None, None, None, True),
+ WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"),
+ WClass("SigChunk", link_types.ref_copy, None, None, None),
+ WClass("SigBit", link_types.ref_copy, None, None, "hash()"),
+ WClass("SigSpec", link_types.ref_copy, None, None, "hash()"),
+ WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
+ WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
+ WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
+ WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
+ WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()")
+ ]
+ ),
+ #Source("kernel/satgen",[
+ # ]
+ # ),
+ #Source("libs/ezsat/ezsat",[
+ # ]
+ # ),
+ #Source("libs/ezsat/ezminisat",[
+ # ]
+ # ),
+ Source("kernel/sigtools",[
+ WClass("SigMap", link_types.pointer, None, None, None, True)
+ ]
+ ),
+ Source("kernel/yosys",[
+ ]
+ ),
+ Source("kernel/cost",[])
+ ]
+
+blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow", "YOSYS_NAMESPACE::Module::Bu0", "YOSYS_NAMESPACE::CaseRule::optimize"]
+
+enum_names = ["State","SyncType","ConstFlags"]
+
+enums = [] #Do not edit
+
+unowned_functions = []
+
+classnames = []
+for source in sources:
+ for wclass in source.classes:
+ classnames.append(wclass.name)
+
+def class_by_name(name):
+ for source in sources:
+ for wclass in source.classes:
+ if wclass.name == name:
+ return wclass
+ return None
+
+def enum_by_name(name):
+ for e in enums:
+ if e.name == name:
+ return e
+ return None
+
+def find_closing(text, open_tok, close_tok):
+ if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok):
+ return text.find(close_tok)
+ return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1
+
+def unpretty_string(s):
+ s = s.strip()
+ while s.find(" ") != -1:
+ s = s.replace(" "," ")
+ while s.find("\t") != -1:
+ s = s.replace("\t"," ")
+ s = s.replace(" (","(")
+ return s
+
+class WEnum:
+ name = None
+ namespace = None
+ values = []
+
+ def from_string(str_def, namespace, line_number):
+ str_def = str_def.strip()
+ if not str.startswith(str_def, "enum "):
+ return None
+ if str_def.count(";") != 1:
+ return None
+ str_def = str_def[5:]
+ enum = WEnum()
+ split = str_def.split(":")
+ if(len(split) != 2):
+ return None
+ enum.name = split[0].strip()
+ if enum.name not in enum_names:
+ return None
+ str_def = split[1]
+ if str_def.count("{") != str_def.count("}") != 1:
+ return None
+ if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';':
+ return None
+ str_def = str_def.split("{")[-1].split("}")[0]
+ enum.values = []
+ for val in str_def.split(','):
+ enum.values.append(val.strip().split('=')[0].strip())
+ enum.namespace = namespace
+ return enum
+
+ def gen_boost_py(self):
+ text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n"
+ for value in self.values:
+ text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n"
+ text += "\t\t\t;\n"
+ return text
+
+ def __str__(self):
+ ret = "Enum " + self.namespace + "::" + self.name + "(\n"
+ for val in self.values:
+ ret = ret + "\t" + val + "\n"
+ return ret + ")"
+
+ def __repr__(self):
+ return __str__(self)
+
+class WConstructor:
+ orig_text = None
+ args = []
+ containing_file = None
+ member_of = None
+ duplicate = False
+ protected = False
+
+ def __init__(self, containing_file, class_):
+ self.orig_text = "Auto generated default constructor"
+ self.args = []
+ self.containing_file = containing_file
+ self.member_of = class_
+ self.protected = False
+
+ def from_string(str_def, containing_file, class_, line_number, protected = False):
+ if class_ == None:
+ return None
+ if str_def.count("delete;") > 0:
+ return None
+ con = WConstructor(containing_file, class_)
+ con.orig_text = str_def
+ con.args = []
+ con.duplicate = False
+ con.protected = protected
+ if not str.startswith(str_def, class_.name + "("):
+ return None
+ str_def = str_def[len(class_.name)+1:]
+ found = find_closing(str_def, "(", ")")
+ if found == -1:
+ return None
+ str_def = str_def[0:found].strip()
+ if len(str_def) == 0:
+ return con
+ for arg in split_list(str_def, ","):
+ parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
+ if parsed == None:
+ return None
+ con.args.append(parsed)
+ return con
+
+ def gen_decl(self):
+ if self.duplicate or self.protected:
+ return ""
+ text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t\t" + self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_listitem() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ");\n"
+ return text
+
+ def gen_decl_derive(self):
+ if self.duplicate or self.protected:
+ return ""
+ text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t\t" + self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_listitem() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ")"
+ if len(self.args) == 0:
+ return text + "{}"
+ text += " : "
+ text += self.member_of.namespace + "::" + self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_call() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += "){}\n"
+ return text
+
+ def gen_decl_wrapperclass(self):
+ if self.duplicate or self.protected:
+ return ""
+ text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t\t" + self.member_of.name + "Wrap("
+ for arg in self.args:
+ text += arg.gen_listitem() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ")"
+ if len(self.args) == 0:
+ return text + "{}"
+ text += " : "
+ text += self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_call() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += "){}\n"
+ return text
+
+ def gen_decl_hash_py(self):
+ text = self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_listitem_hash() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ");"
+ return text
+
+ def gen_def(self):
+ if self.duplicate or self.protected:
+ return ""
+ text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_listitem() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text +=")\n\t{"
+ for arg in self.args:
+ text += arg.gen_translation()
+ if self.member_of.link_type != link_types.derive:
+ text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "("
+ for arg in self.args:
+ text += arg.gen_call() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ if self.member_of.link_type != link_types.derive:
+ text += ");"
+ if self.member_of.link_type == link_types.global_list:
+ text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";"
+ for arg in self.args:
+ text += arg.gen_cleanup()
+ text += "\n\t}\n"
+ return text
+
+ def gen_boost_py(self):
+ if self.duplicate or self.protected or len(self.args) == 0:
+ return ""
+ text = "\n\t\t\t.def(init"
+ text += "<"
+ for a in self.args:
+ text += a.gen_listitem_hash() + ", "
+ text = text[0:-2] + ">())"
+ return text
+
+class WFunction:
+ orig_text = None
+ is_static = False
+ is_inline = False
+ is_virtual = False
+ ret_attr_type = attr_types.default
+ is_operator = False
+ ret_type = None
+ name = None
+ alias = None
+ args = []
+ containing_file = None
+ member_of = None
+ duplicate = False
+ namespace = ""
+
+ def from_string(str_def, containing_file, class_, line_number, namespace):
+ if str_def.count("delete;") > 0:
+ return None
+ func = WFunction()
+ func.is_static = False
+ func.is_inline = False
+ func.is_virtual = False
+ func.ret_attr_type = attr_types.default
+ func.is_operator = False
+ func.member_of = None
+ func.orig_text = str_def
+ func.args = []
+ func.containing_file = containing_file
+ func.member_of = class_
+ func.duplicate = False
+ func.namespace = namespace
+ str_def = str_def.replace("operator ","operator")
+ if str.startswith(str_def, "static "):
+ func.is_static = True
+ str_def = str_def[7:]
+ else:
+ func.is_static = False
+ if str.startswith(str_def, "inline "):
+ func.is_inline = True
+ str_def = str_def[7:]
+ else:
+ func.is_inline = False
+ if str.startswith(str_def, "virtual "):
+ func.is_virtual = True
+ str_def = str_def[8:]
+ else:
+ func.is_virtual = False
+
+ if str_def.count(" ") == 0:
+ return None
+
+ parts = split_list(str_def.strip(), " ")
+
+ prefix = ""
+ i = 0
+ for part in parts:
+ if part in ["unsigned", "long", "short"]:
+ prefix += part + " "
+ i += 1
+ else:
+ break
+ parts = parts[i:]
+
+ if len(parts) <= 1:
+ return None
+
+ func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number)
+
+ if func.ret_type == None:
+ return None
+
+ str_def = parts[1]
+ for part in parts[2:]:
+ str_def = str_def + " " + part
+
+ found = str_def.find("(")
+ if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")):
+ return None
+ func.name = str_def[:found]
+ str_def = str_def[found:]
+ if func.name.find("operator") != -1 and str.startswith(str_def, "()("):
+ func.name += "()"
+ str_def = str_def[2:]
+ str_def = str_def[1:]
+ if func.name.find("operator") != -1:
+ func.is_operator = True
+ if func.name.find("*") == 0:
+ func.name = func.name.replace("*", "")
+ func.ret_type.attr_type = attr_types.star
+ if func.name.find("&&") == 0:
+ func.name = func.name.replace("&&", "")
+ func.ret_type.attr_type = attr_types.ampamp
+ if func.name.find("&") == 0:
+ func.name = func.name.replace("&", "")
+ func.ret_type.attr_type = attr_types.amp
+
+ found = find_closing(str_def, "(", ")")
+ if found == -1:
+ return None
+ str_def = str_def[0:found]
+ if func.name in blacklist_methods:
+ return None
+ if func.namespace != None and func.namespace != "":
+ if (func.namespace + "::" + func.name) in blacklist_methods:
+ return None
+ if func.member_of != None:
+ if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods:
+ return None
+ if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators:
+ return None
+
+ testname = func.name
+ if func.is_operator:
+ testname = testname[:testname.find("operator")]
+ if testname.count(")") != 0 or testname.count("(") != 0 or testname.count("~") != 0 or testname.count(";") != 0 or testname.count(">") != 0 or testname.count("<") != 0 or testname.count("throw") != 0:
+ return None
+
+ func.alias = func.name
+ if func.name in keyword_aliases:
+ func.alias = keyword_aliases[func.name]
+ str_def = str_def[:found].strip()
+ if(len(str_def) == 0):
+ return func
+ for arg in split_list(str_def, ","):
+ if arg.strip() == "...":
+ continue
+ parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
+ if parsed == None:
+ return None
+ func.args.append(parsed)
+ return func
+
+ def gen_alias(self):
+ self.alias = self.name
+ for arg in self.args:
+ self.alias += "__" + arg.wtype.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","")
+
+ def gen_decl(self):
+ if self.duplicate:
+ return ""
+ text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t\t"
+ if self.is_static:
+ text += "static "
+ text += self.ret_type.gen_text() + " " + self.alias + "("
+ for arg in self.args:
+ text += arg.gen_listitem()
+ text += ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ");\n"
+ return text
+
+ def gen_decl_virtual(self):
+ if self.duplicate:
+ return ""
+ if not self.is_virtual:
+ return self.gen_decl()
+ text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t\tvirtual "
+ if self.is_static:
+ text += "static "
+ text += self.ret_type.gen_text() + " py_" + self.alias + "("
+ for arg in self.args:
+ text += arg.gen_listitem()
+ text += ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ")"
+ if len(self.args) == 0:
+ text += "{}"
+ else:
+ text += "\n\t\t{"
+ for arg in self.args:
+ text += "\n\t\t\t(void)" + arg.gen_varname() + ";"
+ text += "\n\t\t}\n"
+ text += "\n\t\tvirtual "
+ if self.is_static:
+ text += "static "
+ text += self.ret_type.gen_text() + " " + self.name + "("
+ for arg in self.args:
+ text += arg.gen_listitem_cpp()
+ text += ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ") YS_OVERRIDE;\n"
+ return text
+
+ def gen_decl_hash_py(self):
+ text = self.ret_type.gen_text() + " " + self.alias + "("
+ for arg in self.args:
+ text += arg.gen_listitem_hash() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ");"
+ return text
+
+ def gen_def(self):
+ if self.duplicate:
+ return ""
+ text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t" + self.ret_type.gen_text() + " "
+ if self.member_of != None:
+ text += self.member_of.name + "::"
+ text += self.alias + "("
+ for arg in self.args:
+ text += arg.gen_listitem()
+ text += ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text +=")\n\t{"
+ for arg in self.args:
+ text += arg.gen_translation()
+ text += "\n\t\t"
+ if self.ret_type.name != "void":
+ if self.ret_type.name in known_containers:
+ text += self.ret_type.gen_text_cpp()
+ else:
+ text += self.ret_type.gen_text()
+ if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star):
+ text += "*"
+ text += " ret_ = "
+ if self.ret_type.name in classnames:
+ text += self.ret_type.name + "::get_py_obj("
+ if self.member_of == None:
+ text += "::" + self.namespace + "::" + self.alias + "("
+ elif self.is_static:
+ text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "("
+ else:
+ text += "this->get_cpp_obj()->" + self.name + "("
+ for arg in self.args:
+ text += arg.gen_call() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ if self.ret_type.name in classnames:
+ text += ")"
+ text += ");"
+ for arg in self.args:
+ text += arg.gen_cleanup()
+ if self.ret_type.name != "void":
+ if self.ret_type.name in classnames:
+ text += "\n\t\treturn *ret_;"
+ elif self.ret_type.name in known_containers:
+ text += known_containers[self.ret_type.name].translate_cpp("ret_", self.ret_type.cont.args, "\n\t\t", self.ret_type.attr_type == attr_types.star)
+ text += "\n\t\treturn ret____tmp;"
+ else:
+ text += "\n\t\treturn ret_;"
+ text += "\n\t}\n"
+ return text
+
+ def gen_def_virtual(self):
+ if self.duplicate:
+ return ""
+ if not self.is_virtual:
+ return self.gen_def()
+ text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
+ text += "\n\t"
+ if self.is_static:
+ text += "static "
+ text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "("
+ for arg in self.args:
+ text += arg.gen_listitem_cpp()
+ text += ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ")\n\t{"
+ for arg in self.args:
+ text += arg.gen_translation_cpp()
+ text += "\n\t\t"
+ if self.member_of == None:
+ text += "::" + self.namespace + "::" + self.alias + "("
+ elif self.is_static:
+ text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "("
+ else:
+ text += "py_" + self.alias + "("
+ for arg in self.args:
+ text += arg.gen_call_cpp() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ if self.ret_type.name in classnames:
+ text += ")"
+ text += ");"
+ for arg in self.args:
+ text += arg.gen_cleanup()
+ text += "\n\t}\n"
+ return text
+
+ def gen_default_impl(self):
+ if self.duplicate:
+ return ""
+ if not self.is_virtual:
+ return ""
+ text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "("
+ for arg in self.args:
+ text += arg.gen_listitem() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+
+ call_string = "py_" + self.alias + "("
+ for arg in self.args:
+ call_string += arg.gen_varname() + ", "
+ if len(self.args) > 0:
+ call_string = call_string[0:-2]
+ call_string += ");"
+
+ text += ")\n\t\t{"
+ text += "\n\t\t\tif(boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))"
+ text += "\n\t\t\t\t" + call_string
+ text += "\n\t\t\telse"
+ text += "\n\t\t\t\t" + self.member_of.name + "::" + call_string
+ text += "\n\t\t}"
+
+ text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "("
+ for arg in self.args:
+ text += arg.gen_listitem() + ", "
+ if len(self.args) > 0:
+ text = text[:-2]
+ text += ")\n\t\t{"
+ text += "\n\t\t\tthis->" + self.member_of.name + "::" + call_string
+ text += "\n\t\t}"
+ return text
+
+
+ def gen_boost_py(self):
+ if self.duplicate:
+ return ""
+ if self.member_of == None:
+ text = "\n\t\tdef"
+ else:
+ text = "\n\t\t\t.def"
+ if len(self.args) > -1:
+ if self.ret_type.name in known_containers:
+ text += "<" + known_containers[self.ret_type.name].typename + " "
+ else:
+ text += "<" + self.ret_type.name + " "
+ if self.member_of == None or self.is_static:
+ text += "(*)("
+ else:
+ text += "(" + self.member_of.name + "::*)("
+ for a in self.args:
+ text += a.gen_listitem_hash() + ", "
+ if len(self.args) > 0:
+ text = text[0:-2] + ")>"
+ else:
+ text += "void)>"
+
+ if self.is_operator:
+ text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\""
+ else:
+ if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual:
+ text += "(\"py_" + self.alias + "\""
+ else:
+ text += "(\"" + self.alias + "\""
+ if self.member_of != None:
+ text += ", &" + self.member_of.name + "::"
+ if self.member_of.link_type == link_types.derive and self.is_virtual:
+ text += "py_" + self.alias
+ text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias
+ else:
+ text += self.alias
+
+ text += ")"
+ else:
+ text += ", " + "YOSYS_PYTHON::" + self.alias + ");"
+ return text
+
+class WMember:
+ orig_text = None
+ wtype = attr_types.default
+ name = None
+ containing_file = None
+ member_of = None
+ namespace = ""
+ is_const = False
+
+ def from_string(str_def, containing_file, class_, line_number, namespace):
+ member = WMember()
+ member.orig_text = str_def
+ member.wtype = None
+ member.name = ""
+ member.containing_file = containing_file
+ member.member_of = class_
+ member.namespace = namespace
+ member.is_const = False
+
+ if str.startswith(str_def, "const "):
+ member.is_const = True
+ str_def = str_def[6:]
+
+ if str_def.count(" ") == 0:
+ return None
+
+ parts = split_list(str_def.strip(), " ")
+
+ prefix = ""
+ i = 0
+ for part in parts:
+ if part in ["unsigned", "long", "short"]:
+ prefix += part + " "
+ i += 1
+ else:
+ break
+ parts = parts[i:]
+
+ if len(parts) <= 1:
+ return None
+
+ member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number)
+
+ if member.wtype == None:
+ return None
+
+ str_def = parts[1]
+ for part in parts[2:]:
+ str_def = str_def + " " + part
+
+ if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1:
+ return None
+
+ found = str_def.find(";")
+ if found == -1:
+ return None
+
+ found_eq = str_def.find("=")
+ if found_eq != -1:
+ found = found_eq
+
+ member.name = str_def[:found]
+ str_def = str_def[found+1:]
+ if member.name.find("*") == 0:
+ member.name = member.name.replace("*", "")
+ member.wtype.attr_type = attr_types.star
+ if member.name.find("&&") == 0:
+ member.name = member.name.replace("&&", "")
+ member.wtype.attr_type = attr_types.ampamp
+ if member.name.find("&") == 0:
+ member.name = member.name.replace("&", "")
+ member.wtype.attr_type = attr_types.amp
+
+ if(len(str_def.strip()) != 0):
+ return None
+
+ if len(member.name.split(",")) > 1:
+ member_list = []
+ for name in member.name.split(","):
+ name = name.strip();
+ member_list.append(WMember())
+ member_list[-1].orig_text = member.orig_text
+ member_list[-1].wtype = member.wtype
+ member_list[-1].name = name
+ member_list[-1].containing_file = member.containing_file
+ member_list[-1].member_of = member.member_of
+ member_list[-1].namespace = member.namespace
+ member_list[-1].is_const = member.is_const
+ return member_list
+
+ return member
+
+ def gen_decl(self):
+ text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n"
+ if self.is_const:
+ return text
+ if self.wtype.name in classnames:
+ text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n"
+ else:
+ text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n"
+ return text
+
+ def gen_def(self):
+ text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()"
+ text += "\n\t{\n\t\t"
+ if self.wtype.attr_type == attr_types.star:
+ text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t"
+ text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t"
+ if self.wtype.name in known_containers:
+ text += self.wtype.gen_text_cpp()
+ else:
+ text += self.wtype.gen_text()
+
+ if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star):
+ text += "*"
+ text += " ret_ = "
+ if self.wtype.name in classnames:
+ text += self.wtype.name + "::get_py_obj("
+ if self.wtype.attr_type != attr_types.star:
+ text += "&"
+ text += "this->get_cpp_obj()->" + self.name
+ if self.wtype.name in classnames:
+ text += ")"
+ text += ";"
+
+ if self.wtype.name in classnames:
+ text += "\n\t\treturn *ret_;"
+ elif self.wtype.name in known_containers:
+ text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star)
+ text += "\n\t\treturn ret____tmp;"
+ else:
+ text += "\n\t\treturn ret_;"
+ text += "\n\t}\n"
+
+ if self.is_const:
+ return text
+
+ ret = Attribute(self.wtype, "rhs");
+
+ if self.wtype.name in classnames:
+ text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)"
+ else:
+ text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)"
+ text += "\n\t{"
+ text += ret.gen_translation()
+ text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";"
+ text += "\n\t}\n"
+
+ return text;
+
+ def gen_boost_py(self):
+ text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name
+ if not self.is_const:
+ text += ", &" + self.member_of.name + "::set_var_py_" + self.name
+ text += ")"
+ return text
+
+def concat_namespace(tuple_list):
+ if len(tuple_list) == 0:
+ return ""
+ ret = ""
+ for namespace in tuple_list:
+ ret += "::" + namespace[0]
+ return ret[2:]
+
+def calc_ident(text):
+ if len(text) == 0 or text[0] != ' ':
+ return 0
+ return calc_ident(text[1:]) + 1
+
+def assure_length(text, length, left = False):
+ if len(text) > length:
+ return text[:length]
+ if left:
+ return text + " "*(length - len(text))
+ return " "*(length - len(text)) + text
+
+def parse_header(source):
+ debug("Parsing " + source.name + ".pyh",1)
+ source_file = open(source.name + ".pyh", "r")
+
+ source_text = []
+ in_line = source_file.readline()
+
+ namespaces = []
+
+ while(in_line):
+ if(len(in_line)>1):
+ source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p "))
+ in_line = source_file.readline()
+
+ i = 0
+
+ namespaces = []
+ class_ = None
+ private_segment = False
+
+ while i < len(source_text):
+ line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
+ ugly_line = unpretty_string(line)
+
+ if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1:
+ namespace_name = ugly_line[10:].replace("{","").strip()
+ namespaces.append((namespace_name, ugly_line.count("{")))
+ debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3)
+ i += 1
+ continue
+
+ if len(namespaces) != 0:
+ namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}"))
+ if namespaces[-1][1] == 0:
+ debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
+ del namespaces[-1]
+ i += 1
+ continue
+
+ if class_ == None and (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0:
+
+ struct_name = ugly_line.split(" ")[1].split("::")[-1]
+ impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1]
+ complete_namespace = concat_namespace(namespaces)
+ for namespace in impl_namespaces:
+ complete_namespace += "::" + namespace
+ debug("\tFound " + struct_name + " in " + complete_namespace,2)
+ class_ = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line))
+ if struct_name in classnames:
+ class_[0].namespace = complete_namespace
+ i += 1
+ continue
+
+ if class_ != None:
+ class_ = (class_[0], class_[1] + ugly_line.count("{") - ugly_line.count("}"))
+ if class_[1] == 0:
+ if class_[0] == None:
+ debug("\tExiting unknown class", 3)
+ else:
+ debug("\tExiting class " + class_[0].name, 3)
+ class_ = None
+ private_segment = False
+ i += 1
+ continue
+
+ if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1):
+ private_segment = True
+ i += 1
+ continue
+ if class_ != None and line.find("public:") != -1:
+ private_segment = False
+ i += 1
+ continue
+
+ candidate = None
+
+ if private_segment and class_ != None and class_[0] != None:
+ candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True)
+ if candidate != None:
+ debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
+ class_[0].found_constrs.append(candidate)
+ i += 1
+ continue
+
+ if not private_segment and (class_ == None or class_[0] != None):
+ if class_ != None:
+ candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
+ else:
+ candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
+ if candidate != None and candidate.name.find("::") == -1:
+ if class_ == None:
+ debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
+ unowned_functions.append(candidate)
+ else:
+ debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
+ class_[0].found_funs.append(candidate)
+ else:
+ candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i)
+ if candidate != None:
+ enums.append(candidate)
+ debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
+ elif class_ != None and class_[1] == 1:
+ candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i)
+ if candidate != None:
+ debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
+ class_[0].found_constrs.append(candidate)
+ else:
+ candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
+ if candidate != None:
+ if type(candidate) == list:
+ for c in candidate:
+ debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2)
+ class_[0].found_vars.extend(candidate)
+ else:
+ debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2)
+ class_[0].found_vars.append(candidate)
+
+ j = i
+ line = unpretty_string(line)
+ while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"):
+ j += 1
+ line = line + "\n" + unpretty_string(source_text[j])
+ if class_ != None:
+ candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
+ else:
+ candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
+ if candidate != None and candidate.name.find("::") == -1:
+ if class_ == None:
+ debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
+ unowned_functions.append(candidate)
+ else:
+ debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
+ class_[0].found_funs.append(candidate)
+ continue
+ candidate = WEnum.from_string(line, concat_namespace(namespaces), i)
+ if candidate != None:
+ enums.append(candidate)
+ debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
+ continue
+ if class_ != None:
+ candidate = WConstructor.from_string(line, source.name, class_[0], i)
+ if candidate != None:
+ debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
+ class_[0].found_constrs.append(candidate)
+ continue
+ if candidate != None:
+ while i < j:
+ i += 1
+ line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
+ ugly_line = unpretty_string(line)
+ if len(namespaces) != 0:
+ namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}"))
+ if namespaces[-1][1] == 0:
+ debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
+ del namespaces[-1]
+ if class_ != None:
+ class_ = (class_[0] , class_[1] + ugly_line.count("{") - ugly_line.count("}"))
+ if class_[1] == 0:
+ if class_[0] == None:
+ debug("\tExiting unknown class", 3)
+ else:
+ debug("\tExiting class " + class_[0].name, 3)
+ class_ = None
+ private_segment = False
+ i += 1
+ else:
+ i += 1
+
+def debug(message, level):
+ if level <= debug.debug_level:
+ print(message)
+
+def expand_function(f):
+ fun_list = []
+ arg_list = []
+ for arg in f.args:
+ if arg.default_value != None and (arg.wtype.name.split(" ")[-1] in primitive_types or arg.wtype.name in enum_names or (arg.wtype.name in classnames and arg.default_value == "nullptr")):
+ fi = copy.deepcopy(f)
+ fi.args = copy.deepcopy(arg_list)
+ fun_list.append(fi)
+ arg_list.append(arg)
+ fun_list.append(f)
+ return fun_list
+
+def expand_functions():
+ global unowned_functions
+ new_funs = []
+ for fun in unowned_functions:
+ new_funs.extend(expand_function(fun))
+ unowned_functions = new_funs
+ for source in sources:
+ for class_ in source.classes:
+ new_funs = []
+ for fun in class_.found_funs:
+ new_funs.extend(expand_function(fun))
+ class_.found_funs = new_funs
+
+def clean_duplicates():
+ for source in sources:
+ for class_ in source.classes:
+ known_decls = {}
+ for fun in class_.found_funs:
+ if fun.gen_decl_hash_py() in known_decls:
+ debug("Multiple declarations of " + fun.gen_decl_hash_py(),3)
+ other = known_decls[fun.gen_decl_hash_py()]
+ other.gen_alias()
+ fun.gen_alias()
+ if fun.gen_decl_hash_py() == other.gen_decl_hash_py():
+ fun.duplicate = True
+ debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3)
+ else:
+ known_decls[fun.gen_decl_hash_py()] = fun
+ known_decls = []
+ for con in class_.found_constrs:
+ if con.gen_decl_hash_py() in known_decls:
+ debug("Multiple declarations of " + con.gen_decl_hash_py(),3)
+ con.duplicate = True
+ else:
+ known_decls.append(con.gen_decl_hash_py())
+ known_decls = []
+ for fun in unowned_functions:
+ if fun.gen_decl_hash_py() in known_decls:
+ debug("Multiple declarations of " + fun.gen_decl_hash_py(),3)
+ fun.duplicate = True
+ else:
+ known_decls.append(fun.gen_decl_hash_py())
+
+def gen_wrappers(filename, debug_level_ = 0):
+ debug.debug_level = debug_level_
+ for source in sources:
+ parse_header(source)
+
+ expand_functions()
+ clean_duplicates()
+
+ import shutil
+ import math
+ col = shutil.get_terminal_size((80,20)).columns
+ debug("-"*col, 1)
+ debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1)
+ debug("-"*col, 1)
+ for source in sources:
+ for class_ in source.classes:
+ debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1)
+ if len(class_.found_constrs) == 0:
+ class_.found_constrs.append(WConstructor(source.name, class_))
+ debug(str(len(unowned_functions)) + " functions are unowned", 1)
+ for enum in enums:
+ debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1)
+ debug("-"*col, 1)
+ wrapper_file = open(filename, "w+")
+ wrapper_file.write(
+"""/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * This is a generated file and can be overwritten by make
+ */
+
+#ifdef WITH_PYTHON
+""")
+ for source in sources:
+ wrapper_file.write("#include \""+source.name+".h\"\n")
+ wrapper_file.write("""
+#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/wrapper.hpp>
+#include <boost/python/call.hpp>
+#include <boost/python.hpp>
+#include <boost/log/exceptions.hpp>
+
+USING_YOSYS_NAMESPACE
+
+namespace YOSYS_PYTHON {
+""")
+
+ for source in sources:
+ for wclass in source.classes:
+ wrapper_file.write("\n\tstruct " + wclass.name + ";")
+
+ wrapper_file.write("\n")
+
+ for source in sources:
+ for wclass in source.classes:
+ wrapper_file.write(wclass.gen_decl(source.name))
+
+ wrapper_file.write("\n")
+
+ for source in sources:
+ for wclass in source.classes:
+ wrapper_file.write(wclass.gen_funs(source.name))
+
+ for fun in unowned_functions:
+ wrapper_file.write(fun.gen_def())
+
+ wrapper_file.write(""" struct Initializer
+ {
+ Initializer() {
+ if(!Yosys::yosys_already_setup())
+ {
+ Yosys::log_streams.push_back(&std::cout);
+ Yosys::log_error_stderr = true;
+ Yosys::yosys_setup();
+ 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")
+++ /dev/null
-#
-# 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"
-
- for con in self.found_constrs:
- text += con.gen_decl()
- for var in self.found_vars:
- text += var.gen_decl()
- for fun in self.found_funs:
- text += fun.gen_decl()
-
-
- if self.link_type == link_types.derive:
- duplicates = {}
- for fun in self.found_funs:
- if fun.name in duplicates:
- fun.gen_alias()
- duplicates[fun.name].gen_alias()
- else:
- duplicates[fun.name] = fun
-
- text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn (" + self.namespace + "::" + self.name +"*)this;\n\t\t}\n"
- text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{"
- text += "\n\t\t\treturn (" + self.name + "*)ref;"
- text += "\n\t\t}\n"
-
- for con in self.found_constrs:
- text += con.gen_decl_derive()
- for var in self.found_vars:
- text += var.gen_decl()
- for fun in self.found_funs:
- text += fun.gen_decl_virtual()
-
- if self.hash_id != None:
- text += "\n\t\tunsigned int get_hash_py()"
- text += "\n\t\t{"
- text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";"
- text += "\n\t\t}"
-
- text += "\n\t};\n"
-
- if self.link_type == link_types.derive:
- text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">"
- text += "\n\t{"
-
- for con in self.found_constrs:
- text += con.gen_decl_wrapperclass()
- for fun in self.found_funs:
- text += fun.gen_default_impl()
-
- text += "\n\t};"
-
- text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)"
- text += "\n\t{"
- text += "\n\t\tostr << \"" + self.name
- if self.string_id != None:
- text +=" \\\"\""
- text += " << ref.get_cpp_obj()->" + self.string_id
- text += " << \"\\\"\""
- else:
- text += " at \" << ref.get_cpp_obj()"
- text += ";"
- text += "\n\t\treturn ostr;"
- text += "\n\t}"
- text += "\n"
-
- return text
-
- def gen_funs(self, filename):
- text = ""
- if self.link_type != link_types.derive:
- for con in self.found_constrs:
- text += con.gen_def()
- for var in self.found_vars:
- text += var.gen_def()
- for fun in self.found_funs:
- text += fun.gen_def()
- else:
- for var in self.found_vars:
- text += var.gen_def()
- for fun in self.found_funs:
- text += fun.gen_def_virtual()
- return text
-
- def gen_boost_py(self):
- text = "\n\t\tclass_<" + self.name
- if self.link_type == link_types.derive:
- text += "Wrap, boost::noncopyable"
- text += ">(\"" + self.name + "\""
- if self.printable_constrs() == 0 or not self.contains_default_constr():
- text += ", no_init"
- text += ")"
- text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))"
- text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))"
- for con in self.found_constrs:
- text += con.gen_boost_py()
- for var in self.found_vars:
- text += var.gen_boost_py()
- static_funs = []
- for fun in self.found_funs:
- text += fun.gen_boost_py()
- if fun.is_static and fun.alias not in static_funs:
- static_funs.append(fun.alias)
- for fun in static_funs:
- text += "\n\t\t\t.staticmethod(\"" + fun + "\")"
-
- if self.hash_id != None:
- text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)"
- text += "\n\t\t\t;\n"
- return text
-
- def contains_default_constr(self):
- for c in self.found_constrs:
- if len(c.args) == 0:
- return True
- return False
-
-#CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE
-
-sources = [
- Source("kernel/celltypes",[
- WClass("CellType", link_types.pointer, None, None, "type.hash()", True),
- WClass("CellTypes", link_types.pointer, None, None, None, True)
- ]
- ),
- Source("kernel/consteval",[
- WClass("ConstEval", link_types.pointer, None, None, None, True)
- ]
- ),
- Source("kernel/log",[]),
- Source("kernel/register",[
- WClass("Pass", link_types.derive, None, None, None, True),
- ]
- ),
- Source("kernel/rtlil",[
- WClass("IdString", link_types.ref_copy, None, "str()", "hash()"),
- WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"),
- WClass("AttrObject", link_types.ref_copy, None, None, None),
- WClass("Selection", link_types.ref_copy, None, None, None),
- WClass("Monitor", link_types.derive, None, None, None),
- WClass("CaseRule",link_types.ref_copy, None, None, None, True),
- WClass("SwitchRule",link_types.ref_copy, None, None, None, True),
- WClass("SyncRule", link_types.ref_copy, None, None, None, True),
- WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"),
- WClass("SigChunk", link_types.ref_copy, None, None, None),
- WClass("SigBit", link_types.ref_copy, None, None, "hash()"),
- WClass("SigSpec", link_types.ref_copy, None, None, "hash()"),
- WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
- WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
- WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
- WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
- WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()")
- ]
- ),
- #Source("kernel/satgen",[
- # ]
- # ),
- #Source("libs/ezsat/ezsat",[
- # ]
- # ),
- #Source("libs/ezsat/ezminisat",[
- # ]
- # ),
- Source("kernel/sigtools",[
- WClass("SigMap", link_types.pointer, None, None, None, True)
- ]
- ),
- Source("kernel/yosys",[
- ]
- ),
- Source("kernel/cost",[])
- ]
-
-blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow", "YOSYS_NAMESPACE::Module::Bu0", "YOSYS_NAMESPACE::CaseRule::optimize"]
-
-enum_names = ["State","SyncType","ConstFlags"]
-
-enums = [] #Do not edit
-
-unowned_functions = []
-
-classnames = []
-for source in sources:
- for wclass in source.classes:
- classnames.append(wclass.name)
-
-def class_by_name(name):
- for source in sources:
- for wclass in source.classes:
- if wclass.name == name:
- return wclass
- return None
-
-def enum_by_name(name):
- for e in enums:
- if e.name == name:
- return e
- return None
-
-def find_closing(text, open_tok, close_tok):
- if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok):
- return text.find(close_tok)
- return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1
-
-def unpretty_string(s):
- s = s.strip()
- while s.find(" ") != -1:
- s = s.replace(" "," ")
- while s.find("\t") != -1:
- s = s.replace("\t"," ")
- s = s.replace(" (","(")
- return s
-
-class WEnum:
- name = None
- namespace = None
- values = []
-
- def from_string(str_def, namespace, line_number):
- str_def = str_def.strip()
- if not str.startswith(str_def, "enum "):
- return None
- if str_def.count(";") != 1:
- return None
- str_def = str_def[5:]
- enum = WEnum()
- split = str_def.split(":")
- if(len(split) != 2):
- return None
- enum.name = split[0].strip()
- if enum.name not in enum_names:
- return None
- str_def = split[1]
- if str_def.count("{") != str_def.count("}") != 1:
- return None
- if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';':
- return None
- str_def = str_def.split("{")[-1].split("}")[0]
- enum.values = []
- for val in str_def.split(','):
- enum.values.append(val.strip().split('=')[0].strip())
- enum.namespace = namespace
- return enum
-
- def gen_boost_py(self):
- text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n"
- for value in self.values:
- text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n"
- text += "\t\t\t;\n"
- return text
-
- def __str__(self):
- ret = "Enum " + self.namespace + "::" + self.name + "(\n"
- for val in self.values:
- ret = ret + "\t" + val + "\n"
- return ret + ")"
-
- def __repr__(self):
- return __str__(self)
-
-class WConstructor:
- orig_text = None
- args = []
- containing_file = None
- member_of = None
- duplicate = False
- protected = False
-
- def __init__(self, containing_file, class_):
- self.orig_text = "Auto generated default constructor"
- self.args = []
- self.containing_file = containing_file
- self.member_of = class_
- self.protected = False
-
- def from_string(str_def, containing_file, class_, line_number, protected = False):
- if class_ == None:
- return None
- if str_def.count("delete;") > 0:
- return None
- con = WConstructor(containing_file, class_)
- con.orig_text = str_def
- con.args = []
- con.duplicate = False
- con.protected = protected
- if not str.startswith(str_def, class_.name + "("):
- return None
- str_def = str_def[len(class_.name)+1:]
- found = find_closing(str_def, "(", ")")
- if found == -1:
- return None
- str_def = str_def[0:found].strip()
- if len(str_def) == 0:
- return con
- for arg in split_list(str_def, ","):
- parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
- if parsed == None:
- return None
- con.args.append(parsed)
- return con
-
- def gen_decl(self):
- if self.duplicate or self.protected:
- return ""
- text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t\t" + self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_listitem() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ");\n"
- return text
-
- def gen_decl_derive(self):
- if self.duplicate or self.protected:
- return ""
- text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t\t" + self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_listitem() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ")"
- if len(self.args) == 0:
- return text + "{}"
- text += " : "
- text += self.member_of.namespace + "::" + self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_call() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += "){}\n"
- return text
-
- def gen_decl_wrapperclass(self):
- if self.duplicate or self.protected:
- return ""
- text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t\t" + self.member_of.name + "Wrap("
- for arg in self.args:
- text += arg.gen_listitem() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ")"
- if len(self.args) == 0:
- return text + "{}"
- text += " : "
- text += self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_call() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += "){}\n"
- return text
-
- def gen_decl_hash_py(self):
- text = self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_listitem_hash() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ");"
- return text
-
- def gen_def(self):
- if self.duplicate or self.protected:
- return ""
- text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_listitem() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text +=")\n\t{"
- for arg in self.args:
- text += arg.gen_translation()
- if self.member_of.link_type != link_types.derive:
- text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "("
- for arg in self.args:
- text += arg.gen_call() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- if self.member_of.link_type != link_types.derive:
- text += ");"
- if self.member_of.link_type == link_types.global_list:
- text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";"
- for arg in self.args:
- text += arg.gen_cleanup()
- text += "\n\t}\n"
- return text
-
- def gen_boost_py(self):
- if self.duplicate or self.protected or len(self.args) == 0:
- return ""
- text = "\n\t\t\t.def(init"
- text += "<"
- for a in self.args:
- text += a.gen_listitem_hash() + ", "
- text = text[0:-2] + ">())"
- return text
-
-class WFunction:
- orig_text = None
- is_static = False
- is_inline = False
- is_virtual = False
- ret_attr_type = attr_types.default
- is_operator = False
- ret_type = None
- name = None
- alias = None
- args = []
- containing_file = None
- member_of = None
- duplicate = False
- namespace = ""
-
- def from_string(str_def, containing_file, class_, line_number, namespace):
- if str_def.count("delete;") > 0:
- return None
- func = WFunction()
- func.is_static = False
- func.is_inline = False
- func.is_virtual = False
- func.ret_attr_type = attr_types.default
- func.is_operator = False
- func.member_of = None
- func.orig_text = str_def
- func.args = []
- func.containing_file = containing_file
- func.member_of = class_
- func.duplicate = False
- func.namespace = namespace
- str_def = str_def.replace("operator ","operator")
- if str.startswith(str_def, "static "):
- func.is_static = True
- str_def = str_def[7:]
- else:
- func.is_static = False
- if str.startswith(str_def, "inline "):
- func.is_inline = True
- str_def = str_def[7:]
- else:
- func.is_inline = False
- if str.startswith(str_def, "virtual "):
- func.is_virtual = True
- str_def = str_def[8:]
- else:
- func.is_virtual = False
-
- if str_def.count(" ") == 0:
- return None
-
- parts = split_list(str_def.strip(), " ")
-
- prefix = ""
- i = 0
- for part in parts:
- if part in ["unsigned", "long", "short"]:
- prefix += part + " "
- i += 1
- else:
- break
- parts = parts[i:]
-
- if len(parts) <= 1:
- return None
-
- func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number)
-
- if func.ret_type == None:
- return None
-
- str_def = parts[1]
- for part in parts[2:]:
- str_def = str_def + " " + part
-
- found = str_def.find("(")
- if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")):
- return None
- func.name = str_def[:found]
- str_def = str_def[found:]
- if func.name.find("operator") != -1 and str.startswith(str_def, "()("):
- func.name += "()"
- str_def = str_def[2:]
- str_def = str_def[1:]
- if func.name.find("operator") != -1:
- func.is_operator = True
- if func.name.find("*") == 0:
- func.name = func.name.replace("*", "")
- func.ret_type.attr_type = attr_types.star
- if func.name.find("&&") == 0:
- func.name = func.name.replace("&&", "")
- func.ret_type.attr_type = attr_types.ampamp
- if func.name.find("&") == 0:
- func.name = func.name.replace("&", "")
- func.ret_type.attr_type = attr_types.amp
-
- found = find_closing(str_def, "(", ")")
- if found == -1:
- return None
- str_def = str_def[0:found]
- if func.name in blacklist_methods:
- return None
- if func.namespace != None and func.namespace != "":
- if (func.namespace + "::" + func.name) in blacklist_methods:
- return None
- if func.member_of != None:
- if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods:
- return None
- if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators:
- return None
-
- testname = func.name
- if func.is_operator:
- testname = testname[:testname.find("operator")]
- if testname.count(")") != 0 or testname.count("(") != 0 or testname.count("~") != 0 or testname.count(";") != 0 or testname.count(">") != 0 or testname.count("<") != 0 or testname.count("throw") != 0:
- return None
-
- func.alias = func.name
- if func.name in keyword_aliases:
- func.alias = keyword_aliases[func.name]
- str_def = str_def[:found].strip()
- if(len(str_def) == 0):
- return func
- for arg in split_list(str_def, ","):
- if arg.strip() == "...":
- continue
- parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
- if parsed == None:
- return None
- func.args.append(parsed)
- return func
-
- def gen_alias(self):
- self.alias = self.name
- for arg in self.args:
- self.alias += "__" + arg.wtype.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","")
-
- def gen_decl(self):
- if self.duplicate:
- return ""
- text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t\t"
- if self.is_static:
- text += "static "
- text += self.ret_type.gen_text() + " " + self.alias + "("
- for arg in self.args:
- text += arg.gen_listitem()
- text += ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ");\n"
- return text
-
- def gen_decl_virtual(self):
- if self.duplicate:
- return ""
- if not self.is_virtual:
- return self.gen_decl()
- text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t\tvirtual "
- if self.is_static:
- text += "static "
- text += self.ret_type.gen_text() + " py_" + self.alias + "("
- for arg in self.args:
- text += arg.gen_listitem()
- text += ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ")"
- if len(self.args) == 0:
- text += "{}"
- else:
- text += "\n\t\t{"
- for arg in self.args:
- text += "\n\t\t\t(void)" + arg.gen_varname() + ";"
- text += "\n\t\t}\n"
- text += "\n\t\tvirtual "
- if self.is_static:
- text += "static "
- text += self.ret_type.gen_text() + " " + self.name + "("
- for arg in self.args:
- text += arg.gen_listitem_cpp()
- text += ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ") YS_OVERRIDE;\n"
- return text
-
- def gen_decl_hash_py(self):
- text = self.ret_type.gen_text() + " " + self.alias + "("
- for arg in self.args:
- text += arg.gen_listitem_hash() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ");"
- return text
-
- def gen_def(self):
- if self.duplicate:
- return ""
- text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t" + self.ret_type.gen_text() + " "
- if self.member_of != None:
- text += self.member_of.name + "::"
- text += self.alias + "("
- for arg in self.args:
- text += arg.gen_listitem()
- text += ", "
- if len(self.args) > 0:
- text = text[:-2]
- text +=")\n\t{"
- for arg in self.args:
- text += arg.gen_translation()
- text += "\n\t\t"
- if self.ret_type.name != "void":
- if self.ret_type.name in known_containers:
- text += self.ret_type.gen_text_cpp()
- else:
- text += self.ret_type.gen_text()
- if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star):
- text += "*"
- text += " ret_ = "
- if self.ret_type.name in classnames:
- text += self.ret_type.name + "::get_py_obj("
- if self.member_of == None:
- text += "::" + self.namespace + "::" + self.alias + "("
- elif self.is_static:
- text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "("
- else:
- text += "this->get_cpp_obj()->" + self.name + "("
- for arg in self.args:
- text += arg.gen_call() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- if self.ret_type.name in classnames:
- text += ")"
- text += ");"
- for arg in self.args:
- text += arg.gen_cleanup()
- if self.ret_type.name != "void":
- if self.ret_type.name in classnames:
- text += "\n\t\treturn *ret_;"
- elif self.ret_type.name in known_containers:
- text += known_containers[self.ret_type.name].translate_cpp("ret_", self.ret_type.cont.args, "\n\t\t", self.ret_type.attr_type == attr_types.star)
- text += "\n\t\treturn ret____tmp;"
- else:
- text += "\n\t\treturn ret_;"
- text += "\n\t}\n"
- return text
-
- def gen_def_virtual(self):
- if self.duplicate:
- return ""
- if not self.is_virtual:
- return self.gen_def()
- text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
- text += "\n\t"
- if self.is_static:
- text += "static "
- text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "("
- for arg in self.args:
- text += arg.gen_listitem_cpp()
- text += ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ")\n\t{"
- for arg in self.args:
- text += arg.gen_translation_cpp()
- text += "\n\t\t"
- if self.member_of == None:
- text += "::" + self.namespace + "::" + self.alias + "("
- elif self.is_static:
- text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "("
- else:
- text += "py_" + self.alias + "("
- for arg in self.args:
- text += arg.gen_call_cpp() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- if self.ret_type.name in classnames:
- text += ")"
- text += ");"
- for arg in self.args:
- text += arg.gen_cleanup()
- text += "\n\t}\n"
- return text
-
- def gen_default_impl(self):
- if self.duplicate:
- return ""
- if not self.is_virtual:
- return ""
- text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "("
- for arg in self.args:
- text += arg.gen_listitem() + ", "
- if len(self.args) > 0:
- text = text[:-2]
-
- call_string = "py_" + self.alias + "("
- for arg in self.args:
- call_string += arg.gen_varname() + ", "
- if len(self.args) > 0:
- call_string = call_string[0:-2]
- call_string += ");"
-
- text += ")\n\t\t{"
- text += "\n\t\t\tif(boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))"
- text += "\n\t\t\t\t" + call_string
- text += "\n\t\t\telse"
- text += "\n\t\t\t\t" + self.member_of.name + "::" + call_string
- text += "\n\t\t}"
-
- text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "("
- for arg in self.args:
- text += arg.gen_listitem() + ", "
- if len(self.args) > 0:
- text = text[:-2]
- text += ")\n\t\t{"
- text += "\n\t\t\tthis->" + self.member_of.name + "::" + call_string
- text += "\n\t\t}"
- return text
-
-
- def gen_boost_py(self):
- if self.duplicate:
- return ""
- if self.member_of == None:
- text = "\n\t\tdef"
- else:
- text = "\n\t\t\t.def"
- if len(self.args) > -1:
- if self.ret_type.name in known_containers:
- text += "<" + known_containers[self.ret_type.name].typename + " "
- else:
- text += "<" + self.ret_type.name + " "
- if self.member_of == None or self.is_static:
- text += "(*)("
- else:
- text += "(" + self.member_of.name + "::*)("
- for a in self.args:
- text += a.gen_listitem_hash() + ", "
- if len(self.args) > 0:
- text = text[0:-2] + ")>"
- else:
- text += "void)>"
-
- if self.is_operator:
- text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\""
- else:
- if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual:
- text += "(\"py_" + self.alias + "\""
- else:
- text += "(\"" + self.alias + "\""
- if self.member_of != None:
- text += ", &" + self.member_of.name + "::"
- if self.member_of.link_type == link_types.derive and self.is_virtual:
- text += "py_" + self.alias
- text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias
- else:
- text += self.alias
-
- text += ")"
- else:
- text += ", " + "YOSYS_PYTHON::" + self.alias + ");"
- return text
-
-class WMember:
- orig_text = None
- wtype = attr_types.default
- name = None
- containing_file = None
- member_of = None
- namespace = ""
- is_const = False
-
- def from_string(str_def, containing_file, class_, line_number, namespace):
- member = WMember()
- member.orig_text = str_def
- member.wtype = None
- member.name = ""
- member.containing_file = containing_file
- member.member_of = class_
- member.namespace = namespace
- member.is_const = False
-
- if str.startswith(str_def, "const "):
- member.is_const = True
- str_def = str_def[6:]
-
- if str_def.count(" ") == 0:
- return None
-
- parts = split_list(str_def.strip(), " ")
-
- prefix = ""
- i = 0
- for part in parts:
- if part in ["unsigned", "long", "short"]:
- prefix += part + " "
- i += 1
- else:
- break
- parts = parts[i:]
-
- if len(parts) <= 1:
- return None
-
- member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number)
-
- if member.wtype == None:
- return None
-
- str_def = parts[1]
- for part in parts[2:]:
- str_def = str_def + " " + part
-
- if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1:
- return None
-
- found = str_def.find(";")
- if found == -1:
- return None
-
- found_eq = str_def.find("=")
- if found_eq != -1:
- found = found_eq
-
- member.name = str_def[:found]
- str_def = str_def[found+1:]
- if member.name.find("*") == 0:
- member.name = member.name.replace("*", "")
- member.wtype.attr_type = attr_types.star
- if member.name.find("&&") == 0:
- member.name = member.name.replace("&&", "")
- member.wtype.attr_type = attr_types.ampamp
- if member.name.find("&") == 0:
- member.name = member.name.replace("&", "")
- member.wtype.attr_type = attr_types.amp
-
- if(len(str_def.strip()) != 0):
- return None
-
- if len(member.name.split(",")) > 1:
- member_list = []
- for name in member.name.split(","):
- name = name.strip();
- member_list.append(WMember())
- member_list[-1].orig_text = member.orig_text
- member_list[-1].wtype = member.wtype
- member_list[-1].name = name
- member_list[-1].containing_file = member.containing_file
- member_list[-1].member_of = member.member_of
- member_list[-1].namespace = member.namespace
- member_list[-1].is_const = member.is_const
- return member_list
-
- return member
-
- def gen_decl(self):
- text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n"
- if self.is_const:
- return text
- if self.wtype.name in classnames:
- text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n"
- else:
- text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n"
- return text
-
- def gen_def(self):
- text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()"
- text += "\n\t{\n\t\t"
- if self.wtype.attr_type == attr_types.star:
- text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t"
- text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t"
- if self.wtype.name in known_containers:
- text += self.wtype.gen_text_cpp()
- else:
- text += self.wtype.gen_text()
-
- if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star):
- text += "*"
- text += " ret_ = "
- if self.wtype.name in classnames:
- text += self.wtype.name + "::get_py_obj("
- if self.wtype.attr_type != attr_types.star:
- text += "&"
- text += "this->get_cpp_obj()->" + self.name
- if self.wtype.name in classnames:
- text += ")"
- text += ";"
-
- if self.wtype.name in classnames:
- text += "\n\t\treturn *ret_;"
- elif self.wtype.name in known_containers:
- text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star)
- text += "\n\t\treturn ret____tmp;"
- else:
- text += "\n\t\treturn ret_;"
- text += "\n\t}\n"
-
- if self.is_const:
- return text
-
- ret = Attribute(self.wtype, "rhs");
-
- if self.wtype.name in classnames:
- text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)"
- else:
- text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)"
- text += "\n\t{"
- text += ret.gen_translation()
- text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";"
- text += "\n\t}\n"
-
- return text;
-
- def gen_boost_py(self):
- text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name
- if not self.is_const:
- text += ", &" + self.member_of.name + "::set_var_py_" + self.name
- text += ")"
- return text
-
-def concat_namespace(tuple_list):
- if len(tuple_list) == 0:
- return ""
- ret = ""
- for namespace in tuple_list:
- ret += "::" + namespace[0]
- return ret[2:]
-
-def calc_ident(text):
- if len(text) == 0 or text[0] != ' ':
- return 0
- return calc_ident(text[1:]) + 1
-
-def assure_length(text, length, left = False):
- if len(text) > length:
- return text[:length]
- if left:
- return text + " "*(length - len(text))
- return " "*(length - len(text)) + text
-
-def parse_header(source):
- debug("Parsing " + source.name + ".pyh",1)
- source_file = open(source.name + ".pyh", "r")
-
- source_text = []
- in_line = source_file.readline()
-
- namespaces = []
-
- while(in_line):
- if(len(in_line)>1):
- source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p "))
- in_line = source_file.readline()
-
- i = 0
-
- namespaces = []
- class_ = None
- private_segment = False
-
- while i < len(source_text):
- line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
- ugly_line = unpretty_string(line)
-
- if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1:
- namespace_name = ugly_line[10:].replace("{","").strip()
- namespaces.append((namespace_name, ugly_line.count("{")))
- debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3)
- i += 1
- continue
-
- if len(namespaces) != 0:
- namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}"))
- if namespaces[-1][1] == 0:
- debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
- del namespaces[-1]
- i += 1
- continue
-
- if class_ == None and (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0:
-
- struct_name = ugly_line.split(" ")[1].split("::")[-1]
- impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1]
- complete_namespace = concat_namespace(namespaces)
- for namespace in impl_namespaces:
- complete_namespace += "::" + namespace
- debug("\tFound " + struct_name + " in " + complete_namespace,2)
- class_ = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line))
- if struct_name in classnames:
- class_[0].namespace = complete_namespace
- i += 1
- continue
-
- if class_ != None:
- class_ = (class_[0], class_[1] + ugly_line.count("{") - ugly_line.count("}"))
- if class_[1] == 0:
- if class_[0] == None:
- debug("\tExiting unknown class", 3)
- else:
- debug("\tExiting class " + class_[0].name, 3)
- class_ = None
- private_segment = False
- i += 1
- continue
-
- if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1):
- private_segment = True
- i += 1
- continue
- if class_ != None and line.find("public:") != -1:
- private_segment = False
- i += 1
- continue
-
- candidate = None
-
- if private_segment and class_ != None and class_[0] != None:
- candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True)
- if candidate != None:
- debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
- class_[0].found_constrs.append(candidate)
- i += 1
- continue
-
- if not private_segment and (class_ == None or class_[0] != None):
- if class_ != None:
- candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
- else:
- candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
- if candidate != None and candidate.name.find("::") == -1:
- if class_ == None:
- debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
- unowned_functions.append(candidate)
- else:
- debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
- class_[0].found_funs.append(candidate)
- else:
- candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i)
- if candidate != None:
- enums.append(candidate)
- debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
- elif class_ != None and class_[1] == 1:
- candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i)
- if candidate != None:
- debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
- class_[0].found_constrs.append(candidate)
- else:
- candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
- if candidate != None:
- if type(candidate) == list:
- for c in candidate:
- debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2)
- class_[0].found_vars.extend(candidate)
- else:
- debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2)
- class_[0].found_vars.append(candidate)
-
- j = i
- line = unpretty_string(line)
- while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"):
- j += 1
- line = line + "\n" + unpretty_string(source_text[j])
- if class_ != None:
- candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
- else:
- candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
- if candidate != None and candidate.name.find("::") == -1:
- if class_ == None:
- debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
- unowned_functions.append(candidate)
- else:
- debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
- class_[0].found_funs.append(candidate)
- continue
- candidate = WEnum.from_string(line, concat_namespace(namespaces), i)
- if candidate != None:
- enums.append(candidate)
- debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
- continue
- if class_ != None:
- candidate = WConstructor.from_string(line, source.name, class_[0], i)
- if candidate != None:
- debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
- class_[0].found_constrs.append(candidate)
- continue
- if candidate != None:
- while i < j:
- i += 1
- line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
- ugly_line = unpretty_string(line)
- if len(namespaces) != 0:
- namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}"))
- if namespaces[-1][1] == 0:
- debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
- del namespaces[-1]
- if class_ != None:
- class_ = (class_[0] , class_[1] + ugly_line.count("{") - ugly_line.count("}"))
- if class_[1] == 0:
- if class_[0] == None:
- debug("\tExiting unknown class", 3)
- else:
- debug("\tExiting class " + class_[0].name, 3)
- class_ = None
- private_segment = False
- i += 1
- else:
- i += 1
-
-def debug(message, level):
- if level <= debug.debug_level:
- print(message)
-
-def expand_function(f):
- fun_list = []
- arg_list = []
- for arg in f.args:
- if arg.default_value != None and (arg.wtype.name.split(" ")[-1] in primitive_types or arg.wtype.name in enum_names or (arg.wtype.name in classnames and arg.default_value == "nullptr")):
- fi = copy.deepcopy(f)
- fi.args = copy.deepcopy(arg_list)
- fun_list.append(fi)
- arg_list.append(arg)
- fun_list.append(f)
- return fun_list
-
-def expand_functions():
- global unowned_functions
- new_funs = []
- for fun in unowned_functions:
- new_funs.extend(expand_function(fun))
- unowned_functions = new_funs
- for source in sources:
- for class_ in source.classes:
- new_funs = []
- for fun in class_.found_funs:
- new_funs.extend(expand_function(fun))
- class_.found_funs = new_funs
-
-def clean_duplicates():
- for source in sources:
- for class_ in source.classes:
- known_decls = {}
- for fun in class_.found_funs:
- if fun.gen_decl_hash_py() in known_decls:
- debug("Multiple declarations of " + fun.gen_decl_hash_py(),3)
- other = known_decls[fun.gen_decl_hash_py()]
- other.gen_alias()
- fun.gen_alias()
- if fun.gen_decl_hash_py() == other.gen_decl_hash_py():
- fun.duplicate = True
- debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3)
- else:
- known_decls[fun.gen_decl_hash_py()] = fun
- known_decls = []
- for con in class_.found_constrs:
- if con.gen_decl_hash_py() in known_decls:
- debug("Multiple declarations of " + con.gen_decl_hash_py(),3)
- con.duplicate = True
- else:
- known_decls.append(con.gen_decl_hash_py())
- known_decls = []
- for fun in unowned_functions:
- if fun.gen_decl_hash_py() in known_decls:
- debug("Multiple declarations of " + fun.gen_decl_hash_py(),3)
- fun.duplicate = True
- else:
- known_decls.append(fun.gen_decl_hash_py())
-
-def gen_wrappers(filename, debug_level_ = 0):
- debug.debug_level = debug_level_
- for source in sources:
- parse_header(source)
-
- expand_functions()
- clean_duplicates()
-
- import shutil
- import math
- col = shutil.get_terminal_size((80,20)).columns
- debug("-"*col, 1)
- debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1)
- debug("-"*col, 1)
- for source in sources:
- for class_ in source.classes:
- debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1)
- if len(class_.found_constrs) == 0:
- class_.found_constrs.append(WConstructor(source.name, class_))
- debug(str(len(unowned_functions)) + " functions are unowned", 1)
- for enum in enums:
- debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1)
- debug("-"*col, 1)
- wrapper_file = open(filename, "w+")
- wrapper_file.write(
-"""/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * This is a generated file and can be overwritten by make
- */
-
-#ifdef WITH_PYTHON
-""")
- for source in sources:
- wrapper_file.write("#include \""+source.name+".h\"\n")
- wrapper_file.write("""
-#include <boost/python/module.hpp>
-#include <boost/python/class.hpp>
-#include <boost/python/wrapper.hpp>
-#include <boost/python/call.hpp>
-#include <boost/python.hpp>
-#include <boost/log/exceptions.hpp>
-
-USING_YOSYS_NAMESPACE
-
-namespace YOSYS_PYTHON {
-""")
-
- for source in sources:
- for wclass in source.classes:
- wrapper_file.write("\n\tstruct " + wclass.name + ";")
-
- wrapper_file.write("\n")
-
- for source in sources:
- for wclass in source.classes:
- wrapper_file.write(wclass.gen_decl(source.name))
-
- wrapper_file.write("\n")
-
- for source in sources:
- for wclass in source.classes:
- wrapper_file.write(wclass.gen_funs(source.name))
-
- for fun in unowned_functions:
- wrapper_file.write(fun.gen_def())
-
- wrapper_file.write(""" struct Initializer
- {
- Initializer() {
- if(!Yosys::yosys_already_setup())
- {
- Yosys::log_streams.push_back(&std::cout);
- Yosys::log_error_stderr = true;
- Yosys::yosys_setup();
- 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")