mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2549 lines
		
	
	
	
		
			82 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			2549 lines
		
	
	
	
		
			82 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#
 | 
						|
#  yosys -- Yosys Open SYnthesis Suite
 | 
						|
#
 | 
						|
#  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 | 
						|
#
 | 
						|
#  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", "string_view", "std::string_view", "State", "char_p", "std::source_location", "source_location"]
 | 
						|
 | 
						|
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(" "):
 | 
						|
			str_def = str_def.replace("const ", "")
 | 
						|
 | 
						|
			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, "const "):
 | 
						|
			if "char_p" in str_def:
 | 
						|
				prefix = "const "
 | 
						|
			str_def = str_def[6:]
 | 
						|
		if str.startswith(str_def, "unsigned "):
 | 
						|
			prefix = "unsigned " + prefix
 | 
						|
			str_def = str_def[9:]
 | 
						|
		while str.startswith(str_def, "long "):
 | 
						|
			prefix= "long " + prefix
 | 
						|
			str_def = str_def[5:]
 | 
						|
		while str.startswith(str_def, "short "):
 | 
						|
			prefix = "short " + prefix
 | 
						|
			str_def = str_def[6:]
 | 
						|
 | 
						|
		str_def = str_def.split("::")[-1]
 | 
						|
 | 
						|
		if str_def.count("*") + str_def.count("&") >= 2:
 | 
						|
			return None
 | 
						|
 | 
						|
		if str_def.count("*") == 1:
 | 
						|
			t.attr_type = attr_types.star
 | 
						|
			str_def = str_def.replace("*","")
 | 
						|
		elif str_def.count("&&") == 1:
 | 
						|
			t.attr_type = attr_types.ampamp
 | 
						|
			str_def = str_def.replace("&&","")
 | 
						|
		elif str_def.count("&") == 1:
 | 
						|
			t.attr_type = attr_types.amp
 | 
						|
			str_def = str_def.replace("&","")
 | 
						|
 | 
						|
		if len(str_def) > 0 and str_def.split("::")[-1] not in primitive_types and str_def.split("::")[-1] not in classnames and str_def.split("::")[-1] not in enum_names:
 | 
						|
			return None
 | 
						|
 | 
						|
		if str_def.count(" ") == 0:
 | 
						|
			t.name = (prefix + str_def).replace("char_p", "char *")
 | 
						|
			t.cont = None
 | 
						|
			return t
 | 
						|
		return None
 | 
						|
 | 
						|
#Represents a container-type
 | 
						|
class WContainer:
 | 
						|
	name = ""
 | 
						|
	args = []
 | 
						|
 | 
						|
	def from_string(str_def, containing_file, line_number):
 | 
						|
		if str_def == None or len(str_def) < 4:
 | 
						|
			return None
 | 
						|
		cont = WContainer()
 | 
						|
		cont.name = str_def[:str_def.find("<")]
 | 
						|
		str_def = str_def[str_def.find("<")+1:find_closing(str_def, "<", ">")]
 | 
						|
		cont.args = []
 | 
						|
		for arg in split_list(str_def, ","):
 | 
						|
			candidate = WType.from_string(arg.strip(), containing_file, line_number)
 | 
						|
			if candidate == None:
 | 
						|
				return None
 | 
						|
			if candidate.name == "void":
 | 
						|
				return None
 | 
						|
			cont.args.append(candidate)
 | 
						|
		return cont
 | 
						|
 | 
						|
#Translators between Python and C++ containers
 | 
						|
#Base Type
 | 
						|
class Translator:
 | 
						|
	tmp_cntr = 0
 | 
						|
	typename = "DefaultType"
 | 
						|
	orig_name = "DefaultCpp"
 | 
						|
 | 
						|
	@classmethod
 | 
						|
	def gen_type(c, types):
 | 
						|
		return "\nImplement a function that outputs the c++ type of this container here\n"
 | 
						|
 | 
						|
	@classmethod
 | 
						|
	def translate(c, varname, types, prefix):
 | 
						|
		return "\nImplement a function translating a python container to a c++ container here\n"
 | 
						|
 | 
						|
	@classmethod
 | 
						|
	def translate_cpp(c, varname, types, prefix, ref):
 | 
						|
		return "\nImplement a function translating a c++ container to a python container here\n"
 | 
						|
 | 
						|
#Translates list-types (vector, pool, set), that only differ in their name and
 | 
						|
#the name of the insertion function
 | 
						|
class PythonListTranslator(Translator):
 | 
						|
	typename = "boost::python::list"
 | 
						|
	insert_name = "Default"
 | 
						|
 | 
						|
	#generate the c++ type string
 | 
						|
	@classmethod
 | 
						|
	def gen_type(c, types):
 | 
						|
		text = c.orig_name + "<"
 | 
						|
		if types[0].name in primitive_types:
 | 
						|
			text += types[0].name
 | 
						|
		elif types[0].name in known_containers:
 | 
						|
			text += known_containers[types[0].name].gen_type(types[0].cont.args)
 | 
						|
		else:
 | 
						|
			text += class_by_name(types[0].name).namespace + "::" + types[0].name
 | 
						|
			if types[0].attr_type == attr_types.star:
 | 
						|
				text += "*"
 | 
						|
		text += ">"
 | 
						|
		return text
 | 
						|
 | 
						|
	#Generate C++ code to translate from a boost::python::list
 | 
						|
	@classmethod
 | 
						|
	def translate(c, varname, types, prefix):
 | 
						|
		text  = prefix + c.gen_type(types) + " " + varname + "___tmp;"
 | 
						|
		cntr_name = "cntr_" + str(Translator.tmp_cntr)
 | 
						|
		Translator.tmp_cntr = Translator.tmp_cntr + 1
 | 
						|
		text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "); " + cntr_name + "++)"
 | 
						|
		text += prefix + "{"
 | 
						|
		tmp_name = "tmp_" + str(Translator.tmp_cntr)
 | 
						|
		Translator.tmp_cntr = Translator.tmp_cntr + 1
 | 
						|
		if types[0].name in known_containers:
 | 
						|
			text += prefix + "\t" + known_containers[types[0].name].typename + " " + tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "[" + cntr_name + "]);"
 | 
						|
			text += known_containers[types[0].name].translate(tmp_name, types[0].cont.args, prefix+"\t")
 | 
						|
			tmp_name = tmp_name + "___tmp"
 | 
						|
			text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + ");"
 | 
						|
		elif types[0].name in classnames:
 | 
						|
			text += prefix + "\t" + types[0].name + "* " + tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "[" + cntr_name + "]);"
 | 
						|
			if types[0].attr_type == attr_types.star:
 | 
						|
				text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + "->get_cpp_obj());"
 | 
						|
			else:
 | 
						|
				text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(*" + tmp_name + "->get_cpp_obj());"
 | 
						|
		else:
 | 
						|
			text += prefix + "\t" + types[0].name + " " + tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "[" + cntr_name + "]);"
 | 
						|
			text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + ");"
 | 
						|
		text += prefix + "}"
 | 
						|
		return text
 | 
						|
 | 
						|
	#Generate C++ code to translate to a boost::python::list
 | 
						|
	@classmethod
 | 
						|
	def translate_cpp(c, varname, types, prefix, ref):
 | 
						|
		text  = prefix + c.typename + " " + varname + "___tmp;"
 | 
						|
		tmp_name = "tmp_" + str(Translator.tmp_cntr)
 | 
						|
		Translator.tmp_cntr = Translator.tmp_cntr + 1
 | 
						|
		if ref:
 | 
						|
			text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
 | 
						|
		else:
 | 
						|
			text += prefix + "for(auto " + tmp_name + " : " + varname + ")"
 | 
						|
		text += prefix + "{"
 | 
						|
		if types[0].name in classnames:
 | 
						|
			if types[0].attr_type == attr_types.star:
 | 
						|
				text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));"
 | 
						|
			else:
 | 
						|
				text += prefix + "\t" + varname + "___tmp.append(*" + types[0].name + "::get_py_obj(&" + tmp_name + "));"
 | 
						|
		elif types[0].name in known_containers:
 | 
						|
			text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[0].attr_type == attr_types.star)
 | 
						|
			text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + "___tmp);"
 | 
						|
		else:
 | 
						|
			text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");"
 | 
						|
		text += prefix + "}"
 | 
						|
		return text
 | 
						|
 | 
						|
class IDictTranslator(PythonListTranslator):
 | 
						|
	typename = "boost::python::list"
 | 
						|
	orig_name = "idict"
 | 
						|
	insert_name = ""
 | 
						|
 | 
						|
#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"
 | 
						|
 | 
						|
#Sub-type for ObjRange
 | 
						|
class ObjRangeTranslator(PythonListTranslator):
 | 
						|
	orig_name = "RTLIL::ObjRange"
 | 
						|
 | 
						|
#Translates dict-types (dict, std::map), that only differ in their name and
 | 
						|
#the name of the insertion function
 | 
						|
class PythonDictTranslator(Translator):
 | 
						|
	typename = "boost::python::dict"
 | 
						|
	insert_name = "Default"
 | 
						|
 | 
						|
	@classmethod
 | 
						|
	def gen_type(c, types):
 | 
						|
		text = c.orig_name + "<"
 | 
						|
		if types[0].name in primitive_types:
 | 
						|
			text += types[0].name
 | 
						|
		elif types[0].name in known_containers:
 | 
						|
			text += known_containers[types[0].name].gen_type(types[0].cont.args)
 | 
						|
		else:
 | 
						|
			text += class_by_name(types[0].name).namespace + "::" + types[0].name
 | 
						|
			if types[0].attr_type == attr_types.star:
 | 
						|
				text += "*"
 | 
						|
		text += ", "
 | 
						|
		if types[1].name in primitive_types:
 | 
						|
			text += types[1].name
 | 
						|
		elif types[1].name in known_containers:
 | 
						|
			text += known_containers[types[1].name].gen_type(types[1].cont.args)
 | 
						|
		else:
 | 
						|
			text += class_by_name(types[1].name).namespace + "::" + types[1].name
 | 
						|
			if types[1].attr_type == attr_types.star:
 | 
						|
				text += "*"
 | 
						|
		text += ">"
 | 
						|
		return text
 | 
						|
 | 
						|
	#Generate c++ code to translate from a boost::python::dict
 | 
						|
	@classmethod
 | 
						|
	def translate(c, varname, types, prefix):
 | 
						|
		text  = prefix + c.gen_type(types) + " " + varname + "___tmp;"
 | 
						|
		text += prefix + "boost::python::list " + varname + "_keylist = " + varname + ".keys();"
 | 
						|
		cntr_name = "cntr_" + str(Translator.tmp_cntr)
 | 
						|
		Translator.tmp_cntr = Translator.tmp_cntr + 1
 | 
						|
		text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "_keylist); " + cntr_name + "++)"
 | 
						|
		text += prefix + "{"
 | 
						|
		key_tmp_name = "key_tmp_" + str(Translator.tmp_cntr)
 | 
						|
		val_tmp_name = "val_tmp_" + str(Translator.tmp_cntr)
 | 
						|
		Translator.tmp_cntr = Translator.tmp_cntr + 1
 | 
						|
 | 
						|
		if types[0].name in known_containers:
 | 
						|
			text += prefix + "\t" + known_containers[types[0].name].typename + " " + key_tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "_keylist[ " + cntr_name + " ]);"
 | 
						|
			text += known_containers[types[0].name].translate(key_tmp_name, types[0].cont.args, prefix+"\t")
 | 
						|
			key_tmp_name = key_tmp_name + "___tmp"
 | 
						|
		elif types[0].name in classnames:
 | 
						|
			text += prefix + "\t" + types[0].name + "* " + key_tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "_keylist[ " + cntr_name + " ]);"
 | 
						|
		else:
 | 
						|
			text += prefix + "\t" + types[0].name + " " + key_tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "_keylist[ " + cntr_name + " ]);"
 | 
						|
 | 
						|
		if types[1].name in known_containers:
 | 
						|
			text += prefix + "\t" + known_containers[types[1].name].typename + " " + val_tmp_name + " = boost::python::extract<" + known_containers[types[1].name].typename + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);"
 | 
						|
			text += known_containers[types[1].name].translate(val_tmp_name, types[1].cont.args, prefix+"\t")
 | 
						|
			val_tmp_name = val_tmp_name + "___tmp"
 | 
						|
		elif types[1].name in classnames:
 | 
						|
			text += prefix + "\t" + types[1].name + "* " + val_tmp_name + " = boost::python::extract<" + types[1].name + "*>(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);"
 | 
						|
		else:
 | 
						|
			text += prefix + "\t" + types[1].name + " " + val_tmp_name + " = boost::python::extract<" + types[1].name + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);"
 | 
						|
 | 
						|
		text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(std::pair<" + types[0].gen_text_cpp() + ", " + types[1].gen_text_cpp() + ">("
 | 
						|
 | 
						|
		if types[0].name not in classnames:
 | 
						|
			text += key_tmp_name
 | 
						|
		else:
 | 
						|
			if types[0].attr_type != attr_types.star:
 | 
						|
				text += "*"
 | 
						|
			text += key_tmp_name + "->get_cpp_obj()"
 | 
						|
 | 
						|
		text += ", "
 | 
						|
		if types[1].name not in classnames:
 | 
						|
			text += val_tmp_name
 | 
						|
		else:
 | 
						|
			if types[1].attr_type != attr_types.star:
 | 
						|
				text += "*"
 | 
						|
			text += val_tmp_name + "->get_cpp_obj()"
 | 
						|
		text += "));\n" + prefix + "}"
 | 
						|
		return text
 | 
						|
 | 
						|
	#Generate c++ code to translate to a boost::python::dict
 | 
						|
	@classmethod
 | 
						|
	def translate_cpp(c, varname, types, prefix, ref):
 | 
						|
		text  = prefix + c.typename + " " + varname + "___tmp;"
 | 
						|
		tmp_name = "tmp_" + str(Translator.tmp_cntr)
 | 
						|
		Translator.tmp_cntr = Translator.tmp_cntr + 1
 | 
						|
		if ref:
 | 
						|
			text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
 | 
						|
		else:
 | 
						|
			text += prefix + "for(auto " + tmp_name + " : " + varname + ")"
 | 
						|
		text += prefix + "{"
 | 
						|
		if types[1].name in known_containers:
 | 
						|
			text += prefix + "\tauto " + tmp_name + "_second = " + tmp_name + ".second;"
 | 
						|
			text += known_containers[types[1].name].translate_cpp(tmp_name + "_second", types[1].cont.args, prefix + "\t", types[1].attr_type == attr_types.star)
 | 
						|
 | 
						|
		if types[0].name in classnames:
 | 
						|
			text += prefix + "\t" + varname + "___tmp[" + types[0].name + "::get_py_obj(" + tmp_name + ".first)] = "
 | 
						|
		elif types[0].name not in known_containers:
 | 
						|
			text += prefix + "\t" + varname + "___tmp[" + tmp_name + ".first] = "
 | 
						|
 | 
						|
		if types[1].name in classnames:
 | 
						|
			if types[1].attr_type == attr_types.star:
 | 
						|
				text += types[1].name + "::get_py_obj(" + tmp_name + ".second);"
 | 
						|
			else:
 | 
						|
				text += "*" + types[1].name + "::get_py_obj(&" + tmp_name + ".second);"
 | 
						|
		elif types[1].name in known_containers:
 | 
						|
			text += tmp_name + "_second___tmp;"
 | 
						|
		else:
 | 
						|
			text += tmp_name + ".second;"
 | 
						|
		text += prefix + "}"
 | 
						|
		return text
 | 
						|
 | 
						|
#Sub-type for dict
 | 
						|
class DictTranslator(PythonDictTranslator):
 | 
						|
	insert_name = "insert"
 | 
						|
	orig_name = "dict"
 | 
						|
 | 
						|
#Sub_type for std::map
 | 
						|
class MapTranslator(PythonDictTranslator):
 | 
						|
	insert_name = "insert"
 | 
						|
	orig_name = "std::map"
 | 
						|
 | 
						|
#Translator for std::pair. Derived from PythonDictTranslator because the
 | 
						|
#gen_type function is the same (because both have two template parameters)
 | 
						|
class TupleTranslator(PythonDictTranslator):
 | 
						|
	typename = "boost::python::tuple"
 | 
						|
	orig_name = "std::pair"
 | 
						|
 | 
						|
	#Generate c++ code to translate from a boost::python::tuple
 | 
						|
	@classmethod
 | 
						|
	def translate(c, varname, types, prefix):
 | 
						|
		text  = prefix + types[0].name + " " + varname + "___tmp_0 = boost::python::extract<" + types[0].name + ">(" + varname + "[0]);"
 | 
						|
		text += prefix + types[1].name + " " + varname + "___tmp_1 = boost::python::extract<" + types[1].name + ">(" + varname + "[1]);"
 | 
						|
		text += prefix + TupleTranslator.gen_type(types) + " " + varname + "___tmp("
 | 
						|
		if types[0].name.split(" ")[-1] in primitive_types:
 | 
						|
			text += varname + "___tmp_0, "
 | 
						|
		else:
 | 
						|
			text += "*" + varname + "___tmp_0.get_cpp_obj(), "
 | 
						|
		if types[1].name.split(" ")[-1] in primitive_types:
 | 
						|
			text += varname + "___tmp_1);"
 | 
						|
		else:
 | 
						|
			text += "*" + varname + "___tmp_1.get_cpp_obj());"
 | 
						|
		return text
 | 
						|
 | 
						|
	#Generate c++ code to translate to a boost::python::tuple
 | 
						|
	@classmethod
 | 
						|
	def translate_cpp(c, varname, types, prefix, ref):
 | 
						|
		# if the tuple is a pair of SigSpecs (aka SigSig), then we need
 | 
						|
		# to call get_py_obj() on each item in the tuple
 | 
						|
		if types[0].name in classnames:
 | 
						|
			first_var = types[0].name + "::get_py_obj(" + varname + ".first)"
 | 
						|
		else:
 | 
						|
			first_var = varname + ".first"
 | 
						|
		if types[1].name in classnames:
 | 
						|
			second_var = types[1].name + "::get_py_obj(" + varname + ".second)"
 | 
						|
		else:
 | 
						|
			second_var = varname + ".second"
 | 
						|
		text  = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");"
 | 
						|
		return text
 | 
						|
 | 
						|
#Associate the Translators with their c++ type
 | 
						|
known_containers = {
 | 
						|
	"std::set"        : SetTranslator,
 | 
						|
	"std::vector"     : VectorTranslator,
 | 
						|
	"pool"            : PoolTranslator,
 | 
						|
	"idict"           : IDictTranslator,
 | 
						|
	"dict"            : DictTranslator,
 | 
						|
	"std::pair"       : TupleTranslator,
 | 
						|
	"std::map"        : MapTranslator,
 | 
						|
	"RTLIL::ObjRange" : ObjRangeTranslator
 | 
						|
}
 | 
						|
 | 
						|
class Attribute:
 | 
						|
	wtype = None
 | 
						|
	varname = None
 | 
						|
	is_const = False
 | 
						|
	default_value = None
 | 
						|
	pos = None
 | 
						|
	pos_counter = 0
 | 
						|
	coerce_arg = None
 | 
						|
 | 
						|
	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, *, owner_fn_name=""):
 | 
						|
		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:]
 | 
						|
 | 
						|
		# handle string views
 | 
						|
		if arg.wtype.name in ["std::string_view", "string_view"]:
 | 
						|
			if arg.varname == "format" and owner_fn_name.startswith("log_"):
 | 
						|
				# coerce format strings to "%s" (not bridgable)
 | 
						|
				arg.coerce_arg = '"%s"'
 | 
						|
			elif arg.varname == "prefix" and "warning" in owner_fn_name:
 | 
						|
				# coerce warning prefix to "warning:"
 | 
						|
				arg.coerce_arg = '"Warning: "'
 | 
						|
			else:
 | 
						|
				# boost::python can't bridge string views, so just copy them
 | 
						|
				arg.wtype.name = "string"
 | 
						|
 | 
						|
		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
 | 
						|
	base_class = 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.base_class = None
 | 
						|
		self.link_type = link_type
 | 
						|
		self.id_ = id_
 | 
						|
		self.string_id = string_id
 | 
						|
		self.hash_id = hash_id
 | 
						|
		self.needs_clone = needs_clone
 | 
						|
		self.found_funs = []
 | 
						|
		self.found_vars = []
 | 
						|
		self.found_constrs = []
 | 
						|
 | 
						|
	def printable_constrs(self):
 | 
						|
		ret = 0
 | 
						|
		for con in self.found_constrs:
 | 
						|
			if not con.protected:
 | 
						|
				ret += 1
 | 
						|
		return ret
 | 
						|
 | 
						|
	def gen_decl(self, filename):
 | 
						|
		long_name = self.namespace + "::" + self.name
 | 
						|
 | 
						|
		text = "\n\t// WRAPPED from " + filename
 | 
						|
		text += "\n\tstruct " + self.name
 | 
						|
		if self.link_type == link_types.derive:
 | 
						|
			text += " : public " + self.namespace + "::" + self.name
 | 
						|
		text += "\n\t{\n"
 | 
						|
 | 
						|
		if self.link_type != link_types.derive:
 | 
						|
 | 
						|
			text += "\t\t" + long_name + "* ref_obj;\n"
 | 
						|
 | 
						|
			if self.link_type == link_types.ref_copy or self.link_type == link_types.pointer:
 | 
						|
				text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n"
 | 
						|
			elif self.link_type == link_types.global_list:
 | 
						|
				text += "\t\t" + self.id_.wtype.name + " " + self.id_.varname + ";\n"
 | 
						|
				text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{"
 | 
						|
				text += "\n\t\t\t" + long_name + "* ret = " + long_name + "::get_all_" + self.name.lower() + "s()->at(this->" + self.id_.varname + ");"
 | 
						|
				text += "\n\t\t\tif(ret != NULL && ret == this->ref_obj)"
 | 
						|
				text += "\n\t\t\t\treturn ret;"
 | 
						|
				text += "\n\t\t\tthrow std::runtime_error(\"" + self.name + "'s c++ object does not exist anymore.\");"
 | 
						|
				text += "\n\t\t\treturn NULL;"
 | 
						|
				text += "\n\t\t}\n"
 | 
						|
 | 
						|
			#if self.link_type != link_types.pointer:
 | 
						|
			text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{"
 | 
						|
			text += "\n\t\t\tif(ref == nullptr){"
 | 
						|
			text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");"
 | 
						|
			text += "\n\t\t\t}"
 | 
						|
			text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));"
 | 
						|
			if self.link_type == link_types.pointer:
 | 
						|
				text += "\n\t\t\tret->ref_obj = ref;"
 | 
						|
			if self.link_type == link_types.ref_copy:
 | 
						|
				if self.needs_clone:
 | 
						|
					text += "\n\t\t\tret->ref_obj = ref->clone();"
 | 
						|
				else:
 | 
						|
					text += "\n\t\t\tret->ref_obj = new "+long_name+"(*ref);"
 | 
						|
			if self.link_type == link_types.global_list:
 | 
						|
				text += "\n\t\t\tret->ref_obj = ref;"
 | 
						|
				text += "\n\t\t\tret->" + self.id_.varname + " = ret->ref_obj->" + self.id_.varname + ";"
 | 
						|
			text += "\n\t\t\treturn ret;"
 | 
						|
			text += "\n\t\t}\n"
 | 
						|
 | 
						|
			if self.link_type == link_types.ref_copy:
 | 
						|
				text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + " ref)\n\t\t{"
 | 
						|
				text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));"
 | 
						|
				if self.needs_clone:
 | 
						|
					text += "\n\t\t\tret->ref_obj = ref.clone();"
 | 
						|
				else:
 | 
						|
					text += "\n\t\t\tret->ref_obj = new "+long_name+"(ref);"
 | 
						|
				text += "\n\t\t\treturn ret;"
 | 
						|
				text += "\n\t\t}\n"
 | 
						|
 | 
						|
			for con in self.found_constrs:
 | 
						|
				text += con.gen_decl()
 | 
						|
			if self.base_class is not None:
 | 
						|
				text += "\n\t\tvirtual ~" + self.name + "() { };"
 | 
						|
			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{"
 | 
						|
			suffix = f"->{self.hash_id}" if self.hash_id else f"->{self.hash_id}"
 | 
						|
			if self.hash_id == "":
 | 
						|
				text += f"\n\t\t\treturn run_hash(*(get_cpp_obj()));"
 | 
						|
			else:
 | 
						|
				text += f"\n\t\t\treturn run_hash(get_cpp_obj()->{self.hash_id});"
 | 
						|
			text += "\n\t\t}"
 | 
						|
 | 
						|
		text += "\n\t};\n"
 | 
						|
 | 
						|
		if self.link_type == link_types.derive:
 | 
						|
			text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">"
 | 
						|
			text += "\n\t{"
 | 
						|
 | 
						|
			for con in self.found_constrs:
 | 
						|
				text += con.gen_decl_wrapperclass()
 | 
						|
			for fun in self.found_funs:
 | 
						|
				text += fun.gen_default_impl()
 | 
						|
 | 
						|
			text += "\n\t};"
 | 
						|
 | 
						|
		text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)"
 | 
						|
		text += "\n\t{"
 | 
						|
		text += "\n\t\tostr << \"" + self.name
 | 
						|
		if self.string_id != None:
 | 
						|
			text +=" \\\"\""
 | 
						|
			text += " << ref.get_cpp_obj()->" + self.string_id
 | 
						|
			text += " << \"\\\"\""
 | 
						|
		else:
 | 
						|
			text += " at \" << ref.get_cpp_obj()"
 | 
						|
		text += ";"
 | 
						|
		text += "\n\t\treturn ostr;"
 | 
						|
		text += "\n\t}"
 | 
						|
		text += "\n"
 | 
						|
 | 
						|
		return text
 | 
						|
 | 
						|
	def gen_funs(self, filename):
 | 
						|
		text = ""
 | 
						|
		if self.link_type != link_types.derive:
 | 
						|
			for con in self.found_constrs:
 | 
						|
				text += con.gen_def()
 | 
						|
			for var in self.found_vars:
 | 
						|
				text += var.gen_def()
 | 
						|
			for fun in self.found_funs:
 | 
						|
				text += fun.gen_def()
 | 
						|
		else:
 | 
						|
			for var in self.found_vars:
 | 
						|
				text += var.gen_def()
 | 
						|
			for fun in self.found_funs:
 | 
						|
				text += fun.gen_def_virtual()
 | 
						|
		return text
 | 
						|
 | 
						|
	def gen_boost_py_body(self):
 | 
						|
		text = ""
 | 
						|
		if self.printable_constrs() == 0 or not self.contains_default_constr():
 | 
						|
			text += ", no_init"
 | 
						|
		text += ")"
 | 
						|
		text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))"
 | 
						|
		text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))"
 | 
						|
		for con in self.found_constrs:
 | 
						|
			text += con.gen_boost_py()
 | 
						|
		for var in self.found_vars:
 | 
						|
			text += var.gen_boost_py()
 | 
						|
		static_funs = []
 | 
						|
		for fun in self.found_funs:
 | 
						|
			text += fun.gen_boost_py()
 | 
						|
			if fun.is_static and fun.alias not in static_funs:
 | 
						|
				static_funs.append(fun.alias)
 | 
						|
		for fun in static_funs:
 | 
						|
			text += "\n\t\t\t.staticmethod(\"" + fun + "\")"
 | 
						|
 | 
						|
		if self.hash_id != None:
 | 
						|
			text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)"
 | 
						|
		text += "\n\t\t\t;\n"
 | 
						|
		return text
 | 
						|
 | 
						|
	def gen_boost_py(self):
 | 
						|
		body = self.gen_boost_py_body()
 | 
						|
		base_info = ""
 | 
						|
		if self.base_class is not None:
 | 
						|
			base_info = ", bases<" + (self.base_class.name) + ">"
 | 
						|
 | 
						|
		if self.link_type == link_types.derive:
 | 
						|
			text = "\n\t\tclass_<" + self.name + base_info + ">(\"Cpp" + self.name + "\""
 | 
						|
			text += body
 | 
						|
			text += "\n\t\tclass_<" + self.name
 | 
						|
			text += "Wrap, boost::noncopyable"
 | 
						|
			text += ">(\"" + self.name + "\""
 | 
						|
			text += body
 | 
						|
		else:
 | 
						|
			text = "\n\t\tclass_<" + self.name + base_info + ">(\"" + self.name + "\""
 | 
						|
			text += body
 | 
						|
		return text
 | 
						|
 | 
						|
 | 
						|
	def contains_default_constr(self):
 | 
						|
		for c in self.found_constrs:
 | 
						|
			if len(c.args) == 0:
 | 
						|
				return True
 | 
						|
		return False
 | 
						|
 | 
						|
#CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE
 | 
						|
 | 
						|
sources = [
 | 
						|
	Source("kernel/celltypes",[
 | 
						|
		WClass("CellType", link_types.pointer, None, None, "type", 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()", ""),
 | 
						|
		WClass("Const", link_types.ref_copy, None, "as_string()", ""),
 | 
						|
		WClass("AttrObject", link_types.ref_copy, None, None, None),
 | 
						|
		WClass("NamedObject", 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"),
 | 
						|
		WClass("SigChunk", link_types.ref_copy, None, None, None),
 | 
						|
		WClass("SigBit", link_types.ref_copy, None, None, ""),
 | 
						|
		WClass("SigSpec", link_types.ref_copy, None, None, ""),
 | 
						|
		WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
 | 
						|
		WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
 | 
						|
		WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
 | 
						|
		WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""),
 | 
						|
		WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "")
 | 
						|
		]
 | 
						|
		),
 | 
						|
	#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"]
 | 
						|
 | 
						|
enum_names = ["State","SyncType","ConstFlags"]
 | 
						|
 | 
						|
enums = [] #Do not edit
 | 
						|
glbls = []
 | 
						|
 | 
						|
unowned_functions = []
 | 
						|
 | 
						|
classnames = []
 | 
						|
for source in sources:
 | 
						|
	for wclass in source.classes:
 | 
						|
		classnames.append(wclass.name)
 | 
						|
 | 
						|
def class_by_name(name):
 | 
						|
	for source in sources:
 | 
						|
		for wclass in source.classes:
 | 
						|
			if wclass.name == name:
 | 
						|
				return wclass
 | 
						|
	return None
 | 
						|
 | 
						|
def enum_by_name(name):
 | 
						|
	for e in enums:
 | 
						|
		if e.name == name:
 | 
						|
			return e
 | 
						|
	return None
 | 
						|
 | 
						|
def find_closing(text, open_tok, close_tok):
 | 
						|
	if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok):
 | 
						|
		return text.find(close_tok)
 | 
						|
	return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1
 | 
						|
 | 
						|
def unpretty_string(s):
 | 
						|
	s = s.strip()
 | 
						|
	while s.find("  ") != -1:
 | 
						|
		s = s.replace("  "," ")
 | 
						|
	while s.find("\t") != -1:
 | 
						|
		s = s.replace("\t"," ")
 | 
						|
	s = s.replace(" (","(")
 | 
						|
	return s
 | 
						|
 | 
						|
class WEnum:
 | 
						|
	name = None
 | 
						|
	namespace = None
 | 
						|
	values = []
 | 
						|
 | 
						|
	def from_string(str_def, namespace, line_number):
 | 
						|
		str_def = str_def.strip()
 | 
						|
		if not str.startswith(str_def, "enum "):
 | 
						|
			return None
 | 
						|
		if str_def.count(";") != 1:
 | 
						|
			return None
 | 
						|
		str_def = str_def[5:]
 | 
						|
		enum = WEnum()
 | 
						|
		split = str_def.split(":")
 | 
						|
		if(len(split) != 2):
 | 
						|
			return None
 | 
						|
		enum.name = split[0].strip()
 | 
						|
		if enum.name not in enum_names:
 | 
						|
			return None
 | 
						|
		str_def = split[1]
 | 
						|
		if str_def.count("{") != str_def.count("}") != 1:
 | 
						|
			return None
 | 
						|
		if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';':
 | 
						|
			return None
 | 
						|
		str_def = str_def.split("{")[-1].split("}")[0]
 | 
						|
		enum.values = []
 | 
						|
		for val in str_def.split(','):
 | 
						|
			enum.values.append(val.strip().split('=')[0].strip())
 | 
						|
		enum.namespace = namespace
 | 
						|
		return enum
 | 
						|
 | 
						|
	def gen_boost_py(self):
 | 
						|
		text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n"
 | 
						|
		for value in self.values:
 | 
						|
			text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n"
 | 
						|
		text += "\t\t\t;\n"
 | 
						|
		return text
 | 
						|
 | 
						|
	def __str__(self):
 | 
						|
		ret = "Enum " + self.namespace + "::" + self.name + "(\n"
 | 
						|
		for val in self.values:
 | 
						|
			ret = ret + "\t" + val + "\n"
 | 
						|
		return ret + ")"
 | 
						|
 | 
						|
	def __repr__(self):
 | 
						|
		return __str__(self)
 | 
						|
 | 
						|
class WConstructor:
 | 
						|
	orig_text = None
 | 
						|
	args = []
 | 
						|
	containing_file = None
 | 
						|
	member_of = None
 | 
						|
	duplicate = False
 | 
						|
	protected = False
 | 
						|
 | 
						|
	def __init__(self, containing_file, class_):
 | 
						|
		self.orig_text = "Auto generated default constructor"
 | 
						|
		self.args = []
 | 
						|
		self.containing_file = containing_file
 | 
						|
		self.member_of = class_
 | 
						|
		self.protected = False
 | 
						|
 | 
						|
	def from_string(str_def, containing_file, class_, line_number, protected = False):
 | 
						|
		if class_ == None:
 | 
						|
			return None
 | 
						|
		if str_def.count("delete;") > 0:
 | 
						|
			return None
 | 
						|
		con = WConstructor(containing_file, class_)
 | 
						|
		con.orig_text = str_def
 | 
						|
		con.args = []
 | 
						|
		con.duplicate = False
 | 
						|
		con.protected = protected
 | 
						|
		if str.startswith(str_def, "inline "):
 | 
						|
			str_def = str_def[7:]
 | 
						|
		if not str.startswith(str_def, class_.name + "("):
 | 
						|
			return None
 | 
						|
		str_def = str_def[len(class_.name)+1:]
 | 
						|
		found = find_closing(str_def, "(", ")")
 | 
						|
		if found == -1:
 | 
						|
			return None
 | 
						|
		str_def = str_def[0:found].strip()
 | 
						|
		if len(str_def) == 0:
 | 
						|
			return con
 | 
						|
		args = split_list(str_def, ",")
 | 
						|
		for i, arg in enumerate(args):
 | 
						|
			parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
 | 
						|
			if parsed == None:
 | 
						|
				return None
 | 
						|
			# Only allow std::source_location as defaulted last argument, and
 | 
						|
			# don't append so it takes default value
 | 
						|
			if parsed.wtype.name in ["std::source_location", "source_location"]:
 | 
						|
				if parsed.default_value is None or i != len(args) - 1:
 | 
						|
					debug("std::source_location not defaulted last arg of " + class_.name + " is unsupported", 2)
 | 
						|
					return None
 | 
						|
				continue
 | 
						|
			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.is_const = 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")
 | 
						|
 | 
						|
		# remove attributes from the start
 | 
						|
		if str.startswith(str_def, "[[") and "]]" in str_def:
 | 
						|
			str_def = str_def[str_def.find("]]")+2:]
 | 
						|
 | 
						|
		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", "const"]:
 | 
						|
				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
 | 
						|
 | 
						|
		post_qualifiers = str_def[found + 1:].lstrip().replace("{", " {") + " "
 | 
						|
		if post_qualifiers.startswith("const "):
 | 
						|
			func.is_const = True
 | 
						|
 | 
						|
		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
 | 
						|
		args = split_list(str_def, ",")
 | 
						|
		for i, arg in enumerate(args):
 | 
						|
			if arg.strip() == "...":
 | 
						|
				continue
 | 
						|
			parsed = Attribute.from_string(arg.strip(), containing_file, line_number, owner_fn_name=func.name)
 | 
						|
			if parsed == None:
 | 
						|
				return None
 | 
						|
			# Only allow std::source_location as defaulted last argument, and
 | 
						|
			# don't append so it takes default value
 | 
						|
			if parsed.wtype.name in ["std::source_location", "source_location"]:
 | 
						|
				if parsed.default_value is None or i != len(args) - 1:
 | 
						|
					debug("std::source_location not defaulted last arg of " + func.name + " is unsupported", 2)
 | 
						|
					return None
 | 
						|
				continue
 | 
						|
			func.args.append(parsed)
 | 
						|
		return func
 | 
						|
 | 
						|
	@property
 | 
						|
	def mangled_name(self):
 | 
						|
		mangled_typename = lambda code: code.replace("::", "_").replace("<","_").replace(">","_") \
 | 
						|
										   .replace(" ","").replace("*","").replace(",","")
 | 
						|
 | 
						|
		return self.name + "".join(
 | 
						|
			f"__{mangled_typename(arg.wtype.gen_text_cpp())}" for arg in self.args
 | 
						|
		)
 | 
						|
 | 
						|
	def gen_alias(self):
 | 
						|
		self.alias = self.mangled_name
 | 
						|
 | 
						|
	def gen_post_qualifiers(self, derived=False):
 | 
						|
		if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual and derived:
 | 
						|
			# we drop the qualifiers when deriving callbacks to be implemented in Python
 | 
						|
			return ''
 | 
						|
		return ' const' if self.is_const else ''
 | 
						|
 | 
						|
	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:
 | 
						|
			if arg.coerce_arg:
 | 
						|
				continue
 | 
						|
			text += arg.gen_listitem()
 | 
						|
			text += ", "
 | 
						|
		if len(self.args) > 0:
 | 
						|
			text = text[:-2]
 | 
						|
		text += f"){self.gen_post_qualifiers()};\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 and self.ret_type.name == "void":
 | 
						|
			text += "{}"
 | 
						|
		else:
 | 
						|
			text += "\n\t\t{"
 | 
						|
			for arg in self.args:
 | 
						|
				text += "\n\t\t\t(void)" + arg.gen_varname() + ";"
 | 
						|
			if self.ret_type.name == "void":
 | 
						|
				pass
 | 
						|
			elif self.ret_type.name == "bool":
 | 
						|
				text += "\n\t\t\treturn false;"
 | 
						|
			else:
 | 
						|
				raise NotImplementedError(self.ret_type.name)
 | 
						|
			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 += f"){self.gen_post_qualifiers()} 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:
 | 
						|
			if arg.coerce_arg:
 | 
						|
				continue
 | 
						|
			text += arg.gen_listitem()
 | 
						|
			text += ", "
 | 
						|
		if len(self.args) > 0:
 | 
						|
			text = text[:-2]
 | 
						|
		text += f"){self.gen_post_qualifiers()}\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.name + "("
 | 
						|
		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.coerce_arg or arg.gen_call()
 | 
						|
			text += ", "
 | 
						|
		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 += f"){self.gen_post_qualifiers()}\n\t{{"
 | 
						|
		for arg in self.args:
 | 
						|
			text += arg.gen_translation_cpp()
 | 
						|
		return_stmt = "return " if self.ret_type.name != "void" else ""
 | 
						|
		text += f"\n\t\t{return_stmt}"
 | 
						|
		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 += f"const_cast<{self.member_of.name}*>(this)->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 += ");"
 | 
						|
 | 
						|
		return_stmt = "return " if self.ret_type.name != "void" else ""
 | 
						|
 | 
						|
		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\ttry {"
 | 
						|
		text += f"\n\t\t\t\t\t{return_stmt}" + call_string
 | 
						|
		text += "\n\t\t\t\t} catch (boost::python::error_already_set &) {"
 | 
						|
		text += "\n\t\t\t\t\tlog_python_exception_as_error();"
 | 
						|
		text += "\n\t\t\t\t}"
 | 
						|
		text += "\n\t\t\t} else {"
 | 
						|
		text += f"\n\t\t\t\t{return_stmt}" + self.member_of.name + "::" + call_string
 | 
						|
		text += "\n\t\t\t}"
 | 
						|
		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 += f")\n\t\t{{"
 | 
						|
		text += f"\n\t\t\t{return_stmt}this->" + 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:
 | 
						|
				if a.coerce_arg:
 | 
						|
					continue
 | 
						|
				text += a.gen_listitem_hash() + ", "
 | 
						|
			if len(self.args) > 0:
 | 
						|
				text = text[0:-2] + f"){self.gen_post_qualifiers(True)}>"
 | 
						|
			else:
 | 
						|
				text += f"void){self.gen_post_qualifiers(True)}>"
 | 
						|
 | 
						|
		if self.is_operator:
 | 
						|
			text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\""
 | 
						|
		else:
 | 
						|
			if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual:
 | 
						|
				text += "(\"py_" + self.alias + "\""
 | 
						|
			else:
 | 
						|
				text += "(\"" + self.alias + "\""
 | 
						|
		if self.member_of != None:
 | 
						|
			text += ", &" + self.member_of.name + "::"
 | 
						|
			if self.member_of.link_type == link_types.derive and self.is_virtual:
 | 
						|
				text += "py_" + self.alias
 | 
						|
				text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias
 | 
						|
			else:
 | 
						|
				text += self.alias
 | 
						|
 | 
						|
			text += ")"
 | 
						|
		else:
 | 
						|
			text += ", " + "YOSYS_PYTHON::" + self.alias + ");"
 | 
						|
		return text
 | 
						|
 | 
						|
class WMember:
 | 
						|
	orig_text = None
 | 
						|
	wtype = attr_types.default
 | 
						|
	name = None
 | 
						|
	containing_file = None
 | 
						|
	member_of = None
 | 
						|
	namespace = ""
 | 
						|
	is_const = False
 | 
						|
 | 
						|
	def from_string(str_def, containing_file, class_, line_number, namespace):
 | 
						|
		member = WMember()
 | 
						|
		member.orig_text = str_def
 | 
						|
		member.wtype = None
 | 
						|
		member.name = ""
 | 
						|
		member.containing_file = containing_file
 | 
						|
		member.member_of = class_
 | 
						|
		member.namespace = namespace
 | 
						|
		member.is_const = False
 | 
						|
 | 
						|
		if str.startswith(str_def, "const "):
 | 
						|
			member.is_const = True
 | 
						|
			str_def = str_def[6:]
 | 
						|
 | 
						|
		if str_def.count(" ") == 0:
 | 
						|
			return None
 | 
						|
 | 
						|
		parts = split_list(str_def.strip(), " ")
 | 
						|
 | 
						|
		prefix = ""
 | 
						|
		i = 0
 | 
						|
		for part in parts:
 | 
						|
			if part in ["unsigned", "long", "short"]:
 | 
						|
				prefix += part + " "
 | 
						|
				i += 1
 | 
						|
			else:
 | 
						|
				break
 | 
						|
		parts = parts[i:]
 | 
						|
 | 
						|
		if len(parts) <= 1:
 | 
						|
			return None
 | 
						|
 | 
						|
		member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number)
 | 
						|
 | 
						|
		if member.wtype == None:
 | 
						|
			return None
 | 
						|
 | 
						|
		str_def = parts[1]
 | 
						|
		for part in parts[2:]:
 | 
						|
			str_def = str_def + " " + part
 | 
						|
 | 
						|
		if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1:
 | 
						|
			return None
 | 
						|
 | 
						|
		found = str_def.find(";")
 | 
						|
		if found == -1:
 | 
						|
			return None
 | 
						|
 | 
						|
		found_eq = str_def.find("=")
 | 
						|
		if found_eq != -1:
 | 
						|
			found = found_eq
 | 
						|
 | 
						|
		member.name = str_def[:found]
 | 
						|
		str_def = str_def[found+1:]
 | 
						|
		if member.name.find("*") == 0:
 | 
						|
			member.name = member.name.replace("*", "")
 | 
						|
			member.wtype.attr_type = attr_types.star
 | 
						|
		if member.name.find("&&") == 0:
 | 
						|
			member.name = member.name.replace("&&", "")
 | 
						|
			member.wtype.attr_type = attr_types.ampamp
 | 
						|
		if member.name.find("&") == 0:
 | 
						|
			member.name = member.name.replace("&", "")
 | 
						|
			member.wtype.attr_type = attr_types.amp
 | 
						|
 | 
						|
		if(len(str_def.strip()) != 0):
 | 
						|
			return None
 | 
						|
 | 
						|
		if len(member.name.split(",")) > 1:
 | 
						|
			member_list = []
 | 
						|
			for name in member.name.split(","):
 | 
						|
				name = name.strip();
 | 
						|
				member_list.append(WMember())
 | 
						|
				member_list[-1].orig_text = member.orig_text
 | 
						|
				member_list[-1].wtype = member.wtype
 | 
						|
				member_list[-1].name = name
 | 
						|
				member_list[-1].containing_file = member.containing_file
 | 
						|
				member_list[-1].member_of = member.member_of
 | 
						|
				member_list[-1].namespace = member.namespace
 | 
						|
				member_list[-1].is_const = member.is_const
 | 
						|
			return member_list
 | 
						|
 | 
						|
		return member
 | 
						|
 | 
						|
	def gen_decl(self):
 | 
						|
		text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n"
 | 
						|
		if self.is_const:
 | 
						|
			return text
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n"
 | 
						|
		else:
 | 
						|
			text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n"
 | 
						|
		return text
 | 
						|
 | 
						|
	def gen_def(self):
 | 
						|
		text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()"
 | 
						|
		text += "\n\t{\n\t\t"
 | 
						|
		if self.wtype.attr_type == attr_types.star:
 | 
						|
			text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t"
 | 
						|
			text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t"
 | 
						|
		if self.wtype.name in known_containers:
 | 
						|
			text += self.wtype.gen_text_cpp()
 | 
						|
		else:
 | 
						|
			text += self.wtype.gen_text()
 | 
						|
 | 
						|
		if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star):
 | 
						|
			text += "*"
 | 
						|
		text += " ret_ = "
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += self.wtype.name + "::get_py_obj("
 | 
						|
			if self.wtype.attr_type != attr_types.star:
 | 
						|
				text += "&"
 | 
						|
		text += "this->get_cpp_obj()->" + self.name
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += ")"
 | 
						|
		text += ";"
 | 
						|
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += "\n\t\treturn *ret_;"
 | 
						|
		elif self.wtype.name in known_containers:
 | 
						|
			text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star)
 | 
						|
			text += "\n\t\treturn ret____tmp;"
 | 
						|
		else:
 | 
						|
			text += "\n\t\treturn ret_;"
 | 
						|
		text += "\n\t}\n"
 | 
						|
 | 
						|
		if self.is_const:
 | 
						|
			return text
 | 
						|
 | 
						|
		ret = Attribute(self.wtype, "rhs");
 | 
						|
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)"
 | 
						|
		else:
 | 
						|
			text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)"
 | 
						|
		text += "\n\t{"
 | 
						|
		text += ret.gen_translation()
 | 
						|
		text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";"
 | 
						|
		text += "\n\t}\n"
 | 
						|
 | 
						|
		return text;
 | 
						|
 | 
						|
	def gen_boost_py(self):
 | 
						|
		text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name
 | 
						|
		if not self.is_const:
 | 
						|
			text += ", &" + self.member_of.name + "::set_var_py_" + self.name
 | 
						|
		text += ")"
 | 
						|
		return text
 | 
						|
 | 
						|
class WGlobal:
 | 
						|
	orig_text = None
 | 
						|
	wtype = attr_types.default
 | 
						|
	name = None
 | 
						|
	containing_file = None
 | 
						|
	namespace = ""
 | 
						|
	is_const = False
 | 
						|
 | 
						|
	def from_string(str_def, containing_file, line_number, namespace):
 | 
						|
		glbl = WGlobal()
 | 
						|
		glbl.orig_text = str_def
 | 
						|
		glbl.wtype = None
 | 
						|
		glbl.name = ""
 | 
						|
		glbl.containing_file = containing_file
 | 
						|
		glbl.namespace = namespace
 | 
						|
		glbl.is_const = False
 | 
						|
 | 
						|
		if not str.startswith(str_def, "extern"):
 | 
						|
			return None
 | 
						|
		str_def = str_def[7:]
 | 
						|
 | 
						|
		if str.startswith(str_def, "const "):
 | 
						|
			glbl.is_const = True
 | 
						|
			str_def = str_def[6:]
 | 
						|
 | 
						|
		if str_def.count(" ") == 0:
 | 
						|
			return None
 | 
						|
 | 
						|
		parts = split_list(str_def.strip(), " ")
 | 
						|
 | 
						|
		prefix = ""
 | 
						|
		i = 0
 | 
						|
		for part in parts:
 | 
						|
			if part in ["unsigned", "long", "short"]:
 | 
						|
				prefix += part + " "
 | 
						|
				i += 1
 | 
						|
			else:
 | 
						|
				break
 | 
						|
		parts = parts[i:]
 | 
						|
 | 
						|
		if len(parts) <= 1:
 | 
						|
			return None
 | 
						|
 | 
						|
		glbl.wtype = WType.from_string(prefix + parts[0], containing_file, line_number)
 | 
						|
 | 
						|
		if glbl.wtype == None:
 | 
						|
			return None
 | 
						|
 | 
						|
		str_def = parts[1]
 | 
						|
		for part in parts[2:]:
 | 
						|
			str_def = str_def + " " + part
 | 
						|
 | 
						|
		if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1:
 | 
						|
			return None
 | 
						|
 | 
						|
		found = str_def.find(";")
 | 
						|
		if found == -1:
 | 
						|
			return None
 | 
						|
 | 
						|
		found_eq = str_def.find("=")
 | 
						|
		if found_eq != -1:
 | 
						|
			found = found_eq
 | 
						|
 | 
						|
		glbl.name = str_def[:found]
 | 
						|
		str_def = str_def[found+1:]
 | 
						|
		if glbl.name.find("*") == 0:
 | 
						|
			glbl.name = glbl.name.replace("*", "")
 | 
						|
			glbl.wtype.attr_type = attr_types.star
 | 
						|
		if glbl.name.find("&&") == 0:
 | 
						|
			glbl.name = glbl.name.replace("&&", "")
 | 
						|
			glbl.wtype.attr_type = attr_types.ampamp
 | 
						|
		if glbl.name.find("&") == 0:
 | 
						|
			glbl.name = glbl.name.replace("&", "")
 | 
						|
			glbl.wtype.attr_type = attr_types.amp
 | 
						|
 | 
						|
		if(len(str_def.strip()) != 0):
 | 
						|
			return None
 | 
						|
 | 
						|
		if len(glbl.name.split(",")) > 1:
 | 
						|
			glbl_list = []
 | 
						|
			for name in glbl.name.split(","):
 | 
						|
				name = name.strip();
 | 
						|
				glbl_list.append(WGlobal())
 | 
						|
				glbl_list[-1].orig_text = glbl.orig_text
 | 
						|
				glbl_list[-1].wtype = glbl.wtype
 | 
						|
				glbl_list[-1].name = name
 | 
						|
				glbl_list[-1].containing_file = glbl.containing_file
 | 
						|
				glbl_list[-1].namespace = glbl.namespace
 | 
						|
				glbl_list[-1].is_const = glbl.is_const
 | 
						|
			return glbl_list
 | 
						|
 | 
						|
		return glbl
 | 
						|
 | 
						|
	def gen_def(self):
 | 
						|
		text = "\n\t"
 | 
						|
		if self.is_const:
 | 
						|
			text += "const "
 | 
						|
		text += self.wtype.gen_text() + " get_var_py_" + self.name + "()"
 | 
						|
		text += "\n\t{\n\t\t"
 | 
						|
		if self.wtype.attr_type == attr_types.star:
 | 
						|
			text += "if(" + self.namespace + "::" + self.name + " == NULL)\n\t\t\t"
 | 
						|
			text += "throw std::runtime_error(\"" + self.namespace + "::" + self.name + " is NULL\");\n\t\t"
 | 
						|
		if self.wtype.name in known_containers:
 | 
						|
			text += self.wtype.gen_text_cpp()
 | 
						|
		else:
 | 
						|
			if self.is_const:
 | 
						|
				text += "const "
 | 
						|
			text += self.wtype.gen_text()
 | 
						|
 | 
						|
		if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star):
 | 
						|
			text += "*"
 | 
						|
		text += " ret_ = "
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += self.wtype.name + "::get_py_obj("
 | 
						|
			if self.wtype.attr_type != attr_types.star:
 | 
						|
				text += "&"
 | 
						|
		text += self.namespace + "::" + self.name
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += ")"
 | 
						|
		text += ";"
 | 
						|
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += "\n\t\treturn *ret_;"
 | 
						|
		elif self.wtype.name in known_containers:
 | 
						|
			text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star)
 | 
						|
			text += "\n\t\treturn ret____tmp;"
 | 
						|
		else:
 | 
						|
			text += "\n\t\treturn ret_;"
 | 
						|
		text += "\n\t}\n"
 | 
						|
 | 
						|
		if self.is_const:
 | 
						|
			return text
 | 
						|
 | 
						|
		ret = Attribute(self.wtype, "rhs");
 | 
						|
 | 
						|
		if self.wtype.name in classnames:
 | 
						|
			text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)"
 | 
						|
		else:
 | 
						|
			text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)"
 | 
						|
		text += "\n\t{"
 | 
						|
		text += ret.gen_translation()
 | 
						|
		text += "\n\t\t" + self.namespace + "::" + self.name + " = " + ret.gen_call() + ";"
 | 
						|
		text += "\n\t}\n"
 | 
						|
 | 
						|
		return text;
 | 
						|
 | 
						|
	def gen_boost_py(self):
 | 
						|
		text = "\n\t\t\t.add_static_property(\"" + self.name + "\", &" + "YOSYS_PYTHON::get_var_py_" + self.name
 | 
						|
		if not self.is_const:
 | 
						|
			text += ", &YOSYS_PYTHON::set_var_py_" + self.name
 | 
						|
		text += ")"
 | 
						|
		return text
 | 
						|
 | 
						|
def concat_namespace(tuple_list):
 | 
						|
	if len(tuple_list) == 0:
 | 
						|
		return ""
 | 
						|
	ret = ""
 | 
						|
	for namespace in tuple_list:
 | 
						|
		ret += "::" + namespace[0]
 | 
						|
	return ret[2:]
 | 
						|
 | 
						|
def calc_ident(text):
 | 
						|
	if len(text) == 0 or text[0] != ' ':
 | 
						|
		return 0
 | 
						|
	return calc_ident(text[1:]) + 1
 | 
						|
 | 
						|
def assure_length(text, length, left = False):
 | 
						|
	if len(text) > length:
 | 
						|
		return text[:length]
 | 
						|
	if left:
 | 
						|
		return text + " "*(length - len(text))
 | 
						|
	return " "*(length - len(text)) + text
 | 
						|
 | 
						|
def nesting_delta(s):
 | 
						|
	return s.count("{") - s.count("}")
 | 
						|
 | 
						|
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 = []
 | 
						|
	classes = []
 | 
						|
	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)
 | 
						|
		debug(f"READ:>> {line}", 2)
 | 
						|
 | 
						|
		# for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line
 | 
						|
		if 'union {' in line:
 | 
						|
			j = i+1
 | 
						|
			while j < len(source_text):
 | 
						|
				union_line = source_text[j]
 | 
						|
				if '};' in union_line:
 | 
						|
					source_text[j] = '\n'
 | 
						|
					break
 | 
						|
				j += 1
 | 
						|
			if j != len(source_text):
 | 
						|
				i += 1
 | 
						|
				continue
 | 
						|
 | 
						|
		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] + nesting_delta(ugly_line))
 | 
						|
			if namespaces[-1][1] == 0:
 | 
						|
				debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
 | 
						|
				namespaces.pop()
 | 
						|
				i += 1
 | 
						|
				continue
 | 
						|
 | 
						|
		if (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0:
 | 
						|
			# Opening a record declaration which isn't a forward declaration
 | 
						|
			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)
 | 
						|
 | 
						|
			base_class_name = None
 | 
						|
			if len(ugly_line.split(" : ")) > 1: # class is derived
 | 
						|
				deriv_str = ugly_line.split(" : ")[1]
 | 
						|
				if len(deriv_str.split("::")) > 1: # namespace of base class is given
 | 
						|
					base_class_name = deriv_str.split("::", 1)[1]
 | 
						|
				else:
 | 
						|
					base_class_name = deriv_str.split(" ")[0]
 | 
						|
				debug("\t  " + struct_name + " is derived from " + base_class_name,2)
 | 
						|
			base_class = class_by_name(base_class_name)
 | 
						|
 | 
						|
			c = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line))
 | 
						|
			debug(f"switch to {struct_name} in namespace {namespaces}", 2)
 | 
						|
			if struct_name in classnames:
 | 
						|
				c[0].namespace = complete_namespace
 | 
						|
				c[0].base_class = base_class
 | 
						|
			classes.append(c)
 | 
						|
			i += 1
 | 
						|
			continue
 | 
						|
 | 
						|
		if len(classes):
 | 
						|
			c = (classes[-1][0], classes[-1][1] + nesting_delta(ugly_line))
 | 
						|
			classes[-1] = c
 | 
						|
			if c[1] == 0:
 | 
						|
				if c[0] == None:
 | 
						|
					debug("\tExiting unknown class", 3)
 | 
						|
				else:
 | 
						|
					debug("\tExiting class " + c[0].name, 3)
 | 
						|
				classes.pop()
 | 
						|
				private_segment = False
 | 
						|
				i += 1
 | 
						|
				continue
 | 
						|
 | 
						|
		class_ = classes[-1] if classes else None
 | 
						|
 | 
						|
		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)
 | 
						|
 | 
						|
					# generate log aliases
 | 
						|
					if candidate.name.startswith("log_formatted"):
 | 
						|
						alias = candidate.name.replace("log_formatted", "log")
 | 
						|
						if alias == "log_string":
 | 
						|
							alias = "log"
 | 
						|
						copied_candidate = copy.copy(candidate)
 | 
						|
						copied_candidate.alias = alias
 | 
						|
						unowned_functions.append(copied_candidate)
 | 
						|
 | 
						|
				else:
 | 
						|
					debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
					class_[0].found_funs.append(candidate)
 | 
						|
			else:
 | 
						|
				candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i)
 | 
						|
				if candidate != None:
 | 
						|
					enums.append(candidate)
 | 
						|
					debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
				elif class_ != None and class_[1] == 1:
 | 
						|
					candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i)
 | 
						|
					if candidate != None:
 | 
						|
						debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
						class_[0].found_constrs.append(candidate)
 | 
						|
					else:
 | 
						|
						candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
 | 
						|
						if candidate != None:
 | 
						|
							if type(candidate) == list:
 | 
						|
								for c in candidate:
 | 
						|
									debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2)
 | 
						|
								class_[0].found_vars.extend(candidate)
 | 
						|
							else:
 | 
						|
								debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2)
 | 
						|
								class_[0].found_vars.append(candidate)
 | 
						|
				if candidate == None and class_ == None:
 | 
						|
					candidate = WGlobal.from_string(ugly_line, source.name, i, concat_namespace(namespaces))
 | 
						|
					if candidate != None:
 | 
						|
						if type(candidate) == list:
 | 
						|
							for c in candidate:
 | 
						|
								glbls.append(c)
 | 
						|
								debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2)
 | 
						|
						else:
 | 
						|
							glbls.append(candidate)
 | 
						|
							debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2)
 | 
						|
 | 
						|
			j = i
 | 
						|
			line = unpretty_string(line)
 | 
						|
			while candidate == None and j+1 < len(source_text) and  line.count(';') <= 1 and line.count("(") >= line.count(")"):
 | 
						|
				j += 1
 | 
						|
				line = line + "\n" + unpretty_string(source_text[j])
 | 
						|
				if class_ != None:
 | 
						|
					candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
 | 
						|
				else:
 | 
						|
					candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
 | 
						|
				if candidate != None and candidate.name.find("::") == -1:
 | 
						|
					if class_ == None:
 | 
						|
						debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
						unowned_functions.append(candidate)
 | 
						|
					else:
 | 
						|
						debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
						class_[0].found_funs.append(candidate)
 | 
						|
					continue
 | 
						|
				candidate = WEnum.from_string(line, concat_namespace(namespaces), i)
 | 
						|
				if candidate != None:
 | 
						|
					enums.append(candidate)
 | 
						|
					debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
					continue
 | 
						|
				if class_ != None:
 | 
						|
					candidate = WConstructor.from_string(line, source.name, class_[0], i)
 | 
						|
					if candidate != None:
 | 
						|
						debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
 | 
						|
						class_[0].found_constrs.append(candidate)
 | 
						|
						continue
 | 
						|
				if class_ == None:
 | 
						|
					candidate = WGlobal.from_string(line, source.name, i, concat_namespace(namespaces))
 | 
						|
					if candidate != None:
 | 
						|
						if type(candidate) == list:
 | 
						|
							for c in candidate:
 | 
						|
								glbls.append(c)
 | 
						|
								debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2)
 | 
						|
						else:
 | 
						|
							glbls.append(candidate)
 | 
						|
							debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2)
 | 
						|
						continue
 | 
						|
		if candidate != None:
 | 
						|
			while i < j:
 | 
						|
				i += 1
 | 
						|
				line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", "                    namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END","                    }")
 | 
						|
				ugly_line = unpretty_string(line)
 | 
						|
				if len(namespaces) != 0:
 | 
						|
					namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + nesting_delta(ugly_line))
 | 
						|
					if namespaces[-1][1] == 0:
 | 
						|
						debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
 | 
						|
						namespaces.pop()
 | 
						|
				if len(classes):
 | 
						|
					c = (classes[-1][0] , classes[-1][1] + nesting_delta(ugly_line))
 | 
						|
					classes[-1] = c
 | 
						|
					if c[1] == 0:
 | 
						|
						if c[0] == None:
 | 
						|
							debug("\tExiting unknown class", 3)
 | 
						|
						else:
 | 
						|
							debug("\tExiting class " + c[0].name, 3)
 | 
						|
						classes.pop()
 | 
						|
						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 inherit_members():
 | 
						|
	for source in sources:
 | 
						|
		for class_ in source.classes:
 | 
						|
			if class_.base_class:
 | 
						|
				base_funs = copy.deepcopy(class_.base_class.found_funs)
 | 
						|
				for fun in base_funs:
 | 
						|
					fun.member_of = class_
 | 
						|
					fun.namespace = class_.namespace
 | 
						|
				base_vars = copy.deepcopy(class_.base_class.found_vars)
 | 
						|
				for var in base_vars:
 | 
						|
					var.member_of = class_
 | 
						|
					var.namespace = class_.namespace
 | 
						|
				class_.found_funs.extend(base_funs)
 | 
						|
				class_.found_vars.extend(base_vars)
 | 
						|
 | 
						|
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()]
 | 
						|
					if fun.mangled_name == other.mangled_name:
 | 
						|
						fun.duplicate = True
 | 
						|
						debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3)
 | 
						|
						continue
 | 
						|
 | 
						|
					other.gen_alias()
 | 
						|
					fun.gen_alias()
 | 
						|
				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()
 | 
						|
	inherit_members()
 | 
						|
	clean_duplicates()
 | 
						|
 | 
						|
	import shutil
 | 
						|
	import math
 | 
						|
	col = shutil.get_terminal_size((80,20)).columns
 | 
						|
	debug("-"*col, 1)
 | 
						|
	debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1)
 | 
						|
	debug("-"*col, 1)
 | 
						|
	for source in sources:
 | 
						|
		for class_ in source.classes:
 | 
						|
			debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1)
 | 
						|
			if len(class_.found_constrs) == 0:
 | 
						|
				class_.found_constrs.append(WConstructor(source.name, class_))
 | 
						|
	debug(str(len(unowned_functions)) + " functions are unowned", 1)
 | 
						|
	debug(str(len(unowned_functions)) + " global variables", 1)
 | 
						|
	for enum in enums:
 | 
						|
		debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1)
 | 
						|
	debug("-"*col, 1)
 | 
						|
	wrapper_file = open(filename, "w+")
 | 
						|
	wrapper_file.write(
 | 
						|
"""/*
 | 
						|
 *  yosys -- Yosys Open SYnthesis Suite
 | 
						|
 *
 | 
						|
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 | 
						|
 *
 | 
						|
 *  Permission to use, copy, modify, and/or distribute this software for any
 | 
						|
 *  purpose with or without fee is hereby granted, provided that the above
 | 
						|
 *  copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
						|
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
						|
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 *
 | 
						|
 *  This is a generated file and can be overwritten by make
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef WITH_PYTHON
 | 
						|
""")
 | 
						|
	for source in sources:
 | 
						|
		wrapper_file.write("#include \""+source.name+".h\"\n")
 | 
						|
	wrapper_file.write("""
 | 
						|
#include <boost/python/module.hpp>
 | 
						|
#include <boost/python/class.hpp>
 | 
						|
#include <boost/python/wrapper.hpp>
 | 
						|
#include <boost/python/call.hpp>
 | 
						|
#include <boost/python.hpp>
 | 
						|
#include <iosfwd> // std::streamsize
 | 
						|
#include <iostream>
 | 
						|
#include <boost/iostreams/concepts.hpp>	// boost::iostreams::sink
 | 
						|
#include <boost/iostreams/stream.hpp>
 | 
						|
USING_YOSYS_NAMESPACE
 | 
						|
 | 
						|
using std::string_view;
 | 
						|
 | 
						|
namespace YOSYS_PYTHON {
 | 
						|
 | 
						|
	[[noreturn]] static void log_python_exception_as_error() {
 | 
						|
		PyErr_Print();
 | 
						|
		log_error("Python interpreter encountered an exception.\\n");
 | 
						|
	}
 | 
						|
 | 
						|
	struct YosysStatics{};
 | 
						|
""")
 | 
						|
 | 
						|
	for source in sources:
 | 
						|
		for wclass in source.classes:
 | 
						|
			wrapper_file.write("\n\tstruct " + wclass.name + ";")
 | 
						|
 | 
						|
	wrapper_file.write("\n")
 | 
						|
 | 
						|
	for source in sources:
 | 
						|
		for wclass in source.classes:
 | 
						|
			wrapper_file.write(wclass.gen_decl(source.name))
 | 
						|
 | 
						|
	wrapper_file.write("\n")
 | 
						|
 | 
						|
	for source in sources:
 | 
						|
		for wclass in source.classes:
 | 
						|
			wrapper_file.write(wclass.gen_funs(source.name))
 | 
						|
 | 
						|
	for fun in unowned_functions:
 | 
						|
		wrapper_file.write(fun.gen_def())
 | 
						|
 | 
						|
	for glbl in glbls:
 | 
						|
		wrapper_file.write(glbl.gen_def())
 | 
						|
 | 
						|
	wrapper_file.write("""	struct Initializer
 | 
						|
	{
 | 
						|
		Initializer() {
 | 
						|
			if(!Yosys::yosys_already_setup())
 | 
						|
			{
 | 
						|
				Yosys::log_streams.push_back(&std::cout);
 | 
						|
				Yosys::log_error_stderr = true;
 | 
						|
				Yosys::yosys_setup();
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		Initializer(Initializer const &) {}
 | 
						|
 | 
						|
		~Initializer() {
 | 
						|
			Yosys::yosys_shutdown();
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
 | 
						|
	/// source: https://stackoverflow.com/questions/26033781/converting-python-io-object-to-stdostream-when-using-boostpython?noredirect=1&lq=1
 | 
						|
	/// @brief Type that implements the Boost.IOStream's Sink and Flushable
 | 
						|
	///        concept for writing data to Python object that support:
 | 
						|
	///          n = object.write(str) # n = None or bytes written
 | 
						|
	///          object.flush()        # if flush exists, then it is callable
 | 
						|
	class PythonOutputDevice
 | 
						|
	{
 | 
						|
	public:
 | 
						|
 | 
						|
		// This class models both the Sink and Flushable concepts.
 | 
						|
		struct category
 | 
						|
			: boost::iostreams::sink_tag,
 | 
						|
				boost::iostreams::flushable_tag
 | 
						|
		{};
 | 
						|
 | 
						|
		explicit
 | 
						|
		PythonOutputDevice(boost::python::object object)
 | 
						|
			: object_(object)
 | 
						|
		{}
 | 
						|
 | 
						|
	// Sink concept.
 | 
						|
	public:
 | 
						|
 | 
						|
		typedef char char_type;
 | 
						|
 | 
						|
		std::streamsize write(const char* buffer, std::streamsize buffer_size)
 | 
						|
		{
 | 
						|
			namespace python = boost::python;
 | 
						|
			// Copy the buffer to a python string.
 | 
						|
			python::str data(buffer, buffer_size);
 | 
						|
 | 
						|
			// Invoke write on the python object, passing in the data.	The following
 | 
						|
			// is equivalent to:
 | 
						|
			//	 n = object_.write(data)
 | 
						|
			python::extract<std::streamsize> bytes_written(
 | 
						|
				object_.attr("write")(data));
 | 
						|
 | 
						|
			// Per the Sink concept, return the number of bytes written.	If the
 | 
						|
			// Python return value provides a numeric result, then use it.	Otherwise,
 | 
						|
			// such as the case of a File object, use the buffer_size.
 | 
						|
			return bytes_written.check()
 | 
						|
				? bytes_written
 | 
						|
				: buffer_size;
 | 
						|
		}
 | 
						|
 | 
						|
	// Flushable concept.
 | 
						|
	public:
 | 
						|
 | 
						|
		bool flush()
 | 
						|
		{
 | 
						|
			// If flush exists, then call it.
 | 
						|
			boost::python::object flush = object_.attr("flush");
 | 
						|
			if (!flush.is_none())
 | 
						|
			{
 | 
						|
				flush();
 | 
						|
			}
 | 
						|
 | 
						|
			// Always return true.	If an error occurs, an exception should be thrown.
 | 
						|
				return true;
 | 
						|
		}
 | 
						|
 | 
						|
	private:
 | 
						|
		boost::python::object object_;
 | 
						|
	};
 | 
						|
 | 
						|
	/// @brief Use an auxiliary function to adapt the legacy function.
 | 
						|
	void log_to_stream(boost::python::object object)
 | 
						|
	{
 | 
						|
		// Create an ostream that delegates to the python object.
 | 
						|
		boost::iostreams::stream<PythonOutputDevice>* output = new boost::iostreams::stream<PythonOutputDevice>(object);
 | 
						|
		Yosys::log_streams.insert(Yosys::log_streams.begin(), output);
 | 
						|
	};
 | 
						|
 | 
						|
 | 
						|
	BOOST_PYTHON_MODULE(libyosys)
 | 
						|
	{
 | 
						|
		using namespace boost::python;
 | 
						|
 | 
						|
		class_<Initializer>("Initializer");
 | 
						|
		scope().attr("_hidden") = new Initializer();
 | 
						|
 | 
						|
		def("log_to_stream", &log_to_stream);
 | 
						|
""")
 | 
						|
 | 
						|
	for enum in enums:
 | 
						|
		wrapper_file.write(enum.gen_boost_py())
 | 
						|
 | 
						|
	for source in sources:
 | 
						|
		for wclass in source.classes:
 | 
						|
			wrapper_file.write(wclass.gen_boost_py())
 | 
						|
 | 
						|
	for fun in unowned_functions:
 | 
						|
		wrapper_file.write(fun.gen_boost_py())
 | 
						|
 | 
						|
	wrapper_file.write("\n\n\t\tclass_<YosysStatics>(\"Yosys\")\n")
 | 
						|
	for glbl in glbls:
 | 
						|
		wrapper_file.write(glbl.gen_boost_py())
 | 
						|
	wrapper_file.write("\t\t;\n")
 | 
						|
 | 
						|
	wrapper_file.write("\n\t}\n}\n#endif")
 | 
						|
 | 
						|
def print_includes():
 | 
						|
	for source in sources:
 | 
						|
		print(source.name + ".pyh")
 |