2 # yosys -- Yosys Open SYnthesis Suite
4 # Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 # Permission to use, copy, modify, and/or distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 # Author Benedikt Tutzer
23 #Map c++ operator Syntax to Python functions
24 wrappable_operators
= {
35 #Restrict certain strings from being function names in Python
46 "continue" : "continue_",
60 "nonlocal" : "nonlocal_",
72 #These can be used without any explicit conversion
73 primitive_types
= ["void", "bool", "int", "double", "size_t", "std::string",
74 "string", "State", "char_p"]
78 #Ways to link between Python- and C++ Objects
79 class link_types(Enum
):
80 global_list
= 1 #Manage a global list of objects in C++, the Python
81 #object contains a key to find the corresponding C++
82 #object and a Pointer to the object to verify it is
83 #still the same, making collisions unlikely to happen
84 ref_copy
= 2 #The Python object contains a copy of the C++ object.
85 #The C++ object is deleted when the Python object gets
87 pointer
= 3 #The Python Object contains a pointer to it's C++
89 derive
= 4 #The Python-Wrapper is derived from the C++ object.
91 class attr_types(Enum
):
102 def __init__(self
, name
, classes
):
104 self
.classes
= classes
106 #Splits a list by the given delimiter, without splitting strings inside
107 #pointy-brackets (< and >)
108 def split_list(str_def
, delim
):
109 str_def
= str_def
.strip()
110 if len(str_def
) == 0:
112 if str_def
.count(delim
) == 0:
114 if str_def
.count("<") == 0:
115 return str_def
.split(delim
)
116 if str_def
.find("<") < str_def
.find(" "):
117 closing
= find_closing(str_def
[str_def
.find("<")+1:], "<", ">") + str_def
.find("<")
118 comma
= str_def
[closing
:].find(delim
)
121 comma
= closing
+ comma
123 comma
= str_def
.find(delim
)
124 rest
= split_list(str_def
[comma
+1:], delim
)
125 ret
= [str_def
[:comma
]]
126 if rest
!= None and len(rest
) != 0:
134 attr_type
= attr_types
.default
136 def __init__(self
, name
= "", cont
= None, attr_type
= attr_types
.default
):
139 self
.attr_type
= attr_type
144 if self
.name
in enum_names
:
145 text
= enum_by_name(self
.name
).namespace
+ "::" + self
.name
146 if self
.cont
!= None:
147 return known_containers
[self
.name
].typename
151 def gen_text_cpp(self
):
153 if self
.attr_type
== attr_types
.star
:
155 if self
.name
in primitive_types
:
156 return self
.name
+ postfix
157 if self
.name
in enum_names
:
158 return enum_by_name(self
.name
).namespace
+ "::" + self
.name
+ postfix
159 if self
.name
in classnames
:
160 return class_by_name(self
.name
).namespace
+ "::" + self
.name
+ postfix
162 if self
.cont
!= None:
164 for a
in self
.cont
.args
:
165 text
+= a
.gen_text_cpp() + ", "
171 def from_string(str_def
, containing_file
, line_number
):
172 str_def
= str_def
.strip()
173 if len(str_def
) == 0:
175 str_def
= str_def
.replace("RTLIL::SigSig", "std::pair<SigSpec, SigSpec>").replace("SigSig", "std::pair<SigSpec, SigSpec>")
179 t
.attr_type
= attr_types
.default
180 if str_def
.find("<") != -1:# and str_def.find("<") < str_def.find(" "):
181 candidate
= WContainer
.from_string(str_def
, containing_file
, line_number
)
182 if candidate
== None:
184 t
.name
= str_def
[:str_def
.find("<")]
186 if t
.name
.count("*") + t
.name
.count("&") > 1:
189 if t
.name
.count("*") == 1 or str_def
[0] == '*' or str_def
[-1] == '*':
190 t
.attr_type
= attr_types
.star
191 t
.name
= t
.name
.replace("*","")
192 elif t
.name
.count("&&") == 1:
193 t
.attr_type
= attr_types
.ampamp
194 t
.name
= t
.name
.replace("&&","")
195 elif t
.name
.count("&") == 1 or str_def
[0] == '&' or str_def
[-1] == '&':
196 t
.attr_type
= attr_types
.amp
197 t
.name
= t
.name
.replace("&","")
200 if(t
.name
not in known_containers
):
206 if str.startswith(str_def
, "unsigned "):
208 str_def
= str_def
[9:]
209 while str.startswith(str_def
, "long "):
210 prefix
= "long " + prefix
211 str_def
= str_def
[5:]
212 while str.startswith(str_def
, "short "):
213 prefix
= "short " + prefix
214 str_def
= str_def
[6:]
216 str_def
= str_def
.split("::")[-1]
218 if str_def
.count("*") + str_def
.count("&") >= 2:
221 if str_def
.count("*") == 1:
222 t
.attr_type
= attr_types
.star
223 str_def
= str_def
.replace("*","")
224 elif str_def
.count("&&") == 1:
225 t
.attr_type
= attr_types
.ampamp
226 str_def
= str_def
.replace("&&","")
227 elif str_def
.count("&") == 1:
228 t
.attr_type
= attr_types
.amp
229 str_def
= str_def
.replace("&","")
231 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
:
234 if str_def
.count(" ") == 0:
235 t
.name
= (prefix
+ str_def
).replace("char_p", "char *")
240 #Represents a container-type
245 def from_string(str_def
, containing_file
, line_number
):
246 if str_def
== None or len(str_def
) < 4:
249 cont
.name
= str_def
[:str_def
.find("<")]
250 str_def
= str_def
[str_def
.find("<")+1:find_closing(str_def
, "<", ">")]
252 for arg
in split_list(str_def
, ","):
253 candidate
= WType
.from_string(arg
.strip(), containing_file
, line_number
)
254 if candidate
== None:
256 if candidate
.name
== "void":
258 cont
.args
.append(candidate
)
261 #Translators between Python and C++ containers
265 typename
= "DefaultType"
266 orig_name
= "DefaultCpp"
269 def gen_type(c
, types
):
270 return "\nImplement a function that outputs the c++ type of this container here\n"
273 def translate(c
, varname
, types
, prefix
):
274 return "\nImplement a function translating a python container to a c++ container here\n"
277 def translate_cpp(c
, varname
, types
, prefix
, ref
):
278 return "\nImplement a function translating a c++ container to a python container here\n"
280 #Translates list-types (vector, pool, set), that only differ in their name and
281 #the name of the insertion function
282 class PythonListTranslator(Translator
):
283 typename
= "boost::python::list"
284 insert_name
= "Default"
286 #generate the c++ type string
288 def gen_type(c
, types
):
289 text
= c
.orig_name
+ "<"
290 if types
[0].name
in primitive_types
:
291 text
+= types
[0].name
292 elif types
[0].name
in known_containers
:
293 text
+= known_containers
[types
[0].name
].gen_type(types
[0].cont
.args
)
295 text
+= class_by_name(types
[0].name
).namespace
+ "::" + types
[0].name
296 if types
[0].attr_type
== attr_types
.star
:
301 #Generate C++ code to translate from a boost::python::list
303 def translate(c
, varname
, types
, prefix
):
304 text
= prefix
+ c
.gen_type(types
) + " " + varname
+ "___tmp;"
305 cntr_name
= "cntr_" + str(Translator
.tmp_cntr
)
306 Translator
.tmp_cntr
= Translator
.tmp_cntr
+ 1
307 text
+= prefix
+ "for(int " + cntr_name
+ " = 0; " + cntr_name
+ " < len(" + varname
+ "); " + cntr_name
+ "++)"
309 tmp_name
= "tmp_" + str(Translator
.tmp_cntr
)
310 Translator
.tmp_cntr
= Translator
.tmp_cntr
+ 1
311 if types
[0].name
in known_containers
:
312 text
+= prefix
+ "\t" + known_containers
[types
[0].name
].typename
+ " " + tmp_name
+ " = boost::python::extract<" + known_containers
[types
[0].name
].typename
+ ">(" + varname
+ "[" + cntr_name
+ "]);"
313 text
+= known_containers
[types
[0].name
].translate(tmp_name
, types
[0].cont
.args
, prefix
+"\t")
314 tmp_name
= tmp_name
+ "___tmp"
315 text
+= prefix
+ "\t" + varname
+ "___tmp" + c
.insert_name
+ "(" + tmp_name
+ ");"
316 elif types
[0].name
in classnames
:
317 text
+= prefix
+ "\t" + types
[0].name
+ "* " + tmp_name
+ " = boost::python::extract<" + types
[0].name
+ "*>(" + varname
+ "[" + cntr_name
+ "]);"
318 if types
[0].attr_type
== attr_types
.star
:
319 text
+= prefix
+ "\t" + varname
+ "___tmp" + c
.insert_name
+ "(" + tmp_name
+ "->get_cpp_obj());"
321 text
+= prefix
+ "\t" + varname
+ "___tmp" + c
.insert_name
+ "(*" + tmp_name
+ "->get_cpp_obj());"
323 text
+= prefix
+ "\t" + types
[0].name
+ " " + tmp_name
+ " = boost::python::extract<" + types
[0].name
+ ">(" + varname
+ "[" + cntr_name
+ "]);"
324 text
+= prefix
+ "\t" + varname
+ "___tmp" + c
.insert_name
+ "(" + tmp_name
+ ");"
328 #Generate C++ code to translate to a boost::python::list
330 def translate_cpp(c
, varname
, types
, prefix
, ref
):
331 text
= prefix
+ c
.typename
+ " " + varname
+ "___tmp;"
332 tmp_name
= "tmp_" + str(Translator
.tmp_cntr
)
333 Translator
.tmp_cntr
= Translator
.tmp_cntr
+ 1
335 text
+= prefix
+ "for(auto " + tmp_name
+ " : *" + varname
+ ")"
337 text
+= prefix
+ "for(auto " + tmp_name
+ " : " + varname
+ ")"
339 if types
[0].name
in classnames
:
340 if types
[0].attr_type
== attr_types
.star
:
341 text
+= prefix
+ "\t" + varname
+ "___tmp.append(" + types
[0].name
+ "::get_py_obj(" + tmp_name
+ "));"
343 text
+= prefix
+ "\t" + varname
+ "___tmp.append(*" + types
[0].name
+ "::get_py_obj(&" + tmp_name
+ "));"
344 elif types
[0].name
in known_containers
:
345 text
+= known_containers
[types
[0].name
].translate_cpp(tmp_name
, types
[0].cont
.args
, prefix
+ "\t", types
[0].attr_type
== attr_types
.star
)
346 text
+= prefix
+ "\t" + varname
+ "___tmp.append(" + tmp_name
+ "___tmp);"
348 text
+= prefix
+ "\t" + varname
+ "___tmp.append(" + tmp_name
+ ");"
352 class IDictTranslator(PythonListTranslator
):
353 typename
= "boost::python::list"
357 #Sub-type for std::set
358 class SetTranslator(PythonListTranslator
):
359 insert_name
= ".insert"
360 orig_name
= "std::set"
362 #Sub-type for std::vector
363 class VectorTranslator(PythonListTranslator
):
364 insert_name
= ".push_back"
365 orig_name
= "std::vector"
368 class PoolTranslator(PythonListTranslator
):
369 insert_name
= ".insert"
372 #Translates dict-types (dict, std::map), that only differ in their name and
373 #the name of the insertion function
374 class PythonDictTranslator(Translator
):
375 typename
= "boost::python::dict"
376 insert_name
= "Default"
379 def gen_type(c
, types
):
380 text
= c
.orig_name
+ "<"
381 if types
[0].name
in primitive_types
:
382 text
+= types
[0].name
383 elif types
[0].name
in known_containers
:
384 text
+= known_containers
[types
[0].name
].gen_type(types
[0].cont
.args
)
386 text
+= class_by_name(types
[0].name
).namespace
+ "::" + types
[0].name
387 if types
[0].attr_type
== attr_types
.star
:
390 if types
[1].name
in primitive_types
:
391 text
+= types
[1].name
392 elif types
[1].name
in known_containers
:
393 text
+= known_containers
[types
[1].name
].gen_type(types
[1].cont
.args
)
395 text
+= class_by_name(types
[1].name
).namespace
+ "::" + types
[1].name
396 if types
[1].attr_type
== attr_types
.star
:
401 #Generate c++ code to translate from a boost::python::dict
403 def translate(c
, varname
, types
, prefix
):
404 text
= prefix
+ c
.gen_type(types
) + " " + varname
+ "___tmp;"
405 text
+= prefix
+ "boost::python::list " + varname
+ "_keylist = " + varname
+ ".keys();"
406 cntr_name
= "cntr_" + str(Translator
.tmp_cntr
)
407 Translator
.tmp_cntr
= Translator
.tmp_cntr
+ 1
408 text
+= prefix
+ "for(int " + cntr_name
+ " = 0; " + cntr_name
+ " < len(" + varname
+ "_keylist); " + cntr_name
+ "++)"
410 key_tmp_name
= "key_tmp_" + str(Translator
.tmp_cntr
)
411 val_tmp_name
= "val_tmp_" + str(Translator
.tmp_cntr
)
412 Translator
.tmp_cntr
= Translator
.tmp_cntr
+ 1
414 if types
[0].name
in known_containers
:
415 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
+ " ]);"
416 text
+= known_containers
[types
[0].name
].translate(key_tmp_name
, types
[0].cont
.args
, prefix
+"\t")
417 key_tmp_name
= key_tmp_name
+ "___tmp"
418 elif types
[0].name
in classnames
:
419 text
+= prefix
+ "\t" + types
[0].name
+ "* " + key_tmp_name
+ " = boost::python::extract<" + types
[0].name
+ "*>(" + varname
+ "_keylist[ " + cntr_name
+ " ]);"
421 text
+= prefix
+ "\t" + types
[0].name
+ " " + key_tmp_name
+ " = boost::python::extract<" + types
[0].name
+ ">(" + varname
+ "_keylist[ " + cntr_name
+ " ]);"
423 if types
[1].name
in known_containers
:
424 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
+ " ]]);"
425 text
+= known_containers
[types
[1].name
].translate(val_tmp_name
, types
[1].cont
.args
, prefix
+"\t")
426 val_tmp_name
= val_tmp_name
+ "___tmp"
427 elif types
[1].name
in classnames
:
428 text
+= prefix
+ "\t" + types
[1].name
+ "* " + val_tmp_name
+ " = boost::python::extract<" + types
[1].name
+ "*>(" + varname
+ "[" + varname
+ "_keylist[ " + cntr_name
+ " ]]);"
430 text
+= prefix
+ "\t" + types
[1].name
+ " " + val_tmp_name
+ " = boost::python::extract<" + types
[1].name
+ ">(" + varname
+ "[" + varname
+ "_keylist[ " + cntr_name
+ " ]]);"
432 text
+= prefix
+ "\t" + varname
+ "___tmp." + c
.insert_name
+ "(std::pair<" + types
[0].gen_text_cpp() + ", " + types
[1].gen_text_cpp() + ">("
434 if types
[0].name
not in classnames
:
437 if types
[0].attr_type
!= attr_types
.star
:
439 text
+= key_tmp_name
+ "->get_cpp_obj()"
442 if types
[1].name
not in classnames
:
445 if types
[1].attr_type
!= attr_types
.star
:
447 text
+= val_tmp_name
+ "->get_cpp_obj()"
448 text
+= "));\n" + prefix
+ "}"
451 #Generate c++ code to translate to a boost::python::dict
453 def translate_cpp(c
, varname
, types
, prefix
, ref
):
454 text
= prefix
+ c
.typename
+ " " + varname
+ "___tmp;"
455 tmp_name
= "tmp_" + str(Translator
.tmp_cntr
)
456 Translator
.tmp_cntr
= Translator
.tmp_cntr
+ 1
458 text
+= prefix
+ "for(auto " + tmp_name
+ " : *" + varname
+ ")"
460 text
+= prefix
+ "for(auto " + tmp_name
+ " : " + varname
+ ")"
462 if types
[1].name
in known_containers
:
463 text
+= prefix
+ "\tauto " + tmp_name
+ "_second = " + tmp_name
+ ".second;"
464 text
+= known_containers
[types
[1].name
].translate_cpp(tmp_name
+ "_second", types
[1].cont
.args
, prefix
+ "\t", types
[1].attr_type
== attr_types
.star
)
466 if types
[0].name
in classnames
:
467 text
+= prefix
+ "\t" + varname
+ "___tmp[" + types
[0].name
+ "::get_py_obj(" + tmp_name
+ ".first)] = "
468 elif types
[0].name
not in known_containers
:
469 text
+= prefix
+ "\t" + varname
+ "___tmp[" + tmp_name
+ ".first] = "
471 if types
[1].name
in classnames
:
472 if types
[1].attr_type
== attr_types
.star
:
473 text
+= types
[1].name
+ "::get_py_obj(" + tmp_name
+ ".second);"
475 text
+= "*" + types
[1].name
+ "::get_py_obj(&" + tmp_name
+ ".second);"
476 elif types
[1].name
in known_containers
:
477 text
+= tmp_name
+ "_second___tmp;"
479 text
+= tmp_name
+ ".second;"
484 class DictTranslator(PythonDictTranslator
):
485 insert_name
= "insert"
488 #Sub_type for std::map
489 class MapTranslator(PythonDictTranslator
):
490 insert_name
= "insert"
491 orig_name
= "std::map"
493 #Translator for std::pair. Derived from PythonDictTranslator because the
494 #gen_type function is the same (because both have two template parameters)
495 class TupleTranslator(PythonDictTranslator
):
496 typename
= "boost::python::tuple"
497 orig_name
= "std::pair"
499 #Generate c++ code to translate from a boost::python::tuple
501 def translate(c
, varname
, types
, prefix
):
502 text
= prefix
+ types
[0].name
+ " " + varname
+ "___tmp_0 = boost::python::extract<" + types
[0].name
+ ">(" + varname
+ "[0]);"
503 text
+= prefix
+ types
[1].name
+ " " + varname
+ "___tmp_1 = boost::python::extract<" + types
[1].name
+ ">(" + varname
+ "[1]);"
504 text
+= prefix
+ TupleTranslator
.gen_type(types
) + " " + varname
+ "___tmp("
505 if types
[0].name
.split(" ")[-1] in primitive_types
:
506 text
+= varname
+ "___tmp_0, "
508 text
+= varname
+ "___tmp_0.get_cpp_obj(), "
509 if types
[1].name
.split(" ")[-1] in primitive_types
:
510 text
+= varname
+ "___tmp_1);"
512 text
+= varname
+ "___tmp_1.get_cpp_obj());"
515 #Generate c++ code to translate to a boost::python::tuple
517 def translate_cpp(c
, varname
, types
, prefix
, ref
):
518 # if the tuple is a pair of SigSpecs (aka SigSig), then we need
519 # to call get_py_obj() on each item in the tuple
520 if types
[0].name
in classnames
:
521 first_var
= types
[0].name
+ "::get_py_obj(" + varname
+ ".first)"
523 first_var
= varname
+ ".first"
524 if types
[1].name
in classnames
:
525 second_var
= types
[1].name
+ "::get_py_obj(" + varname
+ ".second)"
527 second_var
= varname
+ ".second"
528 text
= prefix
+ TupleTranslator
.typename
+ " " + varname
+ "___tmp = boost::python::make_tuple(" + first_var
+ ", " + second_var
+ ");"
531 #Associate the Translators with their c++ type
533 "std::set" : SetTranslator
,
534 "std::vector" : VectorTranslator
,
535 "pool" : PoolTranslator
,
536 "idict" : IDictTranslator
,
537 "dict" : DictTranslator
,
538 "std::pair" : TupleTranslator
,
539 "std::map" : MapTranslator
550 def __init__(self
, wtype
, varname
, is_const
= False, default_value
= None):
552 self
.varname
= varname
553 self
.is_const
= is_const
554 self
.default_value
= None
555 self
.container
= None
558 def from_string(str_def
, containing_file
, line_number
):
562 arg
= Attribute(None, None)
567 arg
.default_value
= None
569 if str.startswith(str_def
, "const "):
571 str_def
= str_def
[6:]
572 if str.startswith(str_def
, "unsigned "):
574 str_def
= str_def
[9:]
575 while str.startswith(str_def
, "long "):
576 prefix
= "long " + prefix
577 str_def
= str_def
[5:]
578 while str.startswith(str_def
, "short "):
579 prefix
= "short " + prefix
580 str_def
= str_def
[6:]
582 if str_def
.find("<") != -1 and str_def
.find("<") < str_def
.find(" "):
583 closing
= find_closing(str_def
[str_def
.find("<"):], "<", ">") + str_def
.find("<") + 1
584 arg
.wtype
= WType
.from_string(str_def
[:closing
].strip(), containing_file
, line_number
)
585 str_def
= str_def
[closing
+1:]
587 if str_def
.count(" ") > 0:
588 arg
.wtype
= WType
.from_string(prefix
+ str_def
[:str_def
.find(" ")].strip(), containing_file
, line_number
)
589 str_def
= str_def
[str_def
.find(" ")+1:]
591 arg
.wtype
= WType
.from_string(prefix
+ str_def
.strip(), containing_file
, line_number
)
595 if arg
.wtype
== None:
597 if str_def
.count("=") == 0:
598 arg
.varname
= str_def
.strip()
599 if arg
.varname
.find(" ") > 0:
602 arg
.varname
= str_def
[:str_def
.find("=")].strip()
603 if arg
.varname
.find(" ") > 0:
605 str_def
= str_def
[str_def
.find("=")+1:].strip()
606 arg
.default_value
= str_def
[arg
.varname
.find("=")+1:].strip()
607 if len(arg
.varname
) == 0:
610 if arg
.varname
[0] == '*':
611 arg
.wtype
.attr_type
= attr_types
.star
612 arg
.varname
= arg
.varname
[1:]
613 elif arg
.varname
[0] == '&':
614 if arg
.wtype
.attr_type
!= attr_types
.default
:
616 if arg
.varname
[1] == '&':
617 arg
.wtype
.attr_type
= attr_types
.ampamp
618 arg
.varname
= arg
.varname
[2:]
620 arg
.wtype
.attr_type
= attr_types
.amp
621 arg
.varname
= arg
.varname
[1:]
624 #Generates the varname. If the attribute has no name in the header file,
626 def gen_varname(self
):
627 if self
.varname
!= None:
629 if self
.wtype
.name
== "void":
632 self
.pos
= Attribute
.pos_counter
633 Attribute
.pos_counter
= Attribute
.pos_counter
+ 1
634 return "gen_varname_" + str(self
.pos
)
636 #Generates the text for the function headers with wrapper types
637 def gen_listitem(self
):
641 if self
.wtype
.name
in classnames
:
642 return prefix
+ self
.wtype
.name
+ "* " + self
.gen_varname()
643 if self
.wtype
.name
in known_containers
:
644 return prefix
+ known_containers
[self
.wtype
.name
].typename
+ " " + self
.gen_varname()
645 return prefix
+ self
.wtype
.name
+ " " + self
.gen_varname()
647 #Generates the test for the function headers with c++ types
648 def gen_listitem_cpp(self
):
653 if self
.wtype
.attr_type
== attr_types
.star
:
655 elif self
.wtype
.attr_type
== attr_types
.amp
:
657 elif self
.wtype
.attr_type
== attr_types
.ampamp
:
659 if self
.wtype
.name
in known_containers
:
660 return prefix
+ known_containers
[self
.wtype
.name
].gen_type(self
.wtype
.cont
.args
) + " " + infix
+ self
.gen_varname()
661 if self
.wtype
.name
in classnames
:
662 return prefix
+ class_by_name(self
.wtype
.name
).namespace
+ "::" + self
.wtype
.name
+ " " + infix
+ self
.gen_varname()
663 return prefix
+ self
.wtype
.name
+ " " + infix
+ self
.gen_varname()
665 #Generates the listitem withtout the varname, so the signature can be
667 def gen_listitem_hash(self
):
671 if self
.wtype
.name
in classnames
:
672 return prefix
+ self
.wtype
.name
+ "* "
673 if self
.wtype
.name
in known_containers
:
674 return known_containers
[self
.wtype
.name
].typename
675 return prefix
+ self
.wtype
.name
677 #Generate Translation code for the attribute
678 def gen_translation(self
):
679 if self
.wtype
.name
in known_containers
:
680 return known_containers
[self
.wtype
.name
].translate(self
.gen_varname(), self
.wtype
.cont
.args
, "\n\t\t")
683 #Generate Translation code from c++ for the attribute
684 def gen_translation_cpp(self
):
685 if self
.wtype
.name
in known_containers
:
686 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
)
689 #Generate Text for the call
691 ret
= self
.gen_varname()
692 if self
.wtype
.name
in known_containers
:
693 if self
.wtype
.attr_type
== attr_types
.star
:
694 return "&" + ret
+ "___tmp"
695 return ret
+ "___tmp"
696 if self
.wtype
.name
in classnames
:
697 if self
.wtype
.attr_type
!= attr_types
.star
:
699 return ret
+ "->get_cpp_obj()"
700 if self
.wtype
.name
== "char *" and self
.gen_varname() in ["format", "fmt"]:
701 return "\"%s\", " + self
.gen_varname()
702 if self
.wtype
.attr_type
== attr_types
.star
:
706 def gen_call_cpp(self
):
707 ret
= self
.gen_varname()
708 if self
.wtype
.name
.split(" ")[-1] in primitive_types
or self
.wtype
.name
in enum_names
:
709 if self
.wtype
.attr_type
== attr_types
.star
:
712 if self
.wtype
.name
not in classnames
:
713 if self
.wtype
.attr_type
== attr_types
.star
:
714 return "&" + ret
+ "___tmp"
715 return ret
+ "___tmp"
716 if self
.wtype
.attr_type
!= attr_types
.star
:
718 return self
.wtype
.name
+ "::get_py_obj(" + self
.gen_varname() + ")"
720 #Generate cleanup code
721 def gen_cleanup(self
):
722 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
):
724 return "\n\t\tdelete " + self
.gen_varname() + "___tmp;"
739 def __init__(self
, name
, link_type
, id_
, string_id
= None, hash_id
= None, needs_clone
= False):
741 self
.namespace
= None
742 self
.base_class
= None
743 self
.link_type
= link_type
745 self
.string_id
= string_id
746 self
.hash_id
= hash_id
747 self
.needs_clone
= needs_clone
750 self
.found_constrs
= []
752 def printable_constrs(self
):
754 for con
in self
.found_constrs
:
755 if not con
.protected
:
759 def gen_decl(self
, filename
):
760 long_name
= self
.namespace
+ "::" + self
.name
762 text
= "\n\t// WRAPPED from " + filename
763 text
+= "\n\tstruct " + self
.name
764 if self
.link_type
== link_types
.derive
:
765 text
+= " : public " + self
.namespace
+ "::" + self
.name
768 if self
.link_type
!= link_types
.derive
:
770 text
+= "\t\t" + long_name
+ "* ref_obj;\n"
772 if self
.link_type
== link_types
.ref_copy
or self
.link_type
== link_types
.pointer
:
773 text
+= "\n\t\t" + long_name
+ "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n"
774 elif self
.link_type
== link_types
.global_list
:
775 text
+= "\t\t" + self
.id_
.wtype
.name
+ " " + self
.id_
.varname
+ ";\n"
776 text
+= "\n\t\t" + long_name
+ "* get_cpp_obj() const\n\t\t{"
777 text
+= "\n\t\t\t" + long_name
+ "* ret = " + long_name
+ "::get_all_" + self
.name
.lower() + "s()->at(this->" + self
.id_
.varname
+ ");"
778 text
+= "\n\t\t\tif(ret != NULL && ret == this->ref_obj)"
779 text
+= "\n\t\t\t\treturn ret;"
780 text
+= "\n\t\t\tthrow std::runtime_error(\"" + self
.name
+ "'s c++ object does not exist anymore.\");"
781 text
+= "\n\t\t\treturn NULL;"
784 #if self.link_type != link_types.pointer:
785 text
+= "\n\t\tstatic " + self
.name
+ "* get_py_obj(" + long_name
+ "* ref)\n\t\t{"
786 text
+= "\n\t\t\tif(ref == nullptr){"
787 text
+= "\n\t\t\t\tthrow std::runtime_error(\"" + self
.name
+ " does not exist.\");"
789 text
+= "\n\t\t\t" + self
.name
+ "* ret = (" + self
.name
+ "*)malloc(sizeof(" + self
.name
+ "));"
790 if self
.link_type
== link_types
.pointer
:
791 text
+= "\n\t\t\tret->ref_obj = ref;"
792 if self
.link_type
== link_types
.ref_copy
:
794 text
+= "\n\t\t\tret->ref_obj = ref->clone();"
796 text
+= "\n\t\t\tret->ref_obj = new "+long_name
+"(*ref);"
797 if self
.link_type
== link_types
.global_list
:
798 text
+= "\n\t\t\tret->ref_obj = ref;"
799 text
+= "\n\t\t\tret->" + self
.id_
.varname
+ " = ret->ref_obj->" + self
.id_
.varname
+ ";"
800 text
+= "\n\t\t\treturn ret;"
803 if self
.link_type
== link_types
.ref_copy
:
804 text
+= "\n\t\tstatic " + self
.name
+ "* get_py_obj(" + long_name
+ " ref)\n\t\t{"
805 text
+= "\n\t\t\t" + self
.name
+ "* ret = (" + self
.name
+ "*)malloc(sizeof(" + self
.name
+ "));"
807 text
+= "\n\t\t\tret->ref_obj = ref.clone();"
809 text
+= "\n\t\t\tret->ref_obj = new "+long_name
+"(ref);"
810 text
+= "\n\t\t\treturn ret;"
813 for con
in self
.found_constrs
:
814 text
+= con
.gen_decl()
815 if self
.base_class
is not None:
816 text
+= "\n\t\tvirtual ~" + self
.name
+ "() { };"
817 for var
in self
.found_vars
:
818 text
+= var
.gen_decl()
819 for fun
in self
.found_funs
:
820 text
+= fun
.gen_decl()
823 if self
.link_type
== link_types
.derive
:
825 for fun
in self
.found_funs
:
826 if fun
.name
in duplicates
:
828 duplicates
[fun
.name
].gen_alias()
830 duplicates
[fun
.name
] = fun
832 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"
833 text
+= "\n\t\tstatic " + self
.name
+ "* get_py_obj(" + long_name
+ "* ref)\n\t\t{"
834 text
+= "\n\t\t\treturn (" + self
.name
+ "*)ref;"
837 for con
in self
.found_constrs
:
838 text
+= con
.gen_decl_derive()
839 for var
in self
.found_vars
:
840 text
+= var
.gen_decl()
841 for fun
in self
.found_funs
:
842 text
+= fun
.gen_decl_virtual()
844 if self
.hash_id
!= None:
845 text
+= "\n\t\tunsigned int get_hash_py()"
847 text
+= "\n\t\t\treturn get_cpp_obj()->" + self
.hash_id
+ ";"
852 if self
.link_type
== link_types
.derive
:
853 text
+= "\n\tstruct " + self
.name
+ "Wrap : " + self
.name
+ ", boost::python::wrapper<" + self
.name
+ ">"
856 for con
in self
.found_constrs
:
857 text
+= con
.gen_decl_wrapperclass()
858 for fun
in self
.found_funs
:
859 text
+= fun
.gen_default_impl()
863 text
+= "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self
.name
+ " &ref)"
865 text
+= "\n\t\tostr << \"" + self
.name
866 if self
.string_id
!= None:
868 text
+= " << ref.get_cpp_obj()->" + self
.string_id
869 text
+= " << \"\\\"\""
871 text
+= " at \" << ref.get_cpp_obj()"
873 text
+= "\n\t\treturn ostr;"
879 def gen_funs(self
, filename
):
881 if self
.link_type
!= link_types
.derive
:
882 for con
in self
.found_constrs
:
883 text
+= con
.gen_def()
884 for var
in self
.found_vars
:
885 text
+= var
.gen_def()
886 for fun
in self
.found_funs
:
887 text
+= fun
.gen_def()
889 for var
in self
.found_vars
:
890 text
+= var
.gen_def()
891 for fun
in self
.found_funs
:
892 text
+= fun
.gen_def_virtual()
895 def gen_boost_py_body(self
):
897 if self
.printable_constrs() == 0 or not self
.contains_default_constr():
900 text
+= "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))"
901 text
+= "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))"
902 for con
in self
.found_constrs
:
903 text
+= con
.gen_boost_py()
904 for var
in self
.found_vars
:
905 text
+= var
.gen_boost_py()
907 for fun
in self
.found_funs
:
908 text
+= fun
.gen_boost_py()
909 if fun
.is_static
and fun
.alias
not in static_funs
:
910 static_funs
.append(fun
.alias
)
911 for fun
in static_funs
:
912 text
+= "\n\t\t\t.staticmethod(\"" + fun
+ "\")"
914 if self
.hash_id
!= None:
915 text
+= "\n\t\t\t.def(\"__hash__\", &" + self
.name
+ "::get_hash_py)"
916 text
+= "\n\t\t\t;\n"
919 def gen_boost_py(self
):
920 body
= self
.gen_boost_py_body()
922 if self
.base_class
is not None:
923 base_info
= ", bases<" + (self
.base_class
.name
) + ">"
925 if self
.link_type
== link_types
.derive
:
926 text
= "\n\t\tclass_<" + self
.name
+ base_info
+ ">(\"Cpp" + self
.name
+ "\""
928 text
+= "\n\t\tclass_<" + self
.name
929 text
+= "Wrap, boost::noncopyable"
930 text
+= ">(\"" + self
.name
+ "\""
933 text
= "\n\t\tclass_<" + self
.name
+ base_info
+ ">(\"" + self
.name
+ "\""
938 def contains_default_constr(self
):
939 for c
in self
.found_constrs
:
944 #CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE
947 Source("kernel/celltypes",[
948 WClass("CellType", link_types
.pointer
, None, None, "type.hash()", True),
949 WClass("CellTypes", link_types
.pointer
, None, None, None, True)
952 Source("kernel/consteval",[
953 WClass("ConstEval", link_types
.pointer
, None, None, None, True)
956 Source("kernel/log",[]),
957 Source("kernel/register",[
958 WClass("Pass", link_types
.derive
, None, None, None, True),
961 Source("kernel/rtlil",[
962 WClass("IdString", link_types
.ref_copy
, None, "str()", "hash()"),
963 WClass("Const", link_types
.ref_copy
, None, "as_string()", "hash()"),
964 WClass("AttrObject", link_types
.ref_copy
, None, None, None),
965 WClass("Selection", link_types
.ref_copy
, None, None, None),
966 WClass("Monitor", link_types
.derive
, None, None, None),
967 WClass("CaseRule",link_types
.ref_copy
, None, None, None, True),
968 WClass("SwitchRule",link_types
.ref_copy
, None, None, None, True),
969 WClass("SyncRule", link_types
.ref_copy
, None, None, None, True),
970 WClass("Process", link_types
.ref_copy
, None, "name.c_str()", "name.hash()"),
971 WClass("SigChunk", link_types
.ref_copy
, None, None, None),
972 WClass("SigBit", link_types
.ref_copy
, None, None, "hash()"),
973 WClass("SigSpec", link_types
.ref_copy
, None, None, "hash()"),
974 WClass("Cell", link_types
.global_list
, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
975 WClass("Wire", link_types
.global_list
, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
976 WClass("Memory", link_types
.global_list
, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
977 WClass("Module", link_types
.global_list
, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
978 WClass("Design", link_types
.global_list
, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()")
981 #Source("kernel/satgen",[
984 #Source("libs/ezsat/ezsat",[
987 #Source("libs/ezsat/ezminisat",[
990 Source("kernel/sigtools",[
991 WClass("SigMap", link_types
.pointer
, None, None, None, True)
994 Source("kernel/yosys",[
997 Source("kernel/cost",[])
1000 blacklist_methods
= ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow", "YOSYS_NAMESPACE::Module::Bu0", "YOSYS_NAMESPACE::CaseRule::optimize"]
1002 enum_names
= ["State","SyncType","ConstFlags"]
1004 enums
= [] #Do not edit
1007 unowned_functions
= []
1010 for source
in sources
:
1011 for wclass
in source
.classes
:
1012 classnames
.append(wclass
.name
)
1014 def class_by_name(name
):
1015 for source
in sources
:
1016 for wclass
in source
.classes
:
1017 if wclass
.name
== name
:
1021 def enum_by_name(name
):
1027 def find_closing(text
, open_tok
, close_tok
):
1028 if text
.find(open_tok
) == -1 or text
.find(close_tok
) <= text
.find(open_tok
):
1029 return text
.find(close_tok
)
1030 return text
.find(close_tok
) + find_closing(text
[text
.find(close_tok
)+1:], open_tok
, close_tok
) + 1
1032 def unpretty_string(s
):
1034 while s
.find(" ") != -1:
1035 s
= s
.replace(" "," ")
1036 while s
.find("\t") != -1:
1037 s
= s
.replace("\t"," ")
1038 s
= s
.replace(" (","(")
1046 def from_string(str_def
, namespace
, line_number
):
1047 str_def
= str_def
.strip()
1048 if not str.startswith(str_def
, "enum "):
1050 if str_def
.count(";") != 1:
1052 str_def
= str_def
[5:]
1054 split
= str_def
.split(":")
1055 if(len(split
) != 2):
1057 enum
.name
= split
[0].strip()
1058 if enum
.name
not in enum_names
:
1061 if str_def
.count("{") != str_def
.count("}") != 1:
1063 if len(str_def
) < str_def
.find("}")+2 or str_def
[str_def
.find("}")+1] != ';':
1065 str_def
= str_def
.split("{")[-1].split("}")[0]
1067 for val
in str_def
.split(','):
1068 enum
.values
.append(val
.strip().split('=')[0].strip())
1069 enum
.namespace
= namespace
1072 def gen_boost_py(self
):
1073 text
= "\n\t\tenum_<" + self
.namespace
+ "::" + self
.name
+ ">(\"" + self
.name
+ "\")\n"
1074 for value
in self
.values
:
1075 text
+= "\t\t\t.value(\"" + value
+ "\"," + self
.namespace
+ "::" + value
+ ")\n"
1080 ret
= "Enum " + self
.namespace
+ "::" + self
.name
+ "(\n"
1081 for val
in self
.values
:
1082 ret
= ret
+ "\t" + val
+ "\n"
1086 return __str__(self
)
1091 containing_file
= None
1096 def __init__(self
, containing_file
, class_
):
1097 self
.orig_text
= "Auto generated default constructor"
1099 self
.containing_file
= containing_file
1100 self
.member_of
= class_
1101 self
.protected
= False
1103 def from_string(str_def
, containing_file
, class_
, line_number
, protected
= False):
1106 if str_def
.count("delete;") > 0:
1108 con
= WConstructor(containing_file
, class_
)
1109 con
.orig_text
= str_def
1111 con
.duplicate
= False
1112 con
.protected
= protected
1113 if str.startswith(str_def
, "inline "):
1114 str_def
= str_def
[7:]
1115 if not str.startswith(str_def
, class_
.name
+ "("):
1117 str_def
= str_def
[len(class_
.name
)+1:]
1118 found
= find_closing(str_def
, "(", ")")
1121 str_def
= str_def
[0:found
].strip()
1122 if len(str_def
) == 0:
1124 for arg
in split_list(str_def
, ","):
1125 parsed
= Attribute
.from_string(arg
.strip(), containing_file
, line_number
)
1128 con
.args
.append(parsed
)
1132 if self
.duplicate
or self
.protected
:
1134 text
= "\n\t\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1135 text
+= "\n\t\t" + self
.member_of
.name
+ "("
1136 for arg
in self
.args
:
1137 text
+= arg
.gen_listitem() + ", "
1138 if len(self
.args
) > 0:
1143 def gen_decl_derive(self
):
1144 if self
.duplicate
or self
.protected
:
1146 text
= "\n\t\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1147 text
+= "\n\t\t" + self
.member_of
.name
+ "("
1148 for arg
in self
.args
:
1149 text
+= arg
.gen_listitem() + ", "
1150 if len(self
.args
) > 0:
1153 if len(self
.args
) == 0:
1156 text
+= self
.member_of
.namespace
+ "::" + self
.member_of
.name
+ "("
1157 for arg
in self
.args
:
1158 text
+= arg
.gen_call() + ", "
1159 if len(self
.args
) > 0:
1164 def gen_decl_wrapperclass(self
):
1165 if self
.duplicate
or self
.protected
:
1167 text
= "\n\t\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1168 text
+= "\n\t\t" + self
.member_of
.name
+ "Wrap("
1169 for arg
in self
.args
:
1170 text
+= arg
.gen_listitem() + ", "
1171 if len(self
.args
) > 0:
1174 if len(self
.args
) == 0:
1177 text
+= self
.member_of
.name
+ "("
1178 for arg
in self
.args
:
1179 text
+= arg
.gen_call() + ", "
1180 if len(self
.args
) > 0:
1185 def gen_decl_hash_py(self
):
1186 text
= self
.member_of
.name
+ "("
1187 for arg
in self
.args
:
1188 text
+= arg
.gen_listitem_hash() + ", "
1189 if len(self
.args
) > 0:
1195 if self
.duplicate
or self
.protected
:
1197 text
= "\n\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1198 text
+= "\n\t" + self
.member_of
.name
+ "::" + self
.member_of
.name
+ "("
1199 for arg
in self
.args
:
1200 text
+= arg
.gen_listitem() + ", "
1201 if len(self
.args
) > 0:
1204 for arg
in self
.args
:
1205 text
+= arg
.gen_translation()
1206 if self
.member_of
.link_type
!= link_types
.derive
:
1207 text
+= "\n\t\tthis->ref_obj = new " + self
.member_of
.namespace
+ "::" + self
.member_of
.name
+ "("
1208 for arg
in self
.args
:
1209 text
+= arg
.gen_call() + ", "
1210 if len(self
.args
) > 0:
1212 if self
.member_of
.link_type
!= link_types
.derive
:
1214 if self
.member_of
.link_type
== link_types
.global_list
:
1215 text
+= "\n\t\tthis->" + self
.member_of
.id_
.varname
+ " = this->ref_obj->" + self
.member_of
.id_
.varname
+ ";"
1216 for arg
in self
.args
:
1217 text
+= arg
.gen_cleanup()
1221 def gen_boost_py(self
):
1222 if self
.duplicate
or self
.protected
or len(self
.args
) == 0:
1224 text
= "\n\t\t\t.def(init"
1227 text
+= a
.gen_listitem_hash() + ", "
1228 text
= text
[0:-2] + ">())"
1236 ret_attr_type
= attr_types
.default
1242 containing_file
= None
1247 def from_string(str_def
, containing_file
, class_
, line_number
, namespace
):
1248 if str_def
.count("delete;") > 0:
1251 func
.is_static
= False
1252 func
.is_inline
= False
1253 func
.is_virtual
= False
1254 func
.ret_attr_type
= attr_types
.default
1255 func
.is_operator
= False
1256 func
.member_of
= None
1257 func
.orig_text
= str_def
1259 func
.containing_file
= containing_file
1260 func
.member_of
= class_
1261 func
.duplicate
= False
1262 func
.namespace
= namespace
1263 str_def
= str_def
.replace("operator ","operator")
1264 if str.startswith(str_def
, "static "):
1265 func
.is_static
= True
1266 str_def
= str_def
[7:]
1268 func
.is_static
= False
1269 if str.startswith(str_def
, "inline "):
1270 func
.is_inline
= True
1271 str_def
= str_def
[7:]
1273 func
.is_inline
= False
1274 if str.startswith(str_def
, "virtual "):
1275 func
.is_virtual
= True
1276 str_def
= str_def
[8:]
1278 func
.is_virtual
= False
1280 if str_def
.count(" ") == 0:
1283 parts
= split_list(str_def
.strip(), " ")
1288 if part
in ["unsigned", "long", "short"]:
1289 prefix
+= part
+ " "
1298 func
.ret_type
= WType
.from_string(prefix
+ parts
[0], containing_file
, line_number
)
1300 if func
.ret_type
== None:
1304 for part
in parts
[2:]:
1305 str_def
= str_def
+ " " + part
1307 found
= str_def
.find("(")
1308 if found
== -1 or (str_def
.find(" ") != -1 and found
> str_def
.find(" ")):
1310 func
.name
= str_def
[:found
]
1311 str_def
= str_def
[found
:]
1312 if func
.name
.find("operator") != -1 and str.startswith(str_def
, "()("):
1314 str_def
= str_def
[2:]
1315 str_def
= str_def
[1:]
1316 if func
.name
.find("operator") != -1:
1317 func
.is_operator
= True
1318 if func
.name
.find("*") == 0:
1319 func
.name
= func
.name
.replace("*", "")
1320 func
.ret_type
.attr_type
= attr_types
.star
1321 if func
.name
.find("&&") == 0:
1322 func
.name
= func
.name
.replace("&&", "")
1323 func
.ret_type
.attr_type
= attr_types
.ampamp
1324 if func
.name
.find("&") == 0:
1325 func
.name
= func
.name
.replace("&", "")
1326 func
.ret_type
.attr_type
= attr_types
.amp
1328 found
= find_closing(str_def
, "(", ")")
1331 str_def
= str_def
[0:found
]
1332 if func
.name
in blacklist_methods
:
1334 if func
.namespace
!= None and func
.namespace
!= "":
1335 if (func
.namespace
+ "::" + func
.name
) in blacklist_methods
:
1337 if func
.member_of
!= None:
1338 if (func
.namespace
+ "::" + func
.member_of
.name
+ "::" + func
.name
) in blacklist_methods
:
1340 if func
.is_operator
and func
.name
.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators
:
1343 testname
= func
.name
1344 if func
.is_operator
:
1345 testname
= testname
[:testname
.find("operator")]
1346 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:
1349 func
.alias
= func
.name
1350 if func
.name
in keyword_aliases
:
1351 func
.alias
= keyword_aliases
[func
.name
]
1352 str_def
= str_def
[:found
].strip()
1353 if(len(str_def
) == 0):
1355 for arg
in split_list(str_def
, ","):
1356 if arg
.strip() == "...":
1358 parsed
= Attribute
.from_string(arg
.strip(), containing_file
, line_number
)
1361 func
.args
.append(parsed
)
1364 def gen_alias(self
):
1365 self
.alias
= self
.name
1366 for arg
in self
.args
:
1367 self
.alias
+= "__" + arg
.wtype
.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","")
1372 text
= "\n\t\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1376 text
+= self
.ret_type
.gen_text() + " " + self
.alias
+ "("
1377 for arg
in self
.args
:
1378 text
+= arg
.gen_listitem()
1380 if len(self
.args
) > 0:
1385 def gen_decl_virtual(self
):
1388 if not self
.is_virtual
:
1389 return self
.gen_decl()
1390 text
= "\n\t\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1391 text
+= "\n\t\tvirtual "
1394 text
+= self
.ret_type
.gen_text() + " py_" + self
.alias
+ "("
1395 for arg
in self
.args
:
1396 text
+= arg
.gen_listitem()
1398 if len(self
.args
) > 0:
1401 if len(self
.args
) == 0:
1405 for arg
in self
.args
:
1406 text
+= "\n\t\t\t(void)" + arg
.gen_varname() + ";"
1408 text
+= "\n\t\tvirtual "
1411 text
+= self
.ret_type
.gen_text() + " " + self
.name
+ "("
1412 for arg
in self
.args
:
1413 text
+= arg
.gen_listitem_cpp()
1415 if len(self
.args
) > 0:
1417 text
+= ") override;\n"
1420 def gen_decl_hash_py(self
):
1421 text
= self
.ret_type
.gen_text() + " " + self
.alias
+ "("
1422 for arg
in self
.args
:
1423 text
+= arg
.gen_listitem_hash() + ", "
1424 if len(self
.args
) > 0:
1432 text
= "\n\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1433 text
+= "\n\t" + self
.ret_type
.gen_text() + " "
1434 if self
.member_of
!= None:
1435 text
+= self
.member_of
.name
+ "::"
1436 text
+= self
.alias
+ "("
1437 for arg
in self
.args
:
1438 text
+= arg
.gen_listitem()
1440 if len(self
.args
) > 0:
1443 for arg
in self
.args
:
1444 text
+= arg
.gen_translation()
1446 if self
.ret_type
.name
!= "void":
1447 if self
.ret_type
.name
in known_containers
:
1448 text
+= self
.ret_type
.gen_text_cpp()
1450 text
+= self
.ret_type
.gen_text()
1451 if self
.ret_type
.name
in classnames
or (self
.ret_type
.name
in known_containers
and self
.ret_type
.attr_type
== attr_types
.star
):
1454 if self
.ret_type
.name
in classnames
:
1455 text
+= self
.ret_type
.name
+ "::get_py_obj("
1456 if self
.member_of
== None:
1457 text
+= "::" + self
.namespace
+ "::" + self
.alias
+ "("
1458 elif self
.is_static
:
1459 text
+= self
.member_of
.namespace
+ "::" + self
.member_of
.name
+ "::" + self
.name
+ "("
1461 text
+= "this->get_cpp_obj()->" + self
.name
+ "("
1462 for arg
in self
.args
:
1463 text
+= arg
.gen_call() + ", "
1464 if len(self
.args
) > 0:
1466 if self
.ret_type
.name
in classnames
:
1469 for arg
in self
.args
:
1470 text
+= arg
.gen_cleanup()
1471 if self
.ret_type
.name
!= "void":
1472 if self
.ret_type
.name
in classnames
:
1473 text
+= "\n\t\treturn *ret_;"
1474 elif self
.ret_type
.name
in known_containers
:
1475 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
)
1476 text
+= "\n\t\treturn ret____tmp;"
1478 text
+= "\n\t\treturn ret_;"
1482 def gen_def_virtual(self
):
1485 if not self
.is_virtual
:
1486 return self
.gen_def()
1487 text
= "\n\t// WRAPPED from \"" + self
.orig_text
.replace("\n"," ") + "\" in " + self
.containing_file
1491 text
+= self
.ret_type
.gen_text() + " " + self
.member_of
.name
+ "::" + self
.name
+ "("
1492 for arg
in self
.args
:
1493 text
+= arg
.gen_listitem_cpp()
1495 if len(self
.args
) > 0:
1498 for arg
in self
.args
:
1499 text
+= arg
.gen_translation_cpp()
1501 if self
.member_of
== None:
1502 text
+= "::" + self
.namespace
+ "::" + self
.alias
+ "("
1503 elif self
.is_static
:
1504 text
+= self
.member_of
.namespace
+ "::" + self
.member_of
.name
+ "::" + self
.name
+ "("
1506 text
+= "py_" + self
.alias
+ "("
1507 for arg
in self
.args
:
1508 text
+= arg
.gen_call_cpp() + ", "
1509 if len(self
.args
) > 0:
1511 if self
.ret_type
.name
in classnames
:
1514 for arg
in self
.args
:
1515 text
+= arg
.gen_cleanup()
1519 def gen_default_impl(self
):
1522 if not self
.is_virtual
:
1524 text
= "\n\n\t\t" + self
.ret_type
.gen_text() + " py_" + self
.alias
+ "("
1525 for arg
in self
.args
:
1526 text
+= arg
.gen_listitem() + ", "
1527 if len(self
.args
) > 0:
1530 call_string
= "py_" + self
.alias
+ "("
1531 for arg
in self
.args
:
1532 call_string
+= arg
.gen_varname() + ", "
1533 if len(self
.args
) > 0:
1534 call_string
= call_string
[0:-2]
1538 text
+= "\n\t\t\tif(boost::python::override py_" + self
.alias
+ " = this->get_override(\"py_" + self
.alias
+ "\"))"
1539 text
+= "\n\t\t\t\t" + call_string
1540 text
+= "\n\t\t\telse"
1541 text
+= "\n\t\t\t\t" + self
.member_of
.name
+ "::" + call_string
1544 text
+= "\n\n\t\t" + self
.ret_type
.gen_text() + " default_py_" + self
.alias
+ "("
1545 for arg
in self
.args
:
1546 text
+= arg
.gen_listitem() + ", "
1547 if len(self
.args
) > 0:
1550 text
+= "\n\t\t\tthis->" + self
.member_of
.name
+ "::" + call_string
1555 def gen_boost_py(self
):
1558 if self
.member_of
== None:
1561 text
= "\n\t\t\t.def"
1562 if len(self
.args
) > -1:
1563 if self
.ret_type
.name
in known_containers
:
1564 text
+= "<" + known_containers
[self
.ret_type
.name
].typename
+ " "
1566 text
+= "<" + self
.ret_type
.name
+ " "
1567 if self
.member_of
== None or self
.is_static
:
1570 text
+= "(" + self
.member_of
.name
+ "::*)("
1572 text
+= a
.gen_listitem_hash() + ", "
1573 if len(self
.args
) > 0:
1574 text
= text
[0:-2] + ")>"
1578 if self
.is_operator
:
1579 text
+= "(\"" + wrappable_operators
[self
.name
.replace("operator","")] + "\""
1581 if self
.member_of
!= None and self
.member_of
.link_type
== link_types
.derive
and self
.is_virtual
:
1582 text
+= "(\"py_" + self
.alias
+ "\""
1584 text
+= "(\"" + self
.alias
+ "\""
1585 if self
.member_of
!= None:
1586 text
+= ", &" + self
.member_of
.name
+ "::"
1587 if self
.member_of
.link_type
== link_types
.derive
and self
.is_virtual
:
1588 text
+= "py_" + self
.alias
1589 text
+= ", &" + self
.member_of
.name
+ "Wrap::default_py_" + self
.alias
1595 text
+= ", " + "YOSYS_PYTHON::" + self
.alias
+ ");"
1600 wtype
= attr_types
.default
1602 containing_file
= None
1607 def from_string(str_def
, containing_file
, class_
, line_number
, namespace
):
1609 member
.orig_text
= str_def
1612 member
.containing_file
= containing_file
1613 member
.member_of
= class_
1614 member
.namespace
= namespace
1615 member
.is_const
= False
1617 if str.startswith(str_def
, "const "):
1618 member
.is_const
= True
1619 str_def
= str_def
[6:]
1621 if str_def
.count(" ") == 0:
1624 parts
= split_list(str_def
.strip(), " ")
1629 if part
in ["unsigned", "long", "short"]:
1630 prefix
+= part
+ " "
1639 member
.wtype
= WType
.from_string(prefix
+ parts
[0], containing_file
, line_number
)
1641 if member
.wtype
== None:
1645 for part
in parts
[2:]:
1646 str_def
= str_def
+ " " + part
1648 if str_def
.find("(") != -1 or str_def
.find(")") != -1 or str_def
.find("{") != -1 or str_def
.find("}") != -1:
1651 found
= str_def
.find(";")
1655 found_eq
= str_def
.find("=")
1659 member
.name
= str_def
[:found
]
1660 str_def
= str_def
[found
+1:]
1661 if member
.name
.find("*") == 0:
1662 member
.name
= member
.name
.replace("*", "")
1663 member
.wtype
.attr_type
= attr_types
.star
1664 if member
.name
.find("&&") == 0:
1665 member
.name
= member
.name
.replace("&&", "")
1666 member
.wtype
.attr_type
= attr_types
.ampamp
1667 if member
.name
.find("&") == 0:
1668 member
.name
= member
.name
.replace("&", "")
1669 member
.wtype
.attr_type
= attr_types
.amp
1671 if(len(str_def
.strip()) != 0):
1674 if len(member
.name
.split(",")) > 1:
1676 for name
in member
.name
.split(","):
1677 name
= name
.strip();
1678 member_list
.append(WMember())
1679 member_list
[-1].orig_text
= member
.orig_text
1680 member_list
[-1].wtype
= member
.wtype
1681 member_list
[-1].name
= name
1682 member_list
[-1].containing_file
= member
.containing_file
1683 member_list
[-1].member_of
= member
.member_of
1684 member_list
[-1].namespace
= member
.namespace
1685 member_list
[-1].is_const
= member
.is_const
1691 text
= "\n\t\t" + self
.wtype
.gen_text() + " get_var_py_" + self
.name
+ "();\n"
1694 if self
.wtype
.name
in classnames
:
1695 text
+= "\n\t\tvoid set_var_py_" + self
.name
+ "(" + self
.wtype
.gen_text() + " *rhs);\n"
1697 text
+= "\n\t\tvoid set_var_py_" + self
.name
+ "(" + self
.wtype
.gen_text() + " rhs);\n"
1701 text
= "\n\t" + self
.wtype
.gen_text() + " " + self
.member_of
.name
+"::get_var_py_" + self
.name
+ "()"
1702 text
+= "\n\t{\n\t\t"
1703 if self
.wtype
.attr_type
== attr_types
.star
:
1704 text
+= "if(this->get_cpp_obj()->" + self
.name
+ " == NULL)\n\t\t\t"
1705 text
+= "throw std::runtime_error(\"Member \\\"" + self
.name
+ "\\\" is NULL\");\n\t\t"
1706 if self
.wtype
.name
in known_containers
:
1707 text
+= self
.wtype
.gen_text_cpp()
1709 text
+= self
.wtype
.gen_text()
1711 if self
.wtype
.name
in classnames
or (self
.wtype
.name
in known_containers
and self
.wtype
.attr_type
== attr_types
.star
):
1714 if self
.wtype
.name
in classnames
:
1715 text
+= self
.wtype
.name
+ "::get_py_obj("
1716 if self
.wtype
.attr_type
!= attr_types
.star
:
1718 text
+= "this->get_cpp_obj()->" + self
.name
1719 if self
.wtype
.name
in classnames
:
1723 if self
.wtype
.name
in classnames
:
1724 text
+= "\n\t\treturn *ret_;"
1725 elif self
.wtype
.name
in known_containers
:
1726 text
+= known_containers
[self
.wtype
.name
].translate_cpp("ret_", self
.wtype
.cont
.args
, "\n\t\t", self
.wtype
.attr_type
== attr_types
.star
)
1727 text
+= "\n\t\treturn ret____tmp;"
1729 text
+= "\n\t\treturn ret_;"
1735 ret
= Attribute(self
.wtype
, "rhs");
1737 if self
.wtype
.name
in classnames
:
1738 text
+= "\n\tvoid " + self
.member_of
.name
+ "::set_var_py_" + self
.name
+ "(" + self
.wtype
.gen_text() + " *rhs)"
1740 text
+= "\n\tvoid " + self
.member_of
.name
+ "::set_var_py_" + self
.name
+ "(" + self
.wtype
.gen_text() + " rhs)"
1742 text
+= ret
.gen_translation()
1743 text
+= "\n\t\tthis->get_cpp_obj()->" + self
.name
+ " = " + ret
.gen_call() + ";"
1748 def gen_boost_py(self
):
1749 text
= "\n\t\t\t.add_property(\"" + self
.name
+ "\", &" + self
.member_of
.name
+ "::get_var_py_" + self
.name
1750 if not self
.is_const
:
1751 text
+= ", &" + self
.member_of
.name
+ "::set_var_py_" + self
.name
1757 wtype
= attr_types
.default
1759 containing_file
= None
1763 def from_string(str_def
, containing_file
, line_number
, namespace
):
1765 glbl
.orig_text
= str_def
1768 glbl
.containing_file
= containing_file
1769 glbl
.namespace
= namespace
1770 glbl
.is_const
= False
1772 if not str.startswith(str_def
, "extern"):
1774 str_def
= str_def
[7:]
1776 if str.startswith(str_def
, "const "):
1777 glbl
.is_const
= True
1778 str_def
= str_def
[6:]
1780 if str_def
.count(" ") == 0:
1783 parts
= split_list(str_def
.strip(), " ")
1788 if part
in ["unsigned", "long", "short"]:
1789 prefix
+= part
+ " "
1798 glbl
.wtype
= WType
.from_string(prefix
+ parts
[0], containing_file
, line_number
)
1800 if glbl
.wtype
== None:
1804 for part
in parts
[2:]:
1805 str_def
= str_def
+ " " + part
1807 if str_def
.find("(") != -1 or str_def
.find(")") != -1 or str_def
.find("{") != -1 or str_def
.find("}") != -1:
1810 found
= str_def
.find(";")
1814 found_eq
= str_def
.find("=")
1818 glbl
.name
= str_def
[:found
]
1819 str_def
= str_def
[found
+1:]
1820 if glbl
.name
.find("*") == 0:
1821 glbl
.name
= glbl
.name
.replace("*", "")
1822 glbl
.wtype
.attr_type
= attr_types
.star
1823 if glbl
.name
.find("&&") == 0:
1824 glbl
.name
= glbl
.name
.replace("&&", "")
1825 glbl
.wtype
.attr_type
= attr_types
.ampamp
1826 if glbl
.name
.find("&") == 0:
1827 glbl
.name
= glbl
.name
.replace("&", "")
1828 glbl
.wtype
.attr_type
= attr_types
.amp
1830 if(len(str_def
.strip()) != 0):
1833 if len(glbl
.name
.split(",")) > 1:
1835 for name
in glbl
.name
.split(","):
1836 name
= name
.strip();
1837 glbl_list
.append(WGlobal())
1838 glbl_list
[-1].orig_text
= glbl
.orig_text
1839 glbl_list
[-1].wtype
= glbl
.wtype
1840 glbl_list
[-1].name
= name
1841 glbl_list
[-1].containing_file
= glbl
.containing_file
1842 glbl_list
[-1].namespace
= glbl
.namespace
1843 glbl_list
[-1].is_const
= glbl
.is_const
1852 text
+= self
.wtype
.gen_text() + " get_var_py_" + self
.name
+ "()"
1853 text
+= "\n\t{\n\t\t"
1854 if self
.wtype
.attr_type
== attr_types
.star
:
1855 text
+= "if(" + self
.namespace
+ "::" + self
.name
+ " == NULL)\n\t\t\t"
1856 text
+= "throw std::runtime_error(\"" + self
.namespace
+ "::" + self
.name
+ " is NULL\");\n\t\t"
1857 if self
.wtype
.name
in known_containers
:
1858 text
+= self
.wtype
.gen_text_cpp()
1862 text
+= self
.wtype
.gen_text()
1864 if self
.wtype
.name
in classnames
or (self
.wtype
.name
in known_containers
and self
.wtype
.attr_type
== attr_types
.star
):
1867 if self
.wtype
.name
in classnames
:
1868 text
+= self
.wtype
.name
+ "::get_py_obj("
1869 if self
.wtype
.attr_type
!= attr_types
.star
:
1871 text
+= self
.namespace
+ "::" + self
.name
1872 if self
.wtype
.name
in classnames
:
1876 if self
.wtype
.name
in classnames
:
1877 text
+= "\n\t\treturn *ret_;"
1878 elif self
.wtype
.name
in known_containers
:
1879 text
+= known_containers
[self
.wtype
.name
].translate_cpp("ret_", self
.wtype
.cont
.args
, "\n\t\t", self
.wtype
.attr_type
== attr_types
.star
)
1880 text
+= "\n\t\treturn ret____tmp;"
1882 text
+= "\n\t\treturn ret_;"
1888 ret
= Attribute(self
.wtype
, "rhs");
1890 if self
.wtype
.name
in classnames
:
1891 text
+= "\n\tvoid set_var_py_" + self
.name
+ "(" + self
.wtype
.gen_text() + " *rhs)"
1893 text
+= "\n\tvoid set_var_py_" + self
.name
+ "(" + self
.wtype
.gen_text() + " rhs)"
1895 text
+= ret
.gen_translation()
1896 text
+= "\n\t\t" + self
.namespace
+ "::" + self
.name
+ " = " + ret
.gen_call() + ";"
1901 def gen_boost_py(self
):
1902 text
= "\n\t\t\t.add_static_property(\"" + self
.name
+ "\", &" + "YOSYS_PYTHON::get_var_py_" + self
.name
1903 if not self
.is_const
:
1904 text
+= ", &YOSYS_PYTHON::set_var_py_" + self
.name
1908 def concat_namespace(tuple_list
):
1909 if len(tuple_list
) == 0:
1912 for namespace
in tuple_list
:
1913 ret
+= "::" + namespace
[0]
1916 def calc_ident(text
):
1917 if len(text
) == 0 or text
[0] != ' ':
1919 return calc_ident(text
[1:]) + 1
1921 def assure_length(text
, length
, left
= False):
1922 if len(text
) > length
:
1923 return text
[:length
]
1925 return text
+ " "*(length
- len(text
))
1926 return " "*(length
- len(text
)) + text
1928 def parse_header(source
):
1929 debug("Parsing " + source
.name
+ ".pyh",1)
1930 source_file
= open(source
.name
+ ".pyh", "r")
1933 in_line
= source_file
.readline()
1939 source_text
.append(in_line
.replace("char *", "char_p ").replace("char* ", "char_p "))
1940 in_line
= source_file
.readline()
1946 private_segment
= False
1948 while i
< len(source_text
):
1949 line
= source_text
[i
].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
1950 ugly_line
= unpretty_string(line
)
1952 # for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line
1953 if 'union {' in line
:
1955 while j
< len(source_text
):
1956 union_line
= source_text
[j
]
1957 if '};' in union_line
:
1958 source_text
[j
] = '\n'
1961 if j
!= len(source_text
):
1965 if str.startswith(ugly_line
, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1:
1966 namespace_name
= ugly_line
[10:].replace("{","").strip()
1967 namespaces
.append((namespace_name
, ugly_line
.count("{")))
1968 debug("-----NAMESPACE " + concat_namespace(namespaces
) + "-----",3)
1972 if len(namespaces
) != 0:
1973 namespaces
[-1] = (namespaces
[-1][0], namespaces
[-1][1] + ugly_line
.count("{") - ugly_line
.count("}"))
1974 if namespaces
[-1][1] == 0:
1975 debug("-----END NAMESPACE " + concat_namespace(namespaces
) + "-----",3)
1980 if class_
== None and (str.startswith(ugly_line
, "struct ") or str.startswith(ugly_line
, "class")) and ugly_line
.count(";") == 0:
1982 struct_name
= ugly_line
.split(" ")[1].split("::")[-1]
1983 impl_namespaces
= ugly_line
.split(" ")[1].split("::")[:-1]
1984 complete_namespace
= concat_namespace(namespaces
)
1985 for namespace
in impl_namespaces
:
1986 complete_namespace
+= "::" + namespace
1987 debug("\tFound " + struct_name
+ " in " + complete_namespace
,2)
1989 base_class_name
= None
1990 if len(ugly_line
.split(" : ")) > 1: # class is derived
1991 deriv_str
= ugly_line
.split(" : ")[1]
1992 if len(deriv_str
.split("::")) > 1: # namespace of base class is given
1993 base_class_name
= deriv_str
.split("::", 1)[1]
1995 base_class_name
= deriv_str
.split(" ")[0]
1996 debug("\t " + struct_name
+ " is derived from " + base_class_name
,2)
1997 base_class
= class_by_name(base_class_name
)
1999 class_
= (class_by_name(struct_name
), ugly_line
.count("{"))#calc_ident(line))
2000 if struct_name
in classnames
:
2001 class_
[0].namespace
= complete_namespace
2002 class_
[0].base_class
= base_class
2007 class_
= (class_
[0], class_
[1] + ugly_line
.count("{") - ugly_line
.count("}"))
2009 if class_
[0] == None:
2010 debug("\tExiting unknown class", 3)
2012 debug("\tExiting class " + class_
[0].name
, 3)
2014 private_segment
= False
2018 if class_
!= None and (line
.find("private:") != -1 or line
.find("protected:") != -1):
2019 private_segment
= True
2022 if class_
!= None and line
.find("public:") != -1:
2023 private_segment
= False
2029 if private_segment
and class_
!= None and class_
[0] != None:
2030 candidate
= WConstructor
.from_string(ugly_line
, source
.name
, class_
[0], i
, True)
2031 if candidate
!= None:
2032 debug("\t\tFound constructor of class \"" + class_
[0].name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2033 class_
[0].found_constrs
.append(candidate
)
2037 if not private_segment
and (class_
== None or class_
[0] != None):
2039 candidate
= WFunction
.from_string(ugly_line
, source
.name
, class_
[0], i
, concat_namespace(namespaces
))
2041 candidate
= WFunction
.from_string(ugly_line
, source
.name
, None, i
, concat_namespace(namespaces
))
2042 if candidate
!= None and candidate
.name
.find("::") == -1:
2044 debug("\tFound unowned function \"" + candidate
.name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2045 unowned_functions
.append(candidate
)
2047 debug("\t\tFound function \"" + candidate
.name
+ "\" of class \"" + class_
[0].name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2048 class_
[0].found_funs
.append(candidate
)
2050 candidate
= WEnum
.from_string(ugly_line
, concat_namespace(namespaces
), i
)
2051 if candidate
!= None:
2052 enums
.append(candidate
)
2053 debug("\tFound enum \"" + candidate
.name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2054 elif class_
!= None and class_
[1] == 1:
2055 candidate
= WConstructor
.from_string(ugly_line
, source
.name
, class_
[0], i
)
2056 if candidate
!= None:
2057 debug("\t\tFound constructor of class \"" + class_
[0].name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2058 class_
[0].found_constrs
.append(candidate
)
2060 candidate
= WMember
.from_string(ugly_line
, source
.name
, class_
[0], i
, concat_namespace(namespaces
))
2061 if candidate
!= None:
2062 if type(candidate
) == list:
2064 debug("\t\tFound member \"" + c
.name
+ "\" of class \"" + class_
[0].name
+ "\" of type \"" + c
.wtype
.name
+ "\"", 2)
2065 class_
[0].found_vars
.extend(candidate
)
2067 debug("\t\tFound member \"" + candidate
.name
+ "\" of class \"" + class_
[0].name
+ "\" of type \"" + candidate
.wtype
.name
+ "\"", 2)
2068 class_
[0].found_vars
.append(candidate
)
2069 if candidate
== None and class_
== None:
2070 candidate
= WGlobal
.from_string(ugly_line
, source
.name
, i
, concat_namespace(namespaces
))
2071 if candidate
!= None:
2072 if type(candidate
) == list:
2075 debug("\tFound global \"" + c
.name
+ "\" in namespace " + concat_namespace(namespaces
), 2)
2077 glbls
.append(candidate
)
2078 debug("\tFound global \"" + candidate
.name
+ "\" in namespace " + concat_namespace(namespaces
), 2)
2081 line
= unpretty_string(line
)
2082 while candidate
== None and j
+1 < len(source_text
) and line
.count(';') <= 1 and line
.count("(") >= line
.count(")"):
2084 line
= line
+ "\n" + unpretty_string(source_text
[j
])
2086 candidate
= WFunction
.from_string(ugly_line
, source
.name
, class_
[0], i
, concat_namespace(namespaces
))
2088 candidate
= WFunction
.from_string(ugly_line
, source
.name
, None, i
, concat_namespace(namespaces
))
2089 if candidate
!= None and candidate
.name
.find("::") == -1:
2091 debug("\tFound unowned function \"" + candidate
.name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2092 unowned_functions
.append(candidate
)
2094 debug("\t\tFound function \"" + candidate
.name
+ "\" of class \"" + class_
[0].name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2095 class_
[0].found_funs
.append(candidate
)
2097 candidate
= WEnum
.from_string(line
, concat_namespace(namespaces
), i
)
2098 if candidate
!= None:
2099 enums
.append(candidate
)
2100 debug("\tFound enum \"" + candidate
.name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2103 candidate
= WConstructor
.from_string(line
, source
.name
, class_
[0], i
)
2104 if candidate
!= None:
2105 debug("\t\tFound constructor of class \"" + class_
[0].name
+ "\" in namespace " + concat_namespace(namespaces
),2)
2106 class_
[0].found_constrs
.append(candidate
)
2109 candidate
= WGlobal
.from_string(line
, source
.name
, i
, concat_namespace(namespaces
))
2110 if candidate
!= None:
2111 if type(candidate
) == list:
2114 debug("\tFound global \"" + c
.name
+ "\" in namespace " + concat_namespace(namespaces
), 2)
2116 glbls
.append(candidate
)
2117 debug("\tFound global \"" + candidate
.name
+ "\" in namespace " + concat_namespace(namespaces
), 2)
2119 if candidate
!= None:
2122 line
= source_text
[i
].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
2123 ugly_line
= unpretty_string(line
)
2124 if len(namespaces
) != 0:
2125 namespaces
[-1] = (namespaces
[-1][0], namespaces
[-1][1] + ugly_line
.count("{") - ugly_line
.count("}"))
2126 if namespaces
[-1][1] == 0:
2127 debug("-----END NAMESPACE " + concat_namespace(namespaces
) + "-----",3)
2130 class_
= (class_
[0] , class_
[1] + ugly_line
.count("{") - ugly_line
.count("}"))
2132 if class_
[0] == None:
2133 debug("\tExiting unknown class", 3)
2135 debug("\tExiting class " + class_
[0].name
, 3)
2137 private_segment
= False
2142 def debug(message
, level
):
2143 if level
<= debug
.debug_level
:
2146 def expand_function(f
):
2150 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")):
2151 fi
= copy
.deepcopy(f
)
2152 fi
.args
= copy
.deepcopy(arg_list
)
2154 arg_list
.append(arg
)
2158 def expand_functions():
2159 global unowned_functions
2161 for fun
in unowned_functions
:
2162 new_funs
.extend(expand_function(fun
))
2163 unowned_functions
= new_funs
2164 for source
in sources
:
2165 for class_
in source
.classes
:
2167 for fun
in class_
.found_funs
:
2168 new_funs
.extend(expand_function(fun
))
2169 class_
.found_funs
= new_funs
2171 def inherit_members():
2172 for source
in sources
:
2173 for class_
in source
.classes
:
2174 if class_
.base_class
:
2175 base_funs
= copy
.deepcopy(class_
.base_class
.found_funs
)
2176 for fun
in base_funs
:
2177 fun
.member_of
= class_
2178 fun
.namespace
= class_
.namespace
2179 base_vars
= copy
.deepcopy(class_
.base_class
.found_vars
)
2180 for var
in base_vars
:
2181 var
.member_of
= class_
2182 var
.namespace
= class_
.namespace
2183 class_
.found_funs
.extend(base_funs
)
2184 class_
.found_vars
.extend(base_vars
)
2186 def clean_duplicates():
2187 for source
in sources
:
2188 for class_
in source
.classes
:
2190 for fun
in class_
.found_funs
:
2191 if fun
.gen_decl_hash_py() in known_decls
:
2192 debug("Multiple declarations of " + fun
.gen_decl_hash_py(),3)
2193 other
= known_decls
[fun
.gen_decl_hash_py()]
2196 if fun
.gen_decl_hash_py() == other
.gen_decl_hash_py():
2197 fun
.duplicate
= True
2198 debug("Disabled \"" + fun
.gen_decl_hash_py() + "\"", 3)
2200 known_decls
[fun
.gen_decl_hash_py()] = fun
2202 for con
in class_
.found_constrs
:
2203 if con
.gen_decl_hash_py() in known_decls
:
2204 debug("Multiple declarations of " + con
.gen_decl_hash_py(),3)
2205 con
.duplicate
= True
2207 known_decls
.append(con
.gen_decl_hash_py())
2209 for fun
in unowned_functions
:
2210 if fun
.gen_decl_hash_py() in known_decls
:
2211 debug("Multiple declarations of " + fun
.gen_decl_hash_py(),3)
2212 fun
.duplicate
= True
2214 known_decls
.append(fun
.gen_decl_hash_py())
2216 def gen_wrappers(filename
, debug_level_
= 0):
2217 debug
.debug_level
= debug_level_
2218 for source
in sources
:
2219 parse_header(source
)
2227 col
= shutil
.get_terminal_size((80,20)).columns
2229 debug("-"*math
.floor((col
-7)/2)+"SUMMARY"+"-"*math
.ceil((col
-7)/2), 1)
2231 for source
in sources
:
2232 for class_
in source
.classes
:
2233 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)
2234 if len(class_
.found_constrs
) == 0:
2235 class_
.found_constrs
.append(WConstructor(source
.name
, class_
))
2236 debug(str(len(unowned_functions
)) + " functions are unowned", 1)
2237 debug(str(len(unowned_functions
)) + " global variables", 1)
2239 debug("Enum " + assure_length(enum
.name
, len(max(enum_names
, key
=len)), True) + " contains " + assure_length(str(len(enum
.values
)), 2, False) + " values", 1)
2241 wrapper_file
= open(filename
, "w+")
2244 * yosys -- Yosys Open SYnthesis Suite
2246 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
2248 * Permission to use, copy, modify, and/or distribute this software for any
2249 * purpose with or without fee is hereby granted, provided that the above
2250 * copyright notice and this permission notice appear in all copies.
2252 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2253 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2254 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2255 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2256 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2257 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2258 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2260 * This is a generated file and can be overwritten by make
2265 for source
in sources
:
2266 wrapper_file
.write("#include \""+source
.name
+".h\"\n")
2267 wrapper_file
.write("""
2268 #include <boost/python/module.hpp>
2269 #include <boost/python/class.hpp>
2270 #include <boost/python/wrapper.hpp>
2271 #include <boost/python/call.hpp>
2272 #include <boost/python.hpp>
2273 #include <iosfwd> // std::streamsize
2275 #include <boost/iostreams/concepts.hpp> // boost::iostreams::sink
2276 #include <boost/iostreams/stream.hpp>
2277 USING_YOSYS_NAMESPACE
2279 namespace YOSYS_PYTHON {
2281 struct YosysStatics{};
2284 for source
in sources
:
2285 for wclass
in source
.classes
:
2286 wrapper_file
.write("\n\tstruct " + wclass
.name
+ ";")
2288 wrapper_file
.write("\n")
2290 for source
in sources
:
2291 for wclass
in source
.classes
:
2292 wrapper_file
.write(wclass
.gen_decl(source
.name
))
2294 wrapper_file
.write("\n")
2296 for source
in sources
:
2297 for wclass
in source
.classes
:
2298 wrapper_file
.write(wclass
.gen_funs(source
.name
))
2300 for fun
in unowned_functions
:
2301 wrapper_file
.write(fun
.gen_def())
2304 wrapper_file
.write(glbl
.gen_def())
2306 wrapper_file
.write(""" struct Initializer
2309 if(!Yosys::yosys_already_setup())
2311 Yosys::log_streams.push_back(&std::cout);
2312 Yosys::log_error_stderr = true;
2313 Yosys::yosys_setup();
2317 Initializer(Initializer const &) {}
2320 Yosys::yosys_shutdown();
2325 /// source: https://stackoverflow.com/questions/26033781/converting-python-io-object-to-stdostream-when-using-boostpython?noredirect=1&lq=1
2326 /// @brief Type that implements the Boost.IOStream's Sink and Flushable
2327 /// concept for writing data to Python object that support:
2328 /// n = object.write(str) # n = None or bytes written
2329 /// object.flush() # if flush exists, then it is callable
2330 class PythonOutputDevice
2334 // This class models both the Sink and Flushable concepts.
2336 : boost::iostreams::sink_tag,
2337 boost::iostreams::flushable_tag
2341 PythonOutputDevice(boost::python::object object)
2348 typedef char char_type;
2350 std::streamsize write(const char* buffer, std::streamsize buffer_size)
2352 namespace python = boost::python;
2353 // Copy the buffer to a python string.
2354 python::str data(buffer, buffer_size);
2356 // Invoke write on the python object, passing in the data. The following
2357 // is equivalent to:
2358 // n = object_.write(data)
2359 python::extract<std::streamsize> bytes_written(
2360 object_.attr("write")(data));
2362 // Per the Sink concept, return the number of bytes written. If the
2363 // Python return value provides a numeric result, then use it. Otherwise,
2364 // such as the case of a File object, use the buffer_size.
2365 return bytes_written.check()
2370 // Flushable concept.
2375 // If flush exists, then call it.
2376 boost::python::object flush = object_.attr("flush");
2377 if (!flush.is_none())
2382 // Always return true. If an error occurs, an exception should be thrown.
2387 boost::python::object object_;
2390 /// @brief Use an auxiliary function to adapt the legacy function.
2391 void log_to_stream(boost::python::object object)
2393 // Create an ostream that delegates to the python object.
2394 boost::iostreams::stream<PythonOutputDevice>* output = new boost::iostreams::stream<PythonOutputDevice>(object);
2395 Yosys::log_streams.insert(Yosys::log_streams.begin(), output);
2399 BOOST_PYTHON_MODULE(libyosys)
2401 using namespace boost::python;
2403 class_<Initializer>("Initializer");
2404 scope().attr("_hidden") = new Initializer();
2406 def("log_to_stream", &log_to_stream);
2410 wrapper_file
.write(enum
.gen_boost_py())
2412 for source
in sources
:
2413 for wclass
in source
.classes
:
2414 wrapper_file
.write(wclass
.gen_boost_py())
2416 for fun
in unowned_functions
:
2417 wrapper_file
.write(fun
.gen_boost_py())
2419 wrapper_file
.write("\n\n\t\tclass_<YosysStatics>(\"Yosys\")\n")
2421 wrapper_file
.write(glbl
.gen_boost_py())
2422 wrapper_file
.write("\t\t;\n")
2424 wrapper_file
.write("\n\t}\n}\n#endif")
2426 def print_includes():
2427 for source
in sources
:
2428 print(source
.name
+ ".pyh")