diff options
Diffstat (limited to 'misc')
| -rw-r--r-- | misc/__init__.py | 5 | ||||
| -rw-r--r-- | misc/py_wrap_generator.py | 2096 | 
2 files changed, 2101 insertions, 0 deletions
diff --git a/misc/__init__.py b/misc/__init__.py new file mode 100644 index 000000000..330fd6d86 --- /dev/null +++ b/misc/__init__.py @@ -0,0 +1,5 @@ +import os +import sys +sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) + +__all__ = ["libyosys"] diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py new file mode 100644 index 000000000..09f934040 --- /dev/null +++ b/misc/py_wrap_generator.py @@ -0,0 +1,2096 @@ +# +#  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")  | 
