Merge pull request #1076 from thasti/centos7-build-fix
[yosys.git] / misc / py_wrap_generator.py
1 #
2 # yosys -- Yosys Open SYnthesis Suite
3 #
4 # Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 #
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.
9 #
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.
17 #
18 # Author Benedikt Tutzer
19 #
20
21 import copy
22
23 #Map c++ operator Syntax to Python functions
24 wrappable_operators = {
25 "<" : "__lt__",
26 "==": "__eq__",
27 "!=": "__ne__",
28 "+" : "__add__",
29 "-" : "__sub__",
30 "*" : "__mul__",
31 "/" : "__div__",
32 "()": "__call__"
33 }
34
35 #Restrict certain strings from being function names in Python
36 keyword_aliases = {
37 "in" : "in_",
38 "False" : "False_",
39 "None" : "None_",
40 "True" : "True_",
41 "and" : "and_",
42 "as" : "as_",
43 "assert" : "assert_",
44 "break" : "break_",
45 "class" : "class_",
46 "continue" : "continue_",
47 "def" : "def_",
48 "del" : "del_",
49 "elif" : "elif_",
50 "else" : "else_",
51 "except" : "except_",
52 "for" : "for_",
53 "from" : "from_",
54 "global" : "global_",
55 "if" : "if_",
56 "import" : "import_",
57 "in" : "in_",
58 "is" : "is_",
59 "lambda" : "lambda_",
60 "nonlocal" : "nonlocal_",
61 "not" : "not_",
62 "or" : "or_",
63 "pass" : "pass_",
64 "raise" : "raise_",
65 "return" : "return_",
66 "try" : "try_",
67 "while" : "while_",
68 "with" : "with_",
69 "yield" : "yield_"
70 }
71
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"]
75
76 from enum import Enum
77
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
86 #deleted
87 pointer = 3 #The Python Object contains a pointer to it's C++
88 #counterpart
89 derive = 4 #The Python-Wrapper is derived from the C++ object.
90
91 class attr_types(Enum):
92 star = "*"
93 amp = "&"
94 ampamp = "&&"
95 default = ""
96
97 #For source-files
98 class Source:
99 name = ""
100 classes = []
101
102 def __init__(self, name, classes):
103 self.name = name
104 self.classes = classes
105
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:
111 return []
112 if str_def.count(delim) == 0:
113 return [str_def]
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)
119 if comma == -1:
120 return [str_def]
121 comma = closing + comma
122 else:
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:
127 ret.extend(rest)
128 return ret
129
130 #Represents a Type
131 class WType:
132 name = ""
133 cont = None
134 attr_type = attr_types.default
135
136 def __init__(self, name = "", cont = None, attr_type = attr_types.default):
137 self.name = name
138 self.cont = cont
139 self.attr_type = attr_type
140
141 #Python type-string
142 def gen_text(self):
143 text = self.name
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
148 return text
149
150 #C++ type-string
151 def gen_text_cpp(self):
152 postfix = ""
153 if self.attr_type == attr_types.star:
154 postfix = "*"
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
161 text = self.name
162 if self.cont != None:
163 text += "<"
164 for a in self.cont.args:
165 text += a.gen_text_cpp() + ", "
166 text = text[:-2]
167 text += ">"
168 return text
169
170 @staticmethod
171 def from_string(str_def, containing_file, line_number):
172 str_def = str_def.strip()
173 if len(str_def) == 0:
174 return None
175 str_def = str_def.replace("RTLIL::SigSig", "std::pair<SigSpec, SigSpec>").replace("SigSig", "std::pair<SigSpec, SigSpec>")
176 t = WType()
177 t.name = ""
178 t.cont = None
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:
183 return None
184 t.name = str_def[:str_def.find("<")]
185
186 if t.name.count("*") + t.name.count("&") > 1:
187 return None
188
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("&","")
198
199 t.cont = candidate
200 if(t.name not in known_containers):
201 return None
202 return t
203
204 prefix = ""
205
206 if str.startswith(str_def, "unsigned "):
207 prefix = "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:]
215
216 str_def = str_def.split("::")[-1]
217
218 if str_def.count("*") + str_def.count("&") >= 2:
219 return None
220
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("&","")
230
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:
232 return None
233
234 if str_def.count(" ") == 0:
235 t.name = (prefix + str_def).replace("char_p", "char *")
236 t.cont = None
237 return t
238 return None
239
240 #Represents a container-type
241 class WContainer:
242 name = ""
243 args = []
244
245 def from_string(str_def, containing_file, line_number):
246 if str_def == None or len(str_def) < 4:
247 return None
248 cont = WContainer()
249 cont.name = str_def[:str_def.find("<")]
250 str_def = str_def[str_def.find("<")+1:find_closing(str_def, "<", ">")]
251 cont.args = []
252 for arg in split_list(str_def, ","):
253 candidate = WType.from_string(arg.strip(), containing_file, line_number)
254 if candidate == None:
255 return None
256 cont.args.append(candidate)
257 return cont
258
259 #Translators between Python and C++ containers
260 #Base Type
261 class Translator:
262 tmp_cntr = 0
263 typename = "DefaultType"
264 orig_name = "DefaultCpp"
265
266 @classmethod
267 def gen_type(c, types):
268 return "\nImplement a function that outputs the c++ type of this container here\n"
269
270 @classmethod
271 def translate(c, varname, types, prefix):
272 return "\nImplement a function translating a python container to a c++ container here\n"
273
274 @classmethod
275 def translate_cpp(c, varname, types, prefix, ref):
276 return "\nImplement a function translating a c++ container to a python container here\n"
277
278 #Translates list-types (vector, pool, set), that only differ in their name and
279 #the name of the insertion function
280 class PythonListTranslator(Translator):
281 typename = "boost::python::list"
282 insert_name = "Default"
283
284 #generate the c++ type string
285 @classmethod
286 def gen_type(c, types):
287 text = c.orig_name + "<"
288 if types[0].name in primitive_types:
289 text += types[0].name
290 elif types[0].name in known_containers:
291 text += known_containers[types[0].name].gen_type(types[0].cont.args)
292 else:
293 text += class_by_name(types[0].name).namespace + "::" + types[0].name
294 if types[0].attr_type == attr_types.star:
295 text += "*"
296 text += ">"
297 return text
298
299 #Generate C++ code to translate from a boost::python::list
300 @classmethod
301 def translate(c, varname, types, prefix):
302 text = prefix + c.gen_type(types) + " " + varname + "___tmp;"
303 cntr_name = "cntr_" + str(Translator.tmp_cntr)
304 Translator.tmp_cntr = Translator.tmp_cntr + 1
305 text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "); " + cntr_name + "++)"
306 text += prefix + "{"
307 tmp_name = "tmp_" + str(Translator.tmp_cntr)
308 Translator.tmp_cntr = Translator.tmp_cntr + 1
309 if types[0].name in known_containers:
310 text += prefix + "\t" + known_containers[types[0].name].typename + " " + tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "[" + cntr_name + "]);"
311 text += known_containers[types[0].name].translate(tmp_name, types[0].cont.args, prefix+"\t")
312 tmp_name = tmp_name + "___tmp"
313 text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + ");"
314 elif types[0].name in classnames:
315 text += prefix + "\t" + types[0].name + "* " + tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "[" + cntr_name + "]);"
316 if types[0].attr_type == attr_types.star:
317 text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + "->get_cpp_obj());"
318 else:
319 text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(*" + tmp_name + "->get_cpp_obj());"
320 else:
321 text += prefix + "\t" + types[0].name + " " + tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "[" + cntr_name + "]);"
322 text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + ");"
323 text += prefix + "}"
324 return text
325
326 #Generate C++ code to translate to a boost::python::list
327 @classmethod
328 def translate_cpp(c, varname, types, prefix, ref):
329 text = prefix + c.typename + " " + varname + "___tmp;"
330 tmp_name = "tmp_" + str(Translator.tmp_cntr)
331 Translator.tmp_cntr = Translator.tmp_cntr + 1
332 if ref:
333 text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
334 else:
335 text += prefix + "for(auto " + tmp_name + " : " + varname + ")"
336 text += prefix + "{"
337 if types[0].name in classnames:
338 if types[0].attr_type == attr_types.star:
339 text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));"
340 else:
341 text += prefix + "\t" + varname + "___tmp.append(*" + types[0].name + "::get_py_obj(&" + tmp_name + "));"
342 elif types[0].name in known_containers:
343 text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[0].attr_type == attr_types.star)
344 text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + "___tmp);"
345 else:
346 text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");"
347 text += prefix + "}"
348 return text
349
350 #Sub-type for std::set
351 class SetTranslator(PythonListTranslator):
352 insert_name = "insert"
353 orig_name = "std::set"
354
355 #Sub-type for std::vector
356 class VectorTranslator(PythonListTranslator):
357 insert_name = "push_back"
358 orig_name = "std::vector"
359
360 #Sub-type for pool
361 class PoolTranslator(PythonListTranslator):
362 insert_name = "insert"
363 orig_name = "pool"
364
365 #Translates dict-types (dict, std::map), that only differ in their name and
366 #the name of the insertion function
367 class PythonDictTranslator(Translator):
368 typename = "boost::python::dict"
369 insert_name = "Default"
370
371 @classmethod
372 def gen_type(c, types):
373 text = c.orig_name + "<"
374 if types[0].name in primitive_types:
375 text += types[0].name
376 elif types[0].name in known_containers:
377 text += known_containers[types[0].name].gen_type(types[0].cont.args)
378 else:
379 text += class_by_name(types[0].name).namespace + "::" + types[0].name
380 if types[0].attr_type == attr_types.star:
381 text += "*"
382 text += ", "
383 if types[1].name in primitive_types:
384 text += types[1].name
385 elif types[1].name in known_containers:
386 text += known_containers[types[1].name].gen_type(types[1].cont.args)
387 else:
388 text += class_by_name(types[1].name).namespace + "::" + types[1].name
389 if types[1].attr_type == attr_types.star:
390 text += "*"
391 text += ">"
392 return text
393
394 #Generate c++ code to translate from a boost::python::dict
395 @classmethod
396 def translate(c, varname, types, prefix):
397 text = prefix + c.gen_type(types) + " " + varname + "___tmp;"
398 text += prefix + "boost::python::list " + varname + "_keylist = " + varname + ".keys();"
399 cntr_name = "cntr_" + str(Translator.tmp_cntr)
400 Translator.tmp_cntr = Translator.tmp_cntr + 1
401 text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "_keylist); " + cntr_name + "++)"
402 text += prefix + "{"
403 key_tmp_name = "key_tmp_" + str(Translator.tmp_cntr)
404 val_tmp_name = "val_tmp_" + str(Translator.tmp_cntr)
405 Translator.tmp_cntr = Translator.tmp_cntr + 1
406
407 if types[0].name in known_containers:
408 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 + " ]);"
409 text += known_containers[types[0].name].translate(key_tmp_name, types[0].cont.args, prefix+"\t")
410 key_tmp_name = key_tmp_name + "___tmp"
411 elif types[0].name in classnames:
412 text += prefix + "\t" + types[0].name + "* " + key_tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "_keylist[ " + cntr_name + " ]);"
413 else:
414 text += prefix + "\t" + types[0].name + " " + key_tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "_keylist[ " + cntr_name + " ]);"
415
416 if types[1].name in known_containers:
417 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 + " ]]);"
418 text += known_containers[types[1].name].translate(val_tmp_name, types[1].cont.args, prefix+"\t")
419 val_tmp_name = val_tmp_name + "___tmp"
420 elif types[1].name in classnames:
421 text += prefix + "\t" + types[1].name + "* " + val_tmp_name + " = boost::python::extract<" + types[1].name + "*>(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);"
422 else:
423 text += prefix + "\t" + types[1].name + " " + val_tmp_name + " = boost::python::extract<" + types[1].name + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);"
424
425 text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(std::pair<" + types[0].gen_text_cpp() + ", " + types[1].gen_text_cpp() + ">("
426
427 if types[0].name not in classnames:
428 text += key_tmp_name
429 else:
430 if types[0].attr_type != attr_types.star:
431 text += "*"
432 text += key_tmp_name + "->get_cpp_obj()"
433
434 text += ", "
435 if types[1].name not in classnames:
436 text += val_tmp_name
437 else:
438 if types[1].attr_type != attr_types.star:
439 text += "*"
440 text += val_tmp_name + "->get_cpp_obj()"
441 text += "));\n" + prefix + "}"
442 return text
443
444 #Generate c++ code to translate to a boost::python::dict
445 @classmethod
446 def translate_cpp(c, varname, types, prefix, ref):
447 text = prefix + c.typename + " " + varname + "___tmp;"
448 tmp_name = "tmp_" + str(Translator.tmp_cntr)
449 Translator.tmp_cntr = Translator.tmp_cntr + 1
450 if ref:
451 text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
452 else:
453 text += prefix + "for(auto " + tmp_name + " : " + varname + ")"
454 text += prefix + "{"
455 if types[1].name in known_containers:
456 text += prefix + "\tauto " + tmp_name + "_second = " + tmp_name + ".second;"
457 text += known_containers[types[1].name].translate_cpp(tmp_name + "_second", types[1].cont.args, prefix + "\t", types[1].attr_type == attr_types.star)
458
459 if types[0].name in classnames:
460 text += prefix + "\t" + varname + "___tmp[" + types[0].name + "::get_py_obj(" + tmp_name + ".first)] = "
461 elif types[0].name not in known_containers:
462 text += prefix + "\t" + varname + "___tmp[" + tmp_name + ".first] = "
463
464 if types[1].name in classnames:
465 if types[1].attr_type == attr_types.star:
466 text += types[1].name + "::get_py_obj(" + tmp_name + ".second);"
467 else:
468 text += "*" + types[1].name + "::get_py_obj(&" + tmp_name + ".second);"
469 elif types[1].name in known_containers:
470 text += tmp_name + "_second___tmp;"
471 else:
472 text += tmp_name + ".second;"
473 text += prefix + "}"
474 return text
475
476 #Sub-type for dict
477 class DictTranslator(PythonDictTranslator):
478 insert_name = "insert"
479 orig_name = "dict"
480
481 #Sub_type for std::map
482 class MapTranslator(PythonDictTranslator):
483 insert_name = "insert"
484 orig_name = "std::map"
485
486 #Translator for std::pair. Derived from PythonDictTranslator because the
487 #gen_type function is the same (because both have two template parameters)
488 class TupleTranslator(PythonDictTranslator):
489 typename = "boost::python::tuple"
490 orig_name = "std::pair"
491
492 #Generate c++ code to translate from a boost::python::tuple
493 @classmethod
494 def translate(c, varname, types, prefix):
495 text = prefix + types[0].name + " " + varname + "___tmp_0 = boost::python::extract<" + types[0].name + ">(" + varname + "[0]);"
496 text += prefix + types[1].name + " " + varname + "___tmp_1 = boost::python::extract<" + types[1].name + ">(" + varname + "[1]);"
497 text += prefix + TupleTranslator.gen_type(types) + " " + varname + "___tmp("
498 if types[0].name.split(" ")[-1] in primitive_types:
499 text += varname + "___tmp_0, "
500 else:
501 text += varname + "___tmp_0.get_cpp_obj(), "
502 if types[1].name.split(" ")[-1] in primitive_types:
503 text += varname + "___tmp_1);"
504 else:
505 text += varname + "___tmp_1.get_cpp_obj());"
506 return text
507
508 #Generate c++ code to translate to a boost::python::tuple
509 @classmethod
510 def translate_cpp(c, varname, types, prefix, ref):
511 text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + varname + ".first, " + varname + ".second);"
512 return text
513 tmp_name = "tmp_" + str(Translator.tmp_cntr)
514 Translator.tmp_cntr = Translator.tmp_cntr + 1
515 if ref:
516 text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
517 else:
518 text += prefix + "for(auto " + tmp_name + " : " + varname + ")"
519 text += prefix + "{"
520 if types[0].name.split(" ")[-1] in primitive_types or types[0].name in enum_names:
521 text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");"
522 elif types[0].name in known_containers:
523 text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[1].attr_type == attr_types.star)
524 text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "___tmp);"
525 elif types[0].name in classnames:
526 text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));"
527 text += prefix + "}"
528 return text
529
530 #Associate the Translators with their c++ type
531 known_containers = {
532 "std::set" : SetTranslator,
533 "std::vector" : VectorTranslator,
534 "pool" : PoolTranslator,
535 "dict" : DictTranslator,
536 "std::pair" : TupleTranslator,
537 "std::map" : MapTranslator
538 }
539
540 class Attribute:
541 wtype = None
542 varname = None
543 is_const = False
544 default_value = None
545 pos = None
546 pos_counter = 0
547
548 def __init__(self, wtype, varname, is_const = False, default_value = None):
549 self.wtype = wtype
550 self.varname = varname
551 self.is_const = is_const
552 self.default_value = None
553 self.container = None
554
555 @staticmethod
556 def from_string(str_def, containing_file, line_number):
557 if len(str_def) < 3:
558 return None
559 orig = str_def
560 arg = Attribute(None, None)
561 prefix = ""
562 arg.wtype = None
563 arg.varname = None
564 arg.is_const = False
565 arg.default_value = None
566 arg.container = None
567 if str.startswith(str_def, "const "):
568 arg.is_const = True
569 str_def = str_def[6:]
570 if str.startswith(str_def, "unsigned "):
571 prefix = "unsigned "
572 str_def = str_def[9:]
573 while str.startswith(str_def, "long "):
574 prefix= "long " + prefix
575 str_def = str_def[5:]
576 while str.startswith(str_def, "short "):
577 prefix = "short " + prefix
578 str_def = str_def[6:]
579
580 if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "):
581 closing = find_closing(str_def[str_def.find("<"):], "<", ">") + str_def.find("<") + 1
582 arg.wtype = WType.from_string(str_def[:closing].strip(), containing_file, line_number)
583 str_def = str_def[closing+1:]
584 else:
585 if str_def.count(" ") > 0:
586 arg.wtype = WType.from_string(prefix + str_def[:str_def.find(" ")].strip(), containing_file, line_number)
587 str_def = str_def[str_def.find(" ")+1:]
588 else:
589 arg.wtype = WType.from_string(prefix + str_def.strip(), containing_file, line_number)
590 str_def = ""
591 arg.varname = ""
592
593 if arg.wtype == None:
594 return None
595 if str_def.count("=") == 0:
596 arg.varname = str_def.strip()
597 if arg.varname.find(" ") > 0:
598 return None
599 else:
600 arg.varname = str_def[:str_def.find("=")].strip()
601 if arg.varname.find(" ") > 0:
602 return None
603 str_def = str_def[str_def.find("=")+1:].strip()
604 arg.default_value = str_def[arg.varname.find("=")+1:].strip()
605 if len(arg.varname) == 0:
606 arg.varname = None
607 return arg
608 if arg.varname[0] == '*':
609 arg.wtype.attr_type = attr_types.star
610 arg.varname = arg.varname[1:]
611 elif arg.varname[0] == '&':
612 if arg.wtype.attr_type != attr_types.default:
613 return None
614 if arg.varname[1] == '&':
615 arg.wtype.attr_type = attr_types.ampamp
616 arg.varname = arg.varname[2:]
617 else:
618 arg.wtype.attr_type = attr_types.amp
619 arg.varname = arg.varname[1:]
620 return arg
621
622 #Generates the varname. If the attribute has no name in the header file,
623 #a name is generated
624 def gen_varname(self):
625 if self.varname != None:
626 return self.varname
627 if self.wtype.name == "void":
628 return ""
629 if self.pos == None:
630 self.pos = Attribute.pos_counter
631 Attribute.pos_counter = Attribute.pos_counter + 1
632 return "gen_varname_" + str(self.pos)
633
634 #Generates the text for the function headers with wrapper types
635 def gen_listitem(self):
636 prefix = ""
637 if self.is_const:
638 prefix = "const "
639 if self.wtype.name in classnames:
640 return prefix + self.wtype.name + "* " + self.gen_varname()
641 if self.wtype.name in known_containers:
642 return prefix + known_containers[self.wtype.name].typename + " " + self.gen_varname()
643 return prefix + self.wtype.name + " " + self.gen_varname()
644
645 #Generates the test for the function headers with c++ types
646 def gen_listitem_cpp(self):
647 prefix = ""
648 if self.is_const:
649 prefix = "const "
650 infix = ""
651 if self.wtype.attr_type == attr_types.star:
652 infix = "*"
653 elif self.wtype.attr_type == attr_types.amp:
654 infix = "&"
655 elif self.wtype.attr_type == attr_types.ampamp:
656 infix = "&&"
657 if self.wtype.name in known_containers:
658 return prefix + known_containers[self.wtype.name].gen_type(self.wtype.cont.args) + " " + infix + self.gen_varname()
659 if self.wtype.name in classnames:
660 return prefix + class_by_name(self.wtype.name).namespace + "::" + self.wtype.name + " " + infix + self.gen_varname()
661 return prefix + self.wtype.name + " " + infix + self.gen_varname()
662
663 #Generates the listitem withtout the varname, so the signature can be
664 #compared
665 def gen_listitem_hash(self):
666 prefix = ""
667 if self.is_const:
668 prefix = "const "
669 if self.wtype.name in classnames:
670 return prefix + self.wtype.name + "* "
671 if self.wtype.name in known_containers:
672 return known_containers[self.wtype.name].typename
673 return prefix + self.wtype.name
674
675 #Generate Translation code for the attribute
676 def gen_translation(self):
677 if self.wtype.name in known_containers:
678 return known_containers[self.wtype.name].translate(self.gen_varname(), self.wtype.cont.args, "\n\t\t")
679 return ""
680
681 #Generate Translation code from c++ for the attribute
682 def gen_translation_cpp(self):
683 if self.wtype.name in known_containers:
684 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)
685 return ""
686
687 #Generate Text for the call
688 def gen_call(self):
689 ret = self.gen_varname()
690 if self.wtype.name in known_containers:
691 if self.wtype.attr_type == attr_types.star:
692 return "&" + ret + "___tmp"
693 return ret + "___tmp"
694 if self.wtype.name in classnames:
695 if self.wtype.attr_type != attr_types.star:
696 ret = "*" + ret
697 return ret + "->get_cpp_obj()"
698 if self.wtype.name == "char *" and self.gen_varname() in ["format", "fmt"]:
699 return "\"%s\", " + self.gen_varname()
700 if self.wtype.attr_type == attr_types.star:
701 return "&" + ret
702 return ret
703
704 def gen_call_cpp(self):
705 ret = self.gen_varname()
706 if self.wtype.name.split(" ")[-1] in primitive_types or self.wtype.name in enum_names:
707 if self.wtype.attr_type == attr_types.star:
708 return "&" + ret
709 return ret
710 if self.wtype.name not in classnames:
711 if self.wtype.attr_type == attr_types.star:
712 return "&" + ret + "___tmp"
713 return ret + "___tmp"
714 if self.wtype.attr_type != attr_types.star:
715 ret = "*" + ret
716 return self.wtype.name + "::get_py_obj(" + self.gen_varname() + ")"
717
718 #Generate cleanup code
719 def gen_cleanup(self):
720 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):
721 return ""
722 return "\n\t\tdelete " + self.gen_varname() + "___tmp;"
723
724 class WClass:
725 name = None
726 namespace = None
727 link_type = None
728 id_ = None
729 string_id = None
730 hash_id = None
731 needs_clone = False
732 found_funs = []
733 found_vars = []
734 found_constrs = []
735
736 def __init__(self, name, link_type, id_, string_id = None, hash_id = None, needs_clone = False):
737 self.name = name
738 self.namespace = None
739 self.link_type = link_type
740 self.id_ = id_
741 self.string_id = string_id
742 self.hash_id = hash_id
743 self.needs_clone = needs_clone
744 self.found_funs = []
745 self.found_vars = []
746 self.found_constrs = []
747
748 def printable_constrs(self):
749 ret = 0
750 for con in self.found_constrs:
751 if not con.protected:
752 ret += 1
753 return ret
754
755 def gen_decl(self, filename):
756 long_name = self.namespace + "::" + self.name
757
758 text = "\n\t// WRAPPED from " + filename
759 text += "\n\tstruct " + self.name
760 if self.link_type == link_types.derive:
761 text += " : public " + self.namespace + "::" + self.name
762 text += "\n\t{\n"
763
764 if self.link_type != link_types.derive:
765
766 text += "\t\t" + long_name + "* ref_obj;\n"
767
768 if self.link_type == link_types.ref_copy or self.link_type == link_types.pointer:
769 text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n"
770 elif self.link_type == link_types.global_list:
771 text += "\t\t" + self.id_.wtype.name + " " + self.id_.varname + ";\n"
772 text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{"
773 text += "\n\t\t\t" + long_name + "* ret = " + long_name + "::get_all_" + self.name.lower() + "s()->at(this->" + self.id_.varname + ");"
774 text += "\n\t\t\tif(ret != NULL && ret == this->ref_obj)"
775 text += "\n\t\t\t\treturn ret;"
776 text += "\n\t\t\tthrow std::runtime_error(\"" + self.name + "'s c++ object does not exist anymore.\");"
777 text += "\n\t\t\treturn NULL;"
778 text += "\n\t\t}\n"
779
780 #if self.link_type != link_types.pointer:
781 text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{"
782 text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));"
783 if self.link_type == link_types.pointer:
784 text += "\n\t\t\tret->ref_obj = ref;"
785 if self.link_type == link_types.ref_copy:
786 if self.needs_clone:
787 text += "\n\t\t\tret->ref_obj = ref->clone();"
788 else:
789 text += "\n\t\t\tret->ref_obj = new "+long_name+"(*ref);"
790 if self.link_type == link_types.global_list:
791 text += "\n\t\t\tret->ref_obj = ref;"
792 text += "\n\t\t\tret->" + self.id_.varname + " = ret->ref_obj->" + self.id_.varname + ";"
793 text += "\n\t\t\treturn ret;"
794 text += "\n\t\t}\n"
795
796 if self.link_type == link_types.ref_copy:
797 text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + " ref)\n\t\t{"
798 text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));"
799 if self.needs_clone:
800 text += "\n\t\t\tret->ref_obj = ref.clone();"
801 else:
802 text += "\n\t\t\tret->ref_obj = new "+long_name+"(ref);"
803 text += "\n\t\t\treturn ret;"
804 text += "\n\t\t}\n"
805
806 for con in self.found_constrs:
807 text += con.gen_decl()
808 for var in self.found_vars:
809 text += var.gen_decl()
810 for fun in self.found_funs:
811 text += fun.gen_decl()
812
813
814 if self.link_type == link_types.derive:
815 duplicates = {}
816 for fun in self.found_funs:
817 if fun.name in duplicates:
818 fun.gen_alias()
819 duplicates[fun.name].gen_alias()
820 else:
821 duplicates[fun.name] = fun
822
823 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"
824 text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{"
825 text += "\n\t\t\treturn (" + self.name + "*)ref;"
826 text += "\n\t\t}\n"
827
828 for con in self.found_constrs:
829 text += con.gen_decl_derive()
830 for var in self.found_vars:
831 text += var.gen_decl()
832 for fun in self.found_funs:
833 text += fun.gen_decl_virtual()
834
835 if self.hash_id != None:
836 text += "\n\t\tunsigned int get_hash_py()"
837 text += "\n\t\t{"
838 text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";"
839 text += "\n\t\t}"
840
841 text += "\n\t};\n"
842
843 if self.link_type == link_types.derive:
844 text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">"
845 text += "\n\t{"
846
847 for con in self.found_constrs:
848 text += con.gen_decl_wrapperclass()
849 for fun in self.found_funs:
850 text += fun.gen_default_impl()
851
852 text += "\n\t};"
853
854 text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)"
855 text += "\n\t{"
856 text += "\n\t\tostr << \"" + self.name
857 if self.string_id != None:
858 text +=" \\\"\""
859 text += " << ref.get_cpp_obj()->" + self.string_id
860 text += " << \"\\\"\""
861 else:
862 text += " at \" << ref.get_cpp_obj()"
863 text += ";"
864 text += "\n\t\treturn ostr;"
865 text += "\n\t}"
866 text += "\n"
867
868 return text
869
870 def gen_funs(self, filename):
871 text = ""
872 if self.link_type != link_types.derive:
873 for con in self.found_constrs:
874 text += con.gen_def()
875 for var in self.found_vars:
876 text += var.gen_def()
877 for fun in self.found_funs:
878 text += fun.gen_def()
879 else:
880 for var in self.found_vars:
881 text += var.gen_def()
882 for fun in self.found_funs:
883 text += fun.gen_def_virtual()
884 return text
885
886 def gen_boost_py(self):
887 text = "\n\t\tclass_<" + self.name
888 if self.link_type == link_types.derive:
889 text += "Wrap, boost::noncopyable"
890 text += ">(\"" + self.name + "\""
891 if self.printable_constrs() == 0 or not self.contains_default_constr():
892 text += ", no_init"
893 text += ")"
894 text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))"
895 text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))"
896 for con in self.found_constrs:
897 text += con.gen_boost_py()
898 for var in self.found_vars:
899 text += var.gen_boost_py()
900 static_funs = []
901 for fun in self.found_funs:
902 text += fun.gen_boost_py()
903 if fun.is_static and fun.alias not in static_funs:
904 static_funs.append(fun.alias)
905 for fun in static_funs:
906 text += "\n\t\t\t.staticmethod(\"" + fun + "\")"
907
908 if self.hash_id != None:
909 text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)"
910 text += "\n\t\t\t;\n"
911 return text
912
913 def contains_default_constr(self):
914 for c in self.found_constrs:
915 if len(c.args) == 0:
916 return True
917 return False
918
919 #CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE
920
921 sources = [
922 Source("kernel/celltypes",[
923 WClass("CellType", link_types.pointer, None, None, "type.hash()", True),
924 WClass("CellTypes", link_types.pointer, None, None, None, True)
925 ]
926 ),
927 Source("kernel/consteval",[
928 WClass("ConstEval", link_types.pointer, None, None, None, True)
929 ]
930 ),
931 Source("kernel/log",[]),
932 Source("kernel/register",[
933 WClass("Pass", link_types.derive, None, None, None, True),
934 ]
935 ),
936 Source("kernel/rtlil",[
937 WClass("IdString", link_types.ref_copy, None, "str()", "hash()"),
938 WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"),
939 WClass("AttrObject", link_types.ref_copy, None, None, None),
940 WClass("Selection", link_types.ref_copy, None, None, None),
941 WClass("Monitor", link_types.derive, None, None, None),
942 WClass("CaseRule",link_types.ref_copy, None, None, None, True),
943 WClass("SwitchRule",link_types.ref_copy, None, None, None, True),
944 WClass("SyncRule", link_types.ref_copy, None, None, None, True),
945 WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"),
946 WClass("SigChunk", link_types.ref_copy, None, None, None),
947 WClass("SigBit", link_types.ref_copy, None, None, "hash()"),
948 WClass("SigSpec", link_types.ref_copy, None, None, "hash()"),
949 WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
950 WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
951 WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
952 WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
953 WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()")
954 ]
955 ),
956 #Source("kernel/satgen",[
957 # ]
958 # ),
959 #Source("libs/ezsat/ezsat",[
960 # ]
961 # ),
962 #Source("libs/ezsat/ezminisat",[
963 # ]
964 # ),
965 Source("kernel/sigtools",[
966 WClass("SigMap", link_types.pointer, None, None, None, True)
967 ]
968 ),
969 Source("kernel/yosys",[
970 ]
971 ),
972 Source("kernel/cost",[])
973 ]
974
975 blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow", "YOSYS_NAMESPACE::Module::Bu0", "YOSYS_NAMESPACE::CaseRule::optimize"]
976
977 enum_names = ["State","SyncType","ConstFlags"]
978
979 enums = [] #Do not edit
980
981 unowned_functions = []
982
983 classnames = []
984 for source in sources:
985 for wclass in source.classes:
986 classnames.append(wclass.name)
987
988 def class_by_name(name):
989 for source in sources:
990 for wclass in source.classes:
991 if wclass.name == name:
992 return wclass
993 return None
994
995 def enum_by_name(name):
996 for e in enums:
997 if e.name == name:
998 return e
999 return None
1000
1001 def find_closing(text, open_tok, close_tok):
1002 if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok):
1003 return text.find(close_tok)
1004 return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1
1005
1006 def unpretty_string(s):
1007 s = s.strip()
1008 while s.find(" ") != -1:
1009 s = s.replace(" "," ")
1010 while s.find("\t") != -1:
1011 s = s.replace("\t"," ")
1012 s = s.replace(" (","(")
1013 return s
1014
1015 class WEnum:
1016 name = None
1017 namespace = None
1018 values = []
1019
1020 def from_string(str_def, namespace, line_number):
1021 str_def = str_def.strip()
1022 if not str.startswith(str_def, "enum "):
1023 return None
1024 if str_def.count(";") != 1:
1025 return None
1026 str_def = str_def[5:]
1027 enum = WEnum()
1028 split = str_def.split(":")
1029 if(len(split) != 2):
1030 return None
1031 enum.name = split[0].strip()
1032 if enum.name not in enum_names:
1033 return None
1034 str_def = split[1]
1035 if str_def.count("{") != str_def.count("}") != 1:
1036 return None
1037 if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';':
1038 return None
1039 str_def = str_def.split("{")[-1].split("}")[0]
1040 enum.values = []
1041 for val in str_def.split(','):
1042 enum.values.append(val.strip().split('=')[0].strip())
1043 enum.namespace = namespace
1044 return enum
1045
1046 def gen_boost_py(self):
1047 text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n"
1048 for value in self.values:
1049 text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n"
1050 text += "\t\t\t;\n"
1051 return text
1052
1053 def __str__(self):
1054 ret = "Enum " + self.namespace + "::" + self.name + "(\n"
1055 for val in self.values:
1056 ret = ret + "\t" + val + "\n"
1057 return ret + ")"
1058
1059 def __repr__(self):
1060 return __str__(self)
1061
1062 class WConstructor:
1063 orig_text = None
1064 args = []
1065 containing_file = None
1066 member_of = None
1067 duplicate = False
1068 protected = False
1069
1070 def __init__(self, containing_file, class_):
1071 self.orig_text = "Auto generated default constructor"
1072 self.args = []
1073 self.containing_file = containing_file
1074 self.member_of = class_
1075 self.protected = False
1076
1077 def from_string(str_def, containing_file, class_, line_number, protected = False):
1078 if class_ == None:
1079 return None
1080 if str_def.count("delete;") > 0:
1081 return None
1082 con = WConstructor(containing_file, class_)
1083 con.orig_text = str_def
1084 con.args = []
1085 con.duplicate = False
1086 con.protected = protected
1087 if not str.startswith(str_def, class_.name + "("):
1088 return None
1089 str_def = str_def[len(class_.name)+1:]
1090 found = find_closing(str_def, "(", ")")
1091 if found == -1:
1092 return None
1093 str_def = str_def[0:found].strip()
1094 if len(str_def) == 0:
1095 return con
1096 for arg in split_list(str_def, ","):
1097 parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
1098 if parsed == None:
1099 return None
1100 con.args.append(parsed)
1101 return con
1102
1103 def gen_decl(self):
1104 if self.duplicate or self.protected:
1105 return ""
1106 text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1107 text += "\n\t\t" + self.member_of.name + "("
1108 for arg in self.args:
1109 text += arg.gen_listitem() + ", "
1110 if len(self.args) > 0:
1111 text = text[:-2]
1112 text += ");\n"
1113 return text
1114
1115 def gen_decl_derive(self):
1116 if self.duplicate or self.protected:
1117 return ""
1118 text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1119 text += "\n\t\t" + self.member_of.name + "("
1120 for arg in self.args:
1121 text += arg.gen_listitem() + ", "
1122 if len(self.args) > 0:
1123 text = text[:-2]
1124 text += ")"
1125 if len(self.args) == 0:
1126 return text + "{}"
1127 text += " : "
1128 text += self.member_of.namespace + "::" + self.member_of.name + "("
1129 for arg in self.args:
1130 text += arg.gen_call() + ", "
1131 if len(self.args) > 0:
1132 text = text[:-2]
1133 text += "){}\n"
1134 return text
1135
1136 def gen_decl_wrapperclass(self):
1137 if self.duplicate or self.protected:
1138 return ""
1139 text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1140 text += "\n\t\t" + self.member_of.name + "Wrap("
1141 for arg in self.args:
1142 text += arg.gen_listitem() + ", "
1143 if len(self.args) > 0:
1144 text = text[:-2]
1145 text += ")"
1146 if len(self.args) == 0:
1147 return text + "{}"
1148 text += " : "
1149 text += self.member_of.name + "("
1150 for arg in self.args:
1151 text += arg.gen_call() + ", "
1152 if len(self.args) > 0:
1153 text = text[:-2]
1154 text += "){}\n"
1155 return text
1156
1157 def gen_decl_hash_py(self):
1158 text = self.member_of.name + "("
1159 for arg in self.args:
1160 text += arg.gen_listitem_hash() + ", "
1161 if len(self.args) > 0:
1162 text = text[:-2]
1163 text += ");"
1164 return text
1165
1166 def gen_def(self):
1167 if self.duplicate or self.protected:
1168 return ""
1169 text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1170 text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "("
1171 for arg in self.args:
1172 text += arg.gen_listitem() + ", "
1173 if len(self.args) > 0:
1174 text = text[:-2]
1175 text +=")\n\t{"
1176 for arg in self.args:
1177 text += arg.gen_translation()
1178 if self.member_of.link_type != link_types.derive:
1179 text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "("
1180 for arg in self.args:
1181 text += arg.gen_call() + ", "
1182 if len(self.args) > 0:
1183 text = text[:-2]
1184 if self.member_of.link_type != link_types.derive:
1185 text += ");"
1186 if self.member_of.link_type == link_types.global_list:
1187 text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";"
1188 for arg in self.args:
1189 text += arg.gen_cleanup()
1190 text += "\n\t}\n"
1191 return text
1192
1193 def gen_boost_py(self):
1194 if self.duplicate or self.protected or len(self.args) == 0:
1195 return ""
1196 text = "\n\t\t\t.def(init"
1197 text += "<"
1198 for a in self.args:
1199 text += a.gen_listitem_hash() + ", "
1200 text = text[0:-2] + ">())"
1201 return text
1202
1203 class WFunction:
1204 orig_text = None
1205 is_static = False
1206 is_inline = False
1207 is_virtual = False
1208 ret_attr_type = attr_types.default
1209 is_operator = False
1210 ret_type = None
1211 name = None
1212 alias = None
1213 args = []
1214 containing_file = None
1215 member_of = None
1216 duplicate = False
1217 namespace = ""
1218
1219 def from_string(str_def, containing_file, class_, line_number, namespace):
1220 if str_def.count("delete;") > 0:
1221 return None
1222 func = WFunction()
1223 func.is_static = False
1224 func.is_inline = False
1225 func.is_virtual = False
1226 func.ret_attr_type = attr_types.default
1227 func.is_operator = False
1228 func.member_of = None
1229 func.orig_text = str_def
1230 func.args = []
1231 func.containing_file = containing_file
1232 func.member_of = class_
1233 func.duplicate = False
1234 func.namespace = namespace
1235 str_def = str_def.replace("operator ","operator")
1236 if str.startswith(str_def, "static "):
1237 func.is_static = True
1238 str_def = str_def[7:]
1239 else:
1240 func.is_static = False
1241 if str.startswith(str_def, "inline "):
1242 func.is_inline = True
1243 str_def = str_def[7:]
1244 else:
1245 func.is_inline = False
1246 if str.startswith(str_def, "virtual "):
1247 func.is_virtual = True
1248 str_def = str_def[8:]
1249 else:
1250 func.is_virtual = False
1251
1252 if str_def.count(" ") == 0:
1253 return None
1254
1255 parts = split_list(str_def.strip(), " ")
1256
1257 prefix = ""
1258 i = 0
1259 for part in parts:
1260 if part in ["unsigned", "long", "short"]:
1261 prefix += part + " "
1262 i += 1
1263 else:
1264 break
1265 parts = parts[i:]
1266
1267 if len(parts) <= 1:
1268 return None
1269
1270 func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number)
1271
1272 if func.ret_type == None:
1273 return None
1274
1275 str_def = parts[1]
1276 for part in parts[2:]:
1277 str_def = str_def + " " + part
1278
1279 found = str_def.find("(")
1280 if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")):
1281 return None
1282 func.name = str_def[:found]
1283 str_def = str_def[found:]
1284 if func.name.find("operator") != -1 and str.startswith(str_def, "()("):
1285 func.name += "()"
1286 str_def = str_def[2:]
1287 str_def = str_def[1:]
1288 if func.name.find("operator") != -1:
1289 func.is_operator = True
1290 if func.name.find("*") == 0:
1291 func.name = func.name.replace("*", "")
1292 func.ret_type.attr_type = attr_types.star
1293 if func.name.find("&&") == 0:
1294 func.name = func.name.replace("&&", "")
1295 func.ret_type.attr_type = attr_types.ampamp
1296 if func.name.find("&") == 0:
1297 func.name = func.name.replace("&", "")
1298 func.ret_type.attr_type = attr_types.amp
1299
1300 found = find_closing(str_def, "(", ")")
1301 if found == -1:
1302 return None
1303 str_def = str_def[0:found]
1304 if func.name in blacklist_methods:
1305 return None
1306 if func.namespace != None and func.namespace != "":
1307 if (func.namespace + "::" + func.name) in blacklist_methods:
1308 return None
1309 if func.member_of != None:
1310 if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods:
1311 return None
1312 if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators:
1313 return None
1314
1315 testname = func.name
1316 if func.is_operator:
1317 testname = testname[:testname.find("operator")]
1318 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:
1319 return None
1320
1321 func.alias = func.name
1322 if func.name in keyword_aliases:
1323 func.alias = keyword_aliases[func.name]
1324 str_def = str_def[:found].strip()
1325 if(len(str_def) == 0):
1326 return func
1327 for arg in split_list(str_def, ","):
1328 if arg.strip() == "...":
1329 continue
1330 parsed = Attribute.from_string(arg.strip(), containing_file, line_number)
1331 if parsed == None:
1332 return None
1333 func.args.append(parsed)
1334 return func
1335
1336 def gen_alias(self):
1337 self.alias = self.name
1338 for arg in self.args:
1339 self.alias += "__" + arg.wtype.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","")
1340
1341 def gen_decl(self):
1342 if self.duplicate:
1343 return ""
1344 text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1345 text += "\n\t\t"
1346 if self.is_static:
1347 text += "static "
1348 text += self.ret_type.gen_text() + " " + self.alias + "("
1349 for arg in self.args:
1350 text += arg.gen_listitem()
1351 text += ", "
1352 if len(self.args) > 0:
1353 text = text[:-2]
1354 text += ");\n"
1355 return text
1356
1357 def gen_decl_virtual(self):
1358 if self.duplicate:
1359 return ""
1360 if not self.is_virtual:
1361 return self.gen_decl()
1362 text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1363 text += "\n\t\tvirtual "
1364 if self.is_static:
1365 text += "static "
1366 text += self.ret_type.gen_text() + " py_" + self.alias + "("
1367 for arg in self.args:
1368 text += arg.gen_listitem()
1369 text += ", "
1370 if len(self.args) > 0:
1371 text = text[:-2]
1372 text += ")"
1373 if len(self.args) == 0:
1374 text += "{}"
1375 else:
1376 text += "\n\t\t{"
1377 for arg in self.args:
1378 text += "\n\t\t\t(void)" + arg.gen_varname() + ";"
1379 text += "\n\t\t}\n"
1380 text += "\n\t\tvirtual "
1381 if self.is_static:
1382 text += "static "
1383 text += self.ret_type.gen_text() + " " + self.name + "("
1384 for arg in self.args:
1385 text += arg.gen_listitem_cpp()
1386 text += ", "
1387 if len(self.args) > 0:
1388 text = text[:-2]
1389 text += ") YS_OVERRIDE;\n"
1390 return text
1391
1392 def gen_decl_hash_py(self):
1393 text = self.ret_type.gen_text() + " " + self.alias + "("
1394 for arg in self.args:
1395 text += arg.gen_listitem_hash() + ", "
1396 if len(self.args) > 0:
1397 text = text[:-2]
1398 text += ");"
1399 return text
1400
1401 def gen_def(self):
1402 if self.duplicate:
1403 return ""
1404 text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1405 text += "\n\t" + self.ret_type.gen_text() + " "
1406 if self.member_of != None:
1407 text += self.member_of.name + "::"
1408 text += self.alias + "("
1409 for arg in self.args:
1410 text += arg.gen_listitem()
1411 text += ", "
1412 if len(self.args) > 0:
1413 text = text[:-2]
1414 text +=")\n\t{"
1415 for arg in self.args:
1416 text += arg.gen_translation()
1417 text += "\n\t\t"
1418 if self.ret_type.name != "void":
1419 if self.ret_type.name in known_containers:
1420 text += self.ret_type.gen_text_cpp()
1421 else:
1422 text += self.ret_type.gen_text()
1423 if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star):
1424 text += "*"
1425 text += " ret_ = "
1426 if self.ret_type.name in classnames:
1427 text += self.ret_type.name + "::get_py_obj("
1428 if self.member_of == None:
1429 text += "::" + self.namespace + "::" + self.alias + "("
1430 elif self.is_static:
1431 text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "("
1432 else:
1433 text += "this->get_cpp_obj()->" + self.name + "("
1434 for arg in self.args:
1435 text += arg.gen_call() + ", "
1436 if len(self.args) > 0:
1437 text = text[:-2]
1438 if self.ret_type.name in classnames:
1439 text += ")"
1440 text += ");"
1441 for arg in self.args:
1442 text += arg.gen_cleanup()
1443 if self.ret_type.name != "void":
1444 if self.ret_type.name in classnames:
1445 text += "\n\t\treturn *ret_;"
1446 elif self.ret_type.name in known_containers:
1447 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)
1448 text += "\n\t\treturn ret____tmp;"
1449 else:
1450 text += "\n\t\treturn ret_;"
1451 text += "\n\t}\n"
1452 return text
1453
1454 def gen_def_virtual(self):
1455 if self.duplicate:
1456 return ""
1457 if not self.is_virtual:
1458 return self.gen_def()
1459 text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file
1460 text += "\n\t"
1461 if self.is_static:
1462 text += "static "
1463 text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "("
1464 for arg in self.args:
1465 text += arg.gen_listitem_cpp()
1466 text += ", "
1467 if len(self.args) > 0:
1468 text = text[:-2]
1469 text += ")\n\t{"
1470 for arg in self.args:
1471 text += arg.gen_translation_cpp()
1472 text += "\n\t\t"
1473 if self.member_of == None:
1474 text += "::" + self.namespace + "::" + self.alias + "("
1475 elif self.is_static:
1476 text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "("
1477 else:
1478 text += "py_" + self.alias + "("
1479 for arg in self.args:
1480 text += arg.gen_call_cpp() + ", "
1481 if len(self.args) > 0:
1482 text = text[:-2]
1483 if self.ret_type.name in classnames:
1484 text += ")"
1485 text += ");"
1486 for arg in self.args:
1487 text += arg.gen_cleanup()
1488 text += "\n\t}\n"
1489 return text
1490
1491 def gen_default_impl(self):
1492 if self.duplicate:
1493 return ""
1494 if not self.is_virtual:
1495 return ""
1496 text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "("
1497 for arg in self.args:
1498 text += arg.gen_listitem() + ", "
1499 if len(self.args) > 0:
1500 text = text[:-2]
1501
1502 call_string = "py_" + self.alias + "("
1503 for arg in self.args:
1504 call_string += arg.gen_varname() + ", "
1505 if len(self.args) > 0:
1506 call_string = call_string[0:-2]
1507 call_string += ");"
1508
1509 text += ")\n\t\t{"
1510 text += "\n\t\t\tif(boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))"
1511 text += "\n\t\t\t\t" + call_string
1512 text += "\n\t\t\telse"
1513 text += "\n\t\t\t\t" + self.member_of.name + "::" + call_string
1514 text += "\n\t\t}"
1515
1516 text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "("
1517 for arg in self.args:
1518 text += arg.gen_listitem() + ", "
1519 if len(self.args) > 0:
1520 text = text[:-2]
1521 text += ")\n\t\t{"
1522 text += "\n\t\t\tthis->" + self.member_of.name + "::" + call_string
1523 text += "\n\t\t}"
1524 return text
1525
1526
1527 def gen_boost_py(self):
1528 if self.duplicate:
1529 return ""
1530 if self.member_of == None:
1531 text = "\n\t\tdef"
1532 else:
1533 text = "\n\t\t\t.def"
1534 if len(self.args) > -1:
1535 if self.ret_type.name in known_containers:
1536 text += "<" + known_containers[self.ret_type.name].typename + " "
1537 else:
1538 text += "<" + self.ret_type.name + " "
1539 if self.member_of == None or self.is_static:
1540 text += "(*)("
1541 else:
1542 text += "(" + self.member_of.name + "::*)("
1543 for a in self.args:
1544 text += a.gen_listitem_hash() + ", "
1545 if len(self.args) > 0:
1546 text = text[0:-2] + ")>"
1547 else:
1548 text += "void)>"
1549
1550 if self.is_operator:
1551 text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\""
1552 else:
1553 if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual:
1554 text += "(\"py_" + self.alias + "\""
1555 else:
1556 text += "(\"" + self.alias + "\""
1557 if self.member_of != None:
1558 text += ", &" + self.member_of.name + "::"
1559 if self.member_of.link_type == link_types.derive and self.is_virtual:
1560 text += "py_" + self.alias
1561 text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias
1562 else:
1563 text += self.alias
1564
1565 text += ")"
1566 else:
1567 text += ", " + "YOSYS_PYTHON::" + self.alias + ");"
1568 return text
1569
1570 class WMember:
1571 orig_text = None
1572 wtype = attr_types.default
1573 name = None
1574 containing_file = None
1575 member_of = None
1576 namespace = ""
1577 is_const = False
1578
1579 def from_string(str_def, containing_file, class_, line_number, namespace):
1580 member = WMember()
1581 member.orig_text = str_def
1582 member.wtype = None
1583 member.name = ""
1584 member.containing_file = containing_file
1585 member.member_of = class_
1586 member.namespace = namespace
1587 member.is_const = False
1588
1589 if str.startswith(str_def, "const "):
1590 member.is_const = True
1591 str_def = str_def[6:]
1592
1593 if str_def.count(" ") == 0:
1594 return None
1595
1596 parts = split_list(str_def.strip(), " ")
1597
1598 prefix = ""
1599 i = 0
1600 for part in parts:
1601 if part in ["unsigned", "long", "short"]:
1602 prefix += part + " "
1603 i += 1
1604 else:
1605 break
1606 parts = parts[i:]
1607
1608 if len(parts) <= 1:
1609 return None
1610
1611 member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number)
1612
1613 if member.wtype == None:
1614 return None
1615
1616 str_def = parts[1]
1617 for part in parts[2:]:
1618 str_def = str_def + " " + part
1619
1620 if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1:
1621 return None
1622
1623 found = str_def.find(";")
1624 if found == -1:
1625 return None
1626
1627 found_eq = str_def.find("=")
1628 if found_eq != -1:
1629 found = found_eq
1630
1631 member.name = str_def[:found]
1632 str_def = str_def[found+1:]
1633 if member.name.find("*") == 0:
1634 member.name = member.name.replace("*", "")
1635 member.wtype.attr_type = attr_types.star
1636 if member.name.find("&&") == 0:
1637 member.name = member.name.replace("&&", "")
1638 member.wtype.attr_type = attr_types.ampamp
1639 if member.name.find("&") == 0:
1640 member.name = member.name.replace("&", "")
1641 member.wtype.attr_type = attr_types.amp
1642
1643 if(len(str_def.strip()) != 0):
1644 return None
1645
1646 if len(member.name.split(",")) > 1:
1647 member_list = []
1648 for name in member.name.split(","):
1649 name = name.strip();
1650 member_list.append(WMember())
1651 member_list[-1].orig_text = member.orig_text
1652 member_list[-1].wtype = member.wtype
1653 member_list[-1].name = name
1654 member_list[-1].containing_file = member.containing_file
1655 member_list[-1].member_of = member.member_of
1656 member_list[-1].namespace = member.namespace
1657 member_list[-1].is_const = member.is_const
1658 return member_list
1659
1660 return member
1661
1662 def gen_decl(self):
1663 text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n"
1664 if self.is_const:
1665 return text
1666 if self.wtype.name in classnames:
1667 text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n"
1668 else:
1669 text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n"
1670 return text
1671
1672 def gen_def(self):
1673 text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()"
1674 text += "\n\t{\n\t\t"
1675 if self.wtype.attr_type == attr_types.star:
1676 text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t"
1677 text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t"
1678 if self.wtype.name in known_containers:
1679 text += self.wtype.gen_text_cpp()
1680 else:
1681 text += self.wtype.gen_text()
1682
1683 if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star):
1684 text += "*"
1685 text += " ret_ = "
1686 if self.wtype.name in classnames:
1687 text += self.wtype.name + "::get_py_obj("
1688 if self.wtype.attr_type != attr_types.star:
1689 text += "&"
1690 text += "this->get_cpp_obj()->" + self.name
1691 if self.wtype.name in classnames:
1692 text += ")"
1693 text += ";"
1694
1695 if self.wtype.name in classnames:
1696 text += "\n\t\treturn *ret_;"
1697 elif self.wtype.name in known_containers:
1698 text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star)
1699 text += "\n\t\treturn ret____tmp;"
1700 else:
1701 text += "\n\t\treturn ret_;"
1702 text += "\n\t}\n"
1703
1704 if self.is_const:
1705 return text
1706
1707 ret = Attribute(self.wtype, "rhs");
1708
1709 if self.wtype.name in classnames:
1710 text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)"
1711 else:
1712 text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)"
1713 text += "\n\t{"
1714 text += ret.gen_translation()
1715 text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";"
1716 text += "\n\t}\n"
1717
1718 return text;
1719
1720 def gen_boost_py(self):
1721 text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name
1722 if not self.is_const:
1723 text += ", &" + self.member_of.name + "::set_var_py_" + self.name
1724 text += ")"
1725 return text
1726
1727 def concat_namespace(tuple_list):
1728 if len(tuple_list) == 0:
1729 return ""
1730 ret = ""
1731 for namespace in tuple_list:
1732 ret += "::" + namespace[0]
1733 return ret[2:]
1734
1735 def calc_ident(text):
1736 if len(text) == 0 or text[0] != ' ':
1737 return 0
1738 return calc_ident(text[1:]) + 1
1739
1740 def assure_length(text, length, left = False):
1741 if len(text) > length:
1742 return text[:length]
1743 if left:
1744 return text + " "*(length - len(text))
1745 return " "*(length - len(text)) + text
1746
1747 def parse_header(source):
1748 debug("Parsing " + source.name + ".pyh",1)
1749 source_file = open(source.name + ".pyh", "r")
1750
1751 source_text = []
1752 in_line = source_file.readline()
1753
1754 namespaces = []
1755
1756 while(in_line):
1757 if(len(in_line)>1):
1758 source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p "))
1759 in_line = source_file.readline()
1760
1761 i = 0
1762
1763 namespaces = []
1764 class_ = None
1765 private_segment = False
1766
1767 while i < len(source_text):
1768 line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
1769 ugly_line = unpretty_string(line)
1770
1771 if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1:
1772 namespace_name = ugly_line[10:].replace("{","").strip()
1773 namespaces.append((namespace_name, ugly_line.count("{")))
1774 debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3)
1775 i += 1
1776 continue
1777
1778 if len(namespaces) != 0:
1779 namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}"))
1780 if namespaces[-1][1] == 0:
1781 debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
1782 del namespaces[-1]
1783 i += 1
1784 continue
1785
1786 if class_ == None and (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0:
1787
1788 struct_name = ugly_line.split(" ")[1].split("::")[-1]
1789 impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1]
1790 complete_namespace = concat_namespace(namespaces)
1791 for namespace in impl_namespaces:
1792 complete_namespace += "::" + namespace
1793 debug("\tFound " + struct_name + " in " + complete_namespace,2)
1794 class_ = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line))
1795 if struct_name in classnames:
1796 class_[0].namespace = complete_namespace
1797 i += 1
1798 continue
1799
1800 if class_ != None:
1801 class_ = (class_[0], class_[1] + ugly_line.count("{") - ugly_line.count("}"))
1802 if class_[1] == 0:
1803 if class_[0] == None:
1804 debug("\tExiting unknown class", 3)
1805 else:
1806 debug("\tExiting class " + class_[0].name, 3)
1807 class_ = None
1808 private_segment = False
1809 i += 1
1810 continue
1811
1812 if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1):
1813 private_segment = True
1814 i += 1
1815 continue
1816 if class_ != None and line.find("public:") != -1:
1817 private_segment = False
1818 i += 1
1819 continue
1820
1821 candidate = None
1822
1823 if private_segment and class_ != None and class_[0] != None:
1824 candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True)
1825 if candidate != None:
1826 debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
1827 class_[0].found_constrs.append(candidate)
1828 i += 1
1829 continue
1830
1831 if not private_segment and (class_ == None or class_[0] != None):
1832 if class_ != None:
1833 candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
1834 else:
1835 candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
1836 if candidate != None and candidate.name.find("::") == -1:
1837 if class_ == None:
1838 debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
1839 unowned_functions.append(candidate)
1840 else:
1841 debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
1842 class_[0].found_funs.append(candidate)
1843 else:
1844 candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i)
1845 if candidate != None:
1846 enums.append(candidate)
1847 debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
1848 elif class_ != None and class_[1] == 1:
1849 candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i)
1850 if candidate != None:
1851 debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
1852 class_[0].found_constrs.append(candidate)
1853 else:
1854 candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
1855 if candidate != None:
1856 if type(candidate) == list:
1857 for c in candidate:
1858 debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2)
1859 class_[0].found_vars.extend(candidate)
1860 else:
1861 debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2)
1862 class_[0].found_vars.append(candidate)
1863
1864 j = i
1865 line = unpretty_string(line)
1866 while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"):
1867 j += 1
1868 line = line + "\n" + unpretty_string(source_text[j])
1869 if class_ != None:
1870 candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces))
1871 else:
1872 candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces))
1873 if candidate != None and candidate.name.find("::") == -1:
1874 if class_ == None:
1875 debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
1876 unowned_functions.append(candidate)
1877 else:
1878 debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
1879 class_[0].found_funs.append(candidate)
1880 continue
1881 candidate = WEnum.from_string(line, concat_namespace(namespaces), i)
1882 if candidate != None:
1883 enums.append(candidate)
1884 debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2)
1885 continue
1886 if class_ != None:
1887 candidate = WConstructor.from_string(line, source.name, class_[0], i)
1888 if candidate != None:
1889 debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2)
1890 class_[0].found_constrs.append(candidate)
1891 continue
1892 if candidate != None:
1893 while i < j:
1894 i += 1
1895 line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }")
1896 ugly_line = unpretty_string(line)
1897 if len(namespaces) != 0:
1898 namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}"))
1899 if namespaces[-1][1] == 0:
1900 debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3)
1901 del namespaces[-1]
1902 if class_ != None:
1903 class_ = (class_[0] , class_[1] + ugly_line.count("{") - ugly_line.count("}"))
1904 if class_[1] == 0:
1905 if class_[0] == None:
1906 debug("\tExiting unknown class", 3)
1907 else:
1908 debug("\tExiting class " + class_[0].name, 3)
1909 class_ = None
1910 private_segment = False
1911 i += 1
1912 else:
1913 i += 1
1914
1915 def debug(message, level):
1916 if level <= debug.debug_level:
1917 print(message)
1918
1919 def expand_function(f):
1920 fun_list = []
1921 arg_list = []
1922 for arg in f.args:
1923 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")):
1924 fi = copy.deepcopy(f)
1925 fi.args = copy.deepcopy(arg_list)
1926 fun_list.append(fi)
1927 arg_list.append(arg)
1928 fun_list.append(f)
1929 return fun_list
1930
1931 def expand_functions():
1932 global unowned_functions
1933 new_funs = []
1934 for fun in unowned_functions:
1935 new_funs.extend(expand_function(fun))
1936 unowned_functions = new_funs
1937 for source in sources:
1938 for class_ in source.classes:
1939 new_funs = []
1940 for fun in class_.found_funs:
1941 new_funs.extend(expand_function(fun))
1942 class_.found_funs = new_funs
1943
1944 def clean_duplicates():
1945 for source in sources:
1946 for class_ in source.classes:
1947 known_decls = {}
1948 for fun in class_.found_funs:
1949 if fun.gen_decl_hash_py() in known_decls:
1950 debug("Multiple declarations of " + fun.gen_decl_hash_py(),3)
1951 other = known_decls[fun.gen_decl_hash_py()]
1952 other.gen_alias()
1953 fun.gen_alias()
1954 if fun.gen_decl_hash_py() == other.gen_decl_hash_py():
1955 fun.duplicate = True
1956 debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3)
1957 else:
1958 known_decls[fun.gen_decl_hash_py()] = fun
1959 known_decls = []
1960 for con in class_.found_constrs:
1961 if con.gen_decl_hash_py() in known_decls:
1962 debug("Multiple declarations of " + con.gen_decl_hash_py(),3)
1963 con.duplicate = True
1964 else:
1965 known_decls.append(con.gen_decl_hash_py())
1966 known_decls = []
1967 for fun in unowned_functions:
1968 if fun.gen_decl_hash_py() in known_decls:
1969 debug("Multiple declarations of " + fun.gen_decl_hash_py(),3)
1970 fun.duplicate = True
1971 else:
1972 known_decls.append(fun.gen_decl_hash_py())
1973
1974 def gen_wrappers(filename, debug_level_ = 0):
1975 debug.debug_level = debug_level_
1976 for source in sources:
1977 parse_header(source)
1978
1979 expand_functions()
1980 clean_duplicates()
1981
1982 import shutil
1983 import math
1984 col = shutil.get_terminal_size((80,20)).columns
1985 debug("-"*col, 1)
1986 debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1)
1987 debug("-"*col, 1)
1988 for source in sources:
1989 for class_ in source.classes:
1990 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)
1991 if len(class_.found_constrs) == 0:
1992 class_.found_constrs.append(WConstructor(source.name, class_))
1993 debug(str(len(unowned_functions)) + " functions are unowned", 1)
1994 for enum in enums:
1995 debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1)
1996 debug("-"*col, 1)
1997 wrapper_file = open(filename, "w+")
1998 wrapper_file.write(
1999 """/*
2000 * yosys -- Yosys Open SYnthesis Suite
2001 *
2002 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
2003 *
2004 * Permission to use, copy, modify, and/or distribute this software for any
2005 * purpose with or without fee is hereby granted, provided that the above
2006 * copyright notice and this permission notice appear in all copies.
2007 *
2008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2015 *
2016 * This is a generated file and can be overwritten by make
2017 */
2018
2019 #ifdef WITH_PYTHON
2020 """)
2021 for source in sources:
2022 wrapper_file.write("#include \""+source.name+".h\"\n")
2023 wrapper_file.write("""
2024 #include <boost/python/module.hpp>
2025 #include <boost/python/class.hpp>
2026 #include <boost/python/wrapper.hpp>
2027 #include <boost/python/call.hpp>
2028 #include <boost/python.hpp>
2029
2030 USING_YOSYS_NAMESPACE
2031
2032 namespace YOSYS_PYTHON {
2033 """)
2034
2035 for source in sources:
2036 for wclass in source.classes:
2037 wrapper_file.write("\n\tstruct " + wclass.name + ";")
2038
2039 wrapper_file.write("\n")
2040
2041 for source in sources:
2042 for wclass in source.classes:
2043 wrapper_file.write(wclass.gen_decl(source.name))
2044
2045 wrapper_file.write("\n")
2046
2047 for source in sources:
2048 for wclass in source.classes:
2049 wrapper_file.write(wclass.gen_funs(source.name))
2050
2051 for fun in unowned_functions:
2052 wrapper_file.write(fun.gen_def())
2053
2054 wrapper_file.write(""" struct Initializer
2055 {
2056 Initializer() {
2057 if(!Yosys::yosys_already_setup())
2058 {
2059 Yosys::log_streams.push_back(&std::cout);
2060 Yosys::log_error_stderr = true;
2061 Yosys::yosys_setup();
2062 }
2063 }
2064
2065 Initializer(Initializer const &) {}
2066
2067 ~Initializer() {
2068 Yosys::yosys_shutdown();
2069 }
2070 };
2071
2072 BOOST_PYTHON_MODULE(libyosys)
2073 {
2074 using namespace boost::python;
2075
2076 class_<Initializer>("Initializer");
2077 scope().attr("_hidden") = new Initializer();
2078 """)
2079
2080 for enum in enums:
2081 wrapper_file.write(enum.gen_boost_py())
2082
2083 for source in sources:
2084 for wclass in source.classes:
2085 wrapper_file.write(wclass.gen_boost_py())
2086
2087 for fun in unowned_functions:
2088 wrapper_file.write(fun.gen_boost_py())
2089
2090 wrapper_file.write("\n\t}\n}\n#endif")
2091
2092 def print_includes():
2093 for source in sources:
2094 print(source.name + ".pyh")