source: orange/source/pyxtract/pyxtract.py @ 9505:4b798678cd3d

Revision 9505:4b798678cd3d, 47.6 KB checked in by matija <matija.polajnar@…>, 2 years ago (diff)

Merge in the (heavily modified) MLC code from GSOC 2011 (modules, documentation, evaluation code, regression test). Widgets will be merged in a little bit later, which will finally close ticket #992.

Line 
1#!/usr/bin/env python
2import re, os, sys, os.path, string, pickle
3from pyxtractstructures import *
4
5               
6if 1: ### Definitions of method slots
7
8  specialmethods=[
9                ("dealloc", "tp_dealloc", "destructor"),
10                ("", "tp_print", "0"),
11                ("", "tp_getattr", "0"),
12                ("", "tp_setattr", "0"),
13                ("cmp", "tp_compare", "cmpfunc"),
14                ("repr", "tp_repr", "reprfunc"),
15                ("", "as_number"),
16                ("", "as_sequence"),
17                ("", "as_mapping"),
18                ("hash", "tp_hash", "hashfunc"),
19                ("call", "tp_call", "ternaryfunc"),
20                ("str", "tp_str", "reprfunc"),
21                ("getattr", "tp_getattro", "getattrofunc"),
22                ("setattr", "tp_setattro", "setattrofunc"),
23                ("", "tp_as_buffer", "0"),
24                ("", "FLAGS"),
25                ("", "DOC"),
26                ("traverse", "tp_traverse", "traverseproc"),
27                ("clear", "tp_clear", "inquiry"),
28                ("richcmp", "tp_richcmp", "richcmpfunc"),
29                ("", "tp_weaklistoffset", "0"),
30                ("iter", "tp_iter", "getiterfunc"),
31                ("iternext", "tp_iternext", "iternextfunc"),
32                ("", "methods",),
33                ("", "tp_members", "0"),
34                ("", "getset",),
35                ("", "BASE",),
36                ("", "tp_dict", "0"),
37                ("", "tp_descrget", "0"),
38                ("", "tp_descrset", "0"),
39                ("", "DICTOFFSET"),
40                ("init", "tp_init", "initproc"),
41                ("", "tp_alloc", "PyType_GenericAlloc"),
42                ("new", "tp_new", "newfunc"),
43                ("", "tp_free", "_PyObject_GC_Del"),
44                ("", "tp_is_gc", "0"),
45                ("", "tp_bases", "0"),
46                ("", "tp_mro", "0"),
47                ("", "tp_cache", "0"),
48                ("", "tp_subclasses", "0"),
49                ("", "tp_weaklist", "0")
50               ]
51
52  specialnumericmethods=[
53                ("add", "nb_add", "binaryfunc"),
54                ("sub", "nb_subtract", "binaryfunc"),
55                ("mul", "nb_multiply", "binaryfunc"),
56                ("div", "nb_divide", "binaryfunc"),
57                ("mod", "nb_remainder", "binaryfunc"),
58                ("divmod", "nb_divmod", "binaryfunc"),
59                ("pow", "nb_power", "ternaryfunc"),
60                ("neg", "nb_negative", "unaryfunc"),
61                ("pos", "nb_positive", "unaryfunc"),
62                ("abs", "nb_absolute", "unaryfunc"),
63                ("nonzero", "nb_nonzero", "inquiry"),
64                ("inv", "nb_invert", "unaryfunc"),
65                ("lshift", "nb_lshift", "binaryfunc"),
66                ("rshift", "nb_rshift", "binaryfunc"),
67                ("and", "nb_and", "binaryfunc"),
68                ("xor", "nb_xor", "binaryfunc"),
69                ("or", "nb_or", "binaryfunc"),
70                ("coerce", "nb_coerce", "coercion"),
71                ("int", "nb_int", "unaryfunc"),
72                ("long", "nb_long", "unaryfunc"),
73                ("float", "nb_float", "unaryfunc"),
74                ("oct", "nb_oct", "unaryfunc"),
75                ("hex", "nb_hex", "unaryfunc")
76                ]
77
78  specialsequencemethods=[
79                ("len_sq", "sq_length", "inquiry"),
80                ("concat", "sq_concat", "binaryfunc"),
81                ("repeat", "sq_repeat", "intargfunc"),
82                ("getitem_sq", "sq_item", "intargfunc"),
83                ("getslice", "sq_slice", "intintargfunc"),
84                ("setitem_sq", "sq_ass_item", "intobjargproc"),
85                ("setslice", "sq_ass_slice", "intintobjargproc"),
86                ("contains", "sq_contains", "objobjproc")
87                ]
88
89  specialmappingmethods=[
90                ("len", "mp_length", "inquiry"),
91                ("getitem", "mp_subscript", "binaryfunc"),
92                ("setitem", "mp_ass_subscript", "objobjargproc")
93                ]
94
95 
96  genericconstrs = {'C_UNNAMED': 'PyOrType_GenericNew',
97                    'C_NAMED'  : 'PyOrType_GenericNamedNew',
98                    'C_CALL'   : 'PyOrType_GenericCallableNew',
99                    'C_CALL3'  : 'PyOrType_GenericCallableNew'}
100               
101if 1: ### Definitions of regular expressions
102
103  constrdef_mac=re.compile(r'(?P<constype>ABSTRACT|C_UNNAMED|C_NAMED|C_CALL)\s*\(\s*(?P<typename>\w*)\s*(-\s*(?P<displayname>\S*))?,\s*(?P<basename>\w*\s*)\s*(,\s*"(?P<doc>[^"]*)")?\s*\)')
104  constrdef_mac_call3=re.compile(r'(?P<constype>C_CALL3)\s*\(\s*(?P<typename>\w*)\s*(-\s*(?P<displayname>\S*))?,\s*(?P<callname>\w*\s*)\s*,\s*(?P<basename>\w*\s*)\s*(,\s*"(?P<doc>[^"]*)")?\s*\)')
105  constrkeywords = re.compile(r'CONSTRUCTOR_KEYWORDS\s*\(\s*(?P<typename>\w*)\s*, \s*"(?P<keywords>[^"]*)"\s*\)')
106  nopickle=re.compile(r"NO_PICKLE\s*\(\s*(?P<typename>\w*)\s*\)")
107  constrwarndef=re.compile(r"[^\w](ABSTRACT|CONS|C_UNNAMED|C_NAMED|C_CALL)[^\w]")
108
109  datastructuredef=re.compile(r'DATASTRUCTURE\s*\(\s*(?P<typename>\w*)\s*(-\s*(?P<displayname>\S*))?,\s*(?P<structurename>\w*)\s*,\s*(?P<dictfield>\w*)\s*\)')
110  newbasedondef=re.compile(r'(inline)?\s*PyObject\s*\*(?P<typename>\w*)_new\s*\([^)]*\)\s*BASED_ON\s*\(\s*(?P<basename>\w*)\s*(-\s*(?P<displayname>\S*))?,\s*"(?P<doc>[^"]*)"\s*\)\s*(?P<allows_empty_args>ALLOWS_EMPTY)?')
111  basedondef=re.compile(r'BASED_ON\s*\(\s*(?P<typename>\w*)\s*(-\s*(?P<displayname>\S*))?,\s*(?P<basename>\w*)\s*\)')
112  hiddendef=re.compile(r'HIDDEN\s*\(\s*(?P<typename>\w*)\s*(-\s*(?P<displayname>\S*))?,\s*(?P<basename>\w*)\s*\)')
113 
114
115  allspecial=['('+m[0]+')' for m in specialmethods+specialnumericmethods+specialsequencemethods+specialmappingmethods]
116  allspecial=filter(lambda x:x!='()', allspecial)
117  allspecial=reduce(lambda x,y:x+'|'+y, allspecial)
118  specialmethoddef=re.compile(r'((PyObject\s*\*)|(int)|(void)|(Py_ssize_t))\s*(?P<typename>\w*)_(?P<methodname>'+allspecial+r')\s*\(')
119
120  calldocdef=re.compile(r'PyObject\s*\*(?P<typename>\w*)_call\s*\([^)]*\)\s*PYDOC\s*\(\s*"(?P<doc>[^"]*)"\s*\)')
121  getdef=re.compile(r'PyObject\s*\*(?P<typename>\w*)_(?P<method>get)_(?P<attrname>\w*)\s*\([^)]*\)\s*(PYDOC\(\s*"(?P<doc>[^"]*)"\s*\))?')
122  setdef=re.compile(r'int\s*(?P<typename>\w*)_(?P<method>set)_(?P<attrname>\w*)\s*\([^)]*\)\s*(PYDOC\(\s*"(?P<doc>[^"]*)"\s*\))?')
123  methoddef=re.compile(r'PyObject\s*\*(?P<typename>\w\w+)_(?P<cname>\w*)\s*\([^)]*\)\s*PYARGS\((?P<argkw>[^),]*)\s*(,\s*"(?P<doc>[^"]*)")?\s*\)(\s*//>(?P<methodname>\w\w+))?')
124  reducedef=re.compile(r'PyObject\s*\*(?P<typename>\w\w+)__reduce__')
125
126  funcdef2=re.compile(r'(?P<defpart>PyObject\s*\*(?P<pyname>\w*)\s*\([^)]*\))\s*;?\s*PYARGS\((?P<argkw>[^),]*)\s*(,\s*"(?P<doc>[^"]*)")?\s*\)')
127  funcwarndef=re.compile("PYARGS")
128  keywargsdef=re.compile(r"METH_VARARGS\s*\|\s*METH_KEYWORDS")
129
130  classconstantintdef=re.compile(r"PYCLASSCONSTANT_INT\((?P<typename>\w*)\s*,\s*(?P<constname>\w*)\s*,\s*(?P<constant>.*)\)\s*$")
131  classconstantfloatdef=re.compile(r"PYCLASSCONSTANT_FLOAT\((?P<typename>\w*)\s*,\s*(?P<constname>\w*)\s*,\s*(?P<constant>.*)\)\s*$")
132  classconstantdef=re.compile(r"PYCLASSCONSTANT\((?P<typename>\w*)\s*,\s*(?P<constname>\w*)\s*,\s*(?P<constant>.*)\)\s*$")
133 
134  constantintdef=re.compile(r"PYCONSTANT_INT\((?P<pyname>\w*)\s*,\s*(?P<constant>.*)\)\s*$")
135  constantfloatdef=re.compile(r"PYCONSTANT_FLOAT\((?P<pyname>\w*)\s*,\s*(?P<constant>.*)\)\s*$")
136  constantdef=re.compile(r"PYCONSTANT\((?P<pyname>\w*)\s*,\s*(?P<ccode>.*)\)\s*$")
137  constantfuncdef=re.compile(r"PYCONSTANTFUNC\((?P<pyname>\w*)\s*,\s*(?P<cfunc>.*)\)\s*$")
138  constantwarndef=re.compile("PYCONSTANT")
139  recognizedattrsdef = re.compile(r'RECOGNIZED_ATTRIBUTES\s*\(\s*(?P<typename>\w*)\s*, \s*"(?P<attributes>[^"]*)"\s*\)')
140
141if 1:
142  cc_functions = "int cc_func_%(type)s(PyObject *obj, void *ptr) { if (!PyOr%(type)s_Check(obj)) return 0;      *(GCPtr<T%(type)s> *)(ptr) = PyOrange_As%(type)s(obj); return 1; }\n" + \
143                 "int ccn_func_%(type)s(PyObject *obj, void *ptr) { if (obj == Py_None) { *(GCPtr<T%(type)s> *)(ptr) = GCPtr<T%(type)s>(); return 1; }      if (!PyOr%(type)s_Check(obj)) return 0;      *(GCPtr<T%(type)s> *)(ptr) = PyOrange_As%(type)s(obj); return 1; }\n\n\n"
144
145
146f_underscored = open("../_underscored", "a")
147hump = re.compile("([a-z])([A-Z])")
148
149def camelChange(mo):
150    if mo.end() == len(mo.string) or not 'A'<=mo.string[mo.end()]<='Z':
151        sg = mo.group(2).lower()
152    else:
153        sg = mo.group(2)
154    return "%s_%s" % (mo.group(1), sg)
155   
156def camel2underscore(s):
157    if s[0].isupper():
158        return s
159    else:
160        u = hump.sub(camelChange, s)
161        if u != s:
162            f_underscored.write("%-40s %s\n" % (s, u))
163        return u
164
165
166def detectConstructors(line, classdefs):
167  found=constrdef_mac.search(line)
168  if not found:
169    found=constrdef_mac_call3.search(line)
170  if found:
171    typename, basename, constype, doc, displayname =found.group("typename", "basename", "constype", "doc", "displayname")
172    printV2("%s (%s): Macro constructor %s", (typename, basename, constype))
173    addClassDef(classdefs, typename, parsedFile, "basetype", basename, displayname=displayname)
174    if constype=="ABSTRACT":
175      classdefs[typename].abstract = True
176    else:
177       addClassDef(classdefs, typename, parsedFile, "constructor", ConstructorDefinition(arguments=doc, type=constype, allows_empty_args = True))
178    return 1
179 
180  found = constrkeywords.search(line)
181  if found:
182    typename, keywords = found.group("typename", "keywords")
183    addClassDef(classdefs, typename, parsedFile, "constructor_keywords", keywords.split())
184    return 1
185 
186  if constrwarndef.search(line):
187    printV0("Warning: looks like constructor, but syntax is not matching")
188    return 1
189
190  found = nopickle.search(line)
191  if found:
192    typename = found.group("typename")
193    addClassDef(classdefs, typename, parsedFile)
194    classdefs[typename].methods["__reduce__"] = MethodDefinition(argkw="METH_NOARGS", cname="*yieldNoPickleError")
195    return 1
196
197def detectAttrs(line, classdefs):
198  found = getdef.search(line) or setdef.search(line)
199  if found:
200    typename, attrname, method, doc = found.group("typename", "attrname", "method", "doc")
201    printV2("%s: definition of %s_%s", (typename, method, attrname))
202    addClassDef(classdefs, typename, parsedFile)
203    if not classdefs[typename].properties.has_key(attrname):
204      classdefs[typename].properties[attrname]=AttributeDefinition()
205    setattr(classdefs[typename].properties[attrname], "has"+method, 1)
206    if doc:
207      classdefs[typename].properties[attrname].description=doc
208    return
209
210  found=classconstantintdef.search(line)
211  if found:
212    typename, constname, constant = found.group("typename", "constname", "constant")
213    printV2("%s: constant definition (%s)", (typename, constname))
214    addClassDef(classdefs, typename, parsedFile)
215    if not classdefs[typename].constants.has_key(constname):
216      classdefs[typename].constants[constname] = ConstantDefinition(ccode=("PyInt_FromLong((long)(%s))" % constant))
217    else:
218      printV0("Warning: constant %s.%s duplicated", (typename, constname))
219    return
220
221  found=classconstantfloatdef.search(line)
222  if found:
223    typename, constname, constant = found.group("typename", "constname", "constant")
224    printV2("%s: constant definition (%s)", (typename, constname))
225    addClassDef(classdefs, typename, parsedFile)
226    if not classdefs[typename].constants.has_key(constname):
227      classdefs[typename].constants[constname] = ConstantDefinition(ccode=("PyFloat_FromDouble((double)(%s))" % constant))
228    else:
229      printV0("Warning: constant %s.%s duplicated", (typename, constname))
230    return
231
232  found=classconstantdef.search(line)
233  if found:
234    typename, constname, constant = found.group("typename", "constname", "constant")
235    printV2("%s: constant definition (%s)", (typename, constname))
236    addClassDef(classdefs, typename, parsedFile)
237    if not classdefs[typename].constants.has_key(constname):
238      classdefs[typename].constants[constname] = ConstantDefinition(ccode=constant)
239    else:
240      printV0("Warning: constant %s.%s duplicated", (typename, constname))
241    return
242
243  found=recognizedattrsdef.search(line)
244  if found:
245    typename, attributes = found.group("typename", "attributes")
246    addClassDef(classdefs, typename, parsedFile, "recognized_attributes", attributes.split())
247
248
249def detectMethods(line, classdefs):
250  # The below if is to avoid methods, like, for instance, map's clear to be recognized
251  # also as a special method. Special methods never include PYARGS.
252  if line.find("PYARGS")<0:
253    found=specialmethoddef.search(line)
254    if found:
255      typename, methodname = found.group("typename", "methodname")
256      addClassDef(classdefs, typename, parsedFile)
257      classdefs[typename].specialmethods[methodname]=1
258
259  found=reducedef.search(line)
260  typename = None
261  if found:
262    typename = found.group("typename")
263    methodname = "__reduce__"
264    cname = "_reduce__"
265    argkw = "METH_NOARGS"
266    doc = "()"
267   
268  else:
269    found=methoddef.search(line)
270    if found:
271      typename, cname, methodname, argkw, doc = found.group("typename", "cname", "methodname", "argkw", "doc")
272
273  if typename: 
274    if not classdefs.has_key(typename) and "_" in typename:
275      com = typename.split("_")
276      for i in range(1, len(com)):
277          subname = "_".join(com[:-i]) 
278          if subname in classdefs:
279              typename = subname
280              cname = "_".join(com[-i:])+"_"+cname
281              break
282
283    if not methodname:
284      methodname = camel2underscore(cname)
285
286     
287    addClassDef(classdefs, typename, parsedFile)
288    classdefs[typename].methods[methodname]=MethodDefinition(argkw=argkw, arguments=doc, cname=cname)
289    return 1
290
291def detectHierarchy(line, classdefs):
292  found=datastructuredef.search(line)
293  if found:
294    typename, structurename, dictfield, displayname = found.group("typename", "structurename", "dictfield", "displayname")
295    addClassDef(classdefs, typename, parsedFile, "datastructure", structurename, displayname=displayname)
296    addClassDef(classdefs, typename, parsedFile, "dictfield", dictfield, 0)
297    printV2("%s: definition/declaration of datastructure", typename)
298    return 1
299 
300  found=newbasedondef.match(line)
301  if found:
302    typename, basename, doc, displayname = found.group("typename", "basename", "doc", "displayname")
303    allows_empty_args = bool(found.group("allows_empty_args"))
304    addClassDef(classdefs, typename, parsedFile, "basetype", basename, 0, displayname)
305    addClassDef(classdefs, typename, parsedFile, "constructor", ConstructorDefinition(arguments=doc, type="MANUAL", allows_empty_args=allows_empty_args))
306    return 1
307
308  found=basedondef.match(line)
309  if found:
310    typename, basename, displayname = found.group("typename", "basename", "displayname")
311    addClassDef(classdefs, typename, parsedFile, "basetype", basename, 0, displayname)
312    return 1
313
314  found=hiddendef.match(line)
315  if found:
316    typename, basename, displayname = found.group("typename", "basename", "displayname")
317    addClassDef(classdefs, typename, parsedFile, "basetype", basename, 0, displayname=displayname)
318    classdefs[typename].hidden = 1
319    return 1
320
321
322def detectCallDoc(line, classdefs):
323  found=calldocdef.search(line)
324  if found:
325    typename, doc = found.group("typename", "doc")
326    printV2("%s: definition/declaration of description" % typename)
327    addClassDef(classdefs, typename, parsedFile, "description", doc)
328    return 1
329
330
331
332def detectFunctions(line, functiondefs):     
333  found=funcdef2.search(line)
334  if found:
335    defpart, pyname, argkw, doc =found.group("defpart", "pyname", "argkw", "doc")
336    printV2("%s: function definition (%s)", (pyname, pyname))
337    functiondefs[pyname]=FunctionDefinition(cname=pyname, argkw=argkw, definition=defpart, arguments=doc)
338    return 1
339  if funcwarndef.search(line):
340    printV0("Warning: looks like function, but syntax is not matching")
341
342
343def detectConstants(line, constantdefs):
344  found=constantdef.search(line)
345  if found:
346    pyname, ccode = found.group("pyname", "ccode")
347    printV2("%s: constant definition (%s)", (pyname, ccode))
348    constantdefs[pyname]=ConstantDefinition(ccode=ccode)
349    #constantdefs.append((pyname, ccode))
350    return 1
351
352  found=constantintdef.search(line)
353  if found:
354    pyname, constant = found.group("pyname", "constant")
355    printV2("%s: constant definition (%s)", (pyname, constant))
356    constantdefs[pyname]=ConstantDefinition(ccode=("PyInt_FromLong((long)(%s))" % constant))
357    #constantdefs.append((pyname, ccode))
358    return 1
359
360  found=constantfloatdef.search(line)
361  if found:
362    pyname, constant = found.group("pyname", "constant")
363    printV2("%s: constant definition (%s)", (pyname, constant))
364    constantdefs[pyname]=ConstantDefinition(ccode=("PyFloat_FromDouble((double)(%s))" % constant))
365    #constantdefs.append((pyname, ccode))
366    return 1
367
368  found=constantfuncdef.search(line)
369  if found:
370    pyname, cfunc = found.group("pyname", "cfunc")
371    printV2("%s: constant returning definition (%s)", (pyname, cfunc))
372    constantdefs[pyname]=ConstantDefinition(cfunc=cfunc)
373    #constantdefs.append((pyname, cfunc, 0))
374    return 1
375
376  if constantwarndef.search(line):
377    printV0("Warning: looks like constant, but syntax is not matching")
378
379
380
381def parseFiles():
382  global parsedFile
383  functions, constants, classdefs = {}, {}, {}
384
385  for l in libraries:
386    f = open(l, "rt")
387    cd = pickle.load(f)
388    #ignore functions and constants - we don't need them
389    for c in cd.values():
390      c.imported = True
391    classdefs.update(cd)
392   
393   
394  aliases=readAliases() 
395
396  filenamedef=re.compile(r"(?P<stem>.*)\.\w*$")
397  for parsedFile in filenames:
398    found=filenamedef.match(parsedFile)
399    if found:
400      filestem=found.group("stem")
401    else:
402      filestem=parsedFile
403
404    infile=open(parsedFile, "rt")
405    printNQ("Parsing " + parsedFile)
406    global lineno
407    lineno=0
408
409    for line in infile:
410      lineno=lineno+1
411      if line.strip().startswith("PYXTRACT_IGNORE"):
412        continue
413      detectHierarchy(line, classdefs) # BASED_ON, DATASTRUCTURE those lines get detected twice!
414      # detectMethods must be before detectAttrs to allow for methods named get_something, set_something
415      for i in [detectConstructors, detectMethods, detectAttrs, detectCallDoc]:
416        if i(line, classdefs):
417          break
418      else:
419        detectFunctions(line, functions)
420        detectConstants(line, constants)
421
422    infile.close()
423
424  classdefsEffects(classdefs)
425
426
427  return functions, constants, classdefs, aliases
428
429def findDataStructure(classdefs, typename):
430  rtypename = typename
431  while typename and typename!="ROOT" and classdefs.has_key(typename) and not classdefs[typename].datastructure:
432    typename = classdefs[typename].basetype
433    if not classdefs.has_key(typename):
434      return None
435    if classdefs[typename].imported:
436      classdefs[typename].used = True
437  if not typename or not classdefs.has_key(typename) or typename=="ROOT":
438    return None
439  else:
440    return classdefs[typename].datastructure
441
442def findConstructorDoc(classdefs, typename):
443  while typename and typename!="ROOT" and classdefs.has_key(typename) and not classdefs[typename].constructor:
444    typename=classdefs[typename].basetype
445  if not typename or not classdefs.has_key(typename) or typename=="ROOT":
446    return "<abstract class>"
447  else:
448    return classdefs[typename].constructor.arguments
449
450def classdefsEffects(classdefs):
451  ks=classdefs.keys()       
452  for typename in ks:
453    classdef=classdefs[typename]
454    classdef.datastructure = findDataStructure(classdefs, typename)
455    if not classdefs[typename].datastructure:
456      printNQ("Warning: %s looked like a class, but is ignored since no corresponding data structure was found" % typename)
457      del classdefs[typename]
458     
459    scs = pyprops and pyprops.get("T"+typename, None)
460    classdef.subconstants = scs and scs.constants
461    if scs:
462      for consttype, valuelist in classdef.subconstants.items():
463        for k, v in valuelist:
464          classdef.constants[k]=ConstantDefinition(ccode=("Py%s_%s_FromLong((long)(%s))" % (typename, consttype, v)))
465#        classdef.constants[consttype]=ConstantDefinition(ccode=("(PyObject *)&Py%s_%s_Type" % (typename, consttype)))
466     
467     
468
469
470def readAliases():
471  aliases={}
472  if os.path.isfile("_aliases.txt"):
473    f=open("_aliases.txt", "rt")
474    actClass, aliasList = "", []
475    for line in f:
476      ss=line.split()
477      if len(ss):
478        if len(ss)==2:
479          aliasList.append(ss)
480        if (len(ss)==1) or (len(ss)==3):
481          if actClass and len(aliasList):
482            aliases[actClass]=aliasList
483          actClass=ss[0]
484          aliasList=[]
485
486    if actClass and len(aliasList):
487      aliases[actClass]=aliasList
488    f.close()
489   
490  return aliases
491       
492def findSpecialMethod(classdefs, type, name):
493  while 1:
494    if classdefs[type].specialmethods.has_key(name):
495      return type
496    elif classdefs[type].basetype:
497      type=classdefs[type].basetype
498    else:
499      return None 
500
501
502def writeAppendix(filename, targetname, classdefs, aliases):
503  if (    not recreate
504      and  os.path.isfile(targetname)
505      and (os.path.getmtime(targetname)>=os.path.getmtime(filename))
506      and (os.path.getmtime(targetname)>=os.path.getmtime("aliases.txt"))):
507    printV1("\nFile unchanged, skipping.")
508    return
509
510  usedbases={}
511  classdefi=classdefs.items()
512  classdefi.sort(lambda x,y:cmp(x[0],y[0]))
513  basecount=0
514  for (type, fields) in classdefi:
515    if fields.infile==filename:
516      usedbases[fields.basetype]=1
517    basecount += 1
518  if usedbases.has_key("ROOT"):
519    del usedbases["ROOT"]
520
521  if not basecount:
522    if os.path.isfile(targetname):
523      os.remove(targetname)
524      printV1("\nFile does not define any classes, removing.")
525    else:
526      printV1("\nFile does not define any classes, skipping.")
527    return
528
529  printV1("\nConstructing class definitions")
530 
531  outfile=open("px/"+targetname+".new", "wt")
532  newfiles.append(targetname)
533  outfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
534  outfile.write('#include <cstddef>\n\n')
535
536  usedbases=usedbases.keys()
537  usedbases.sort()
538  #outfile.write("extern TOrangeType PyOrOrangeType_Type;\n")
539  for type in usedbases:
540    if type:
541      if classdefs[type].imported:
542        outfile.write("extern IMPORT_DLL TOrangeType PyOr"+type+"_Type;\n")
543      else:
544        outfile.write("extern %s_API TOrangeType PyOr%s_Type;\n" % (modulename.upper(), type))
545  outfile.write("\n\n")
546
547  for (type, fields) in classdefi:
548    if fields.infile!=filename:
549      continue
550
551    outfile.write('/* -------------- %s --------------*/\n\n' % type)
552
553    # Write PyMethodDef
554    if len(fields.methods):
555      methodnames=fields.methods.keys()
556      methodnames.sort()
557      outfile.write("PyMethodDef "+type+"_methods[] = {\n")
558      for methodname in methodnames:
559        method=fields.methods[methodname]
560        cname = method.cname[0] == "*" and method.cname[1:] or type+"_"+method.cname
561        if method.arguments:
562          outfile.write('     {"'+methodname+'", (binaryfunc)'+cname+", "+method.argkw+", \""+method.arguments+"\"},\n")
563        else:
564          outfile.write('     {"'+methodname+'", (binaryfunc)'+cname+", "+method.argkw+"},\n")
565      outfile.write("     {NULL, NULL}\n};\n\n")
566     
567
568    # Write GetSetDef
569    properties=filter(lambda (name, definition): not definition.builtin, fields.properties.items())
570    if len(properties):
571      properties.sort(lambda x,y:cmp(x[0], y[0]))
572      outfile.write("PyGetSetDef "+type+"_getset[]=  {\n")
573      for (name, definition) in properties:
574        camelname = camel2underscore(name)
575        outfile.write('  {"%s"' % camelname)
576        if definition.hasget:
577          outfile.write(", (getter)%s_get_%s" % (type, name))
578        else:
579          outfile.write(", NULL")
580        if definition.hasset:
581          outfile.write(", (setter)%s_set_%s" % (type, name))
582        else:
583          outfile.write(", NULL")
584        if definition.description:
585          outfile.write(', "'+definition.description+'"')
586        outfile.write("},\n")
587      outfile.write('  {NULL}};\n\n')
588
589    # Write doc strings
590    if fields.call and fields.call.arguments and len(fields.call.arguments):
591      outfile.write('char '+type+'[] = "'+fields.call.arguments+'";\n')
592    if fields.description:
593      outfile.write('char '+type+'_doc[] = "'+fields.description+'";\n')
594    outfile.write('\n')
595
596    if fields.subconstants:
597      for constname, constvalues in fields.subconstants.items():
598        outfile.write("""
599TNamedConstantsDef %(wholename)s_values[] = {%(valueslist)s, {0, 0}};
600static PyObject *%(wholename)s_repr(PyObject *self) { return stringFromList(self, %(wholename)s_values); }
601PyObject *%(wholename)s__reduce__(PyObject *self);
602PyMethodDef %(wholename)s_methods[] = { {"__reduce__", (binaryfunc)%(wholename)s__reduce__, METH_NOARGS, "reduce"}, {NULL, NULL}};
603PyTypeObject Py%(wholename)s_Type = {PyObject_HEAD_INIT(&PyType_Type) 0, "%(classname)s.%(constname)s", sizeof(PyIntObject), 0, 0, 0, 0, 0, 0, (reprfunc)%(wholename)s_repr, 0, 0, 0, 0, 0, (reprfunc)%(wholename)s_repr, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, 0, 0, 0, 0, 0, 0, 0, %(wholename)s_methods, 0, 0, &PyInt_Type, 0, 0, 0, 0, 0, 0, 0, PyObject_Del};
604PyObject *Py%(wholename)s_FromLong(long ok) { PyIntObject *r = PyObject_New(PyIntObject, &Py%(wholename)s_Type); r->ob_ival = ok; return (PyObject *)r; }
605void *PT%(wholename)s(void *l) { return Py%(wholename)s_FromLong(*(int *)l); }
606PyObject *%(wholename)s__reduce__(PyObject *self) { return Py_BuildValue("O(s(i))", getExportedFunction("__pickleLoaderNamedConstants"), "%(wholename)s", ((PyIntObject *)(self))->ob_ival); }
607
608""" % {"wholename": type+"_"+constname, "classname": type, "constname": constname, "valueslist": ", ".join('{"%s", %s}' % k for k in constvalues)})
609
610#PyObject *%(wholename)s__reduce__(PyObject *self) { return Py_BuildValue("O(i)", &PyInt_Type, ((PyIntObject *)(self))->ob_ival); }
611
612
613
614
615    # Write constants
616    if fields.constants:
617      outfile.write("void %s_addConstants()\n{ PyObject *&dict = PyOr%s_Type.ot_inherited.tp_dict;\n  if (!dict) dict = PyDict_New();\n" % (type, type))
618      for name, const in fields.constants.items():
619        if const.ccode:
620          outfile.write('  PyDict_SetItemString(dict, "%s", %s);\n' % (name, const.ccode))
621        else:
622          outfile.write('  PyDict_SetItemString(dict, "%s", %s());\n' % (name, const.cfunc))
623      outfile.write("}\n\n")
624
625    # Write default constructor
626    if fields.constructor:
627      if fields.constructor.type!="MANUAL":
628        outfile.write('POrange %s_default_constructor(PyTypeObject *type)\n{ return POrange(mlnew T%s(), type); }\n\n' % (type, type))
629    else:
630      outfile.write('PyObject *%s_abstract_constructor(PyTypeObject *type, PyObject *args, PyObject *kwds)\n{ return PyOrType_GenericAbstract((PyTypeObject *)&PyOr%s_Type, type, args, kwds); }\n\n' % (type, type))
631
632    # Write constructor keywords
633    if fields.constructor_keywords:
634      outfile.write('char *%s_constructor_keywords[] = {%s, NULL};\n' % (type, reduce(lambda x, y: x + ", " + y, ['"%s"' % x for x in fields.constructor_keywords])))
635
636    if fields.recognized_attributes:
637      outfile.write('char *%s_recognized_attributes[] = {%s, NULL};\n' % (type, reduce(lambda x, y: x + ", " + y, ['"%s"' % x for x in fields.recognized_attributes])))
638     
639    outfile.write('\n')                   
640                   
641    # Write aliases   
642    if aliases.has_key(type):
643      outfile.write("TAttributeAlias "+type+"_aliases[] = {\n")
644      for alias in aliases[type]:
645        outfile.write('    {"%s", "%s"},\n' % tuple(alias))
646      outfile.write("    {NULL, NULL}};\n\n")
647   
648    # Write type object 
649
650    def hasany(methods, fields):
651      for smethod in methods:
652        if smethod[0] and fields.specialmethods.has_key(smethod[0]):
653          return 1
654      return 0
655
656    def writeslots(methods, isbase=0):
657      def write0(innulls):
658        outfile.write(innulls and ' 0,' or '  0,')
659        return 1
660
661      innulls=0
662      for smethod in methods:
663        if not smethod[0]:
664          if smethod[1]=="BASE":
665            if fields.basetype and (fields.basetype!="ROOT"):
666              name='(_typeobject *)&PyOr'+fields.basetype+'_Type,'
667              innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_base */\n' % name))
668            else:
669              innulls=write0(innulls)
670
671          elif smethod[1]=="DICTOFFSET":
672            if fields.dictfield and fields.dictfield!="0":
673              innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_dictoffset */\n' % ("offsetof(%s, %s)," % (fields.datastructure, fields.dictfield))))
674            else:
675              innulls=write0(innulls)
676
677          elif smethod[1]=="DOC":
678            innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_doc */\n' % ('"'+findConstructorDoc(classdefs, type)+'",')))
679
680          elif smethod[1]=="FLAGS":
681            fl = "Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE"
682            for cond, flag in [(fields.specialmethods.has_key("traverse"), "Py_TPFLAGS_HAVE_GC")
683                              ]:
684              if cond:
685                fl += " | "+flag
686            innulls=outfile.write((innulls and '\n' or '') + (%s, /* tp_flags */\n' % fl))
687                       
688          else:
689            otherfields= [("as_number",    hasnumeric),
690                          ("as_sequence",  hassequence),
691                          ("as_mapping",   hasmapping),
692                          ("doc",          fields.description),
693                          ("methods",      fields.methods),
694                          ("getset",       len(properties))
695                         ] 
696                     
697            for (name, condition) in otherfields:
698              if smethod[1]==name:
699                if condition:
700                  slotcont='%s_%s,' % (type, name)
701                  if name[:3]=="as_":
702                     slotcont="&"+slotcont
703                  innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_%s */\n' % (slotcont, name)))
704                else:
705                  innulls=write0(innulls)
706                break
707            else:
708              if len(smethod)==3:
709                if smethod[2]=='0':
710                  innulls=write0(innulls)
711                else:
712                  innulls=outfile.write((innulls and '\n' or '') + (%-50s /* %s */\n' % (smethod[2]+',', smethod[1])))
713              else:
714                raise "invalid slot name %s" % smethod[1]
715             
716        else: # smethod[0]!=""
717          if fields.specialmethods.has_key(smethod[0]):
718            innulls=outfile.write((innulls and '\n' or '') + (%-50s /* %s */\n' % ("(%s)%s_%s," % (smethod[2], type, smethod[0]), smethod[1])))
719           
720          elif smethod[0]=="new":
721            if fields.constructor:
722              innulls = outfile.write((innulls and '\n' or '') + (%-50s /* tp_new */\n' % ("(newfunc)%s," % genericconstrs[fields.constructor.type])))
723            else:
724              innulls = outfile.write((innulls and '\n' or '') + (%-50s /* tp_new */\n' % ("(newfunc)%s_abstract_constructor," % type)))
725
726          else:
727            innulls=write0(innulls)
728     
729      return innulls
730
731
732    additional=[]
733    for (subtype, submethods, subappendix) in [('PyNumberMethods', specialnumericmethods, '_as_number'),
734                                               ('PySequenceMethods', specialsequencemethods, '_as_sequence'),
735                                               ('PyMappingMethods', specialmappingmethods, '_as_mapping')]:
736      hasit = hasany(submethods, fields)
737      additional.append(hasit)
738      if hasit:
739        outfile.write(subtype+' '+type+subappendix +' = {\n')
740        innulls=writeslots(submethods, 0)
741        outfile.write((innulls and '\n' or '') + '};\n\n')
742
743    hasnumeric, hassequence, hasmapping = tuple(additional)
744
745    outfile.write('PyTypeObject PyOr'+type+'_Type_inh = {\n')
746    outfile.write('  PyObject_HEAD_INIT((_typeobject *)&PyType_Type)\n')
747    outfile.write('  0,\n')
748    if getattr(fields, "displayname", None):
749        outfile.write('  "%s",\n' % fields.displayname)
750    else:
751        outfile.write('  "%s.%s",\n' % (modulename, type))
752    outfile.write('  sizeof(%s), 0,\n' % fields.datastructure)
753    innulls=writeslots(specialmethods, 1)
754    outfile.write((innulls and '\n' or '') + '};\n\n')
755
756    if fields.datastructure == "TPyOrange":
757      outfile.write(cc_functions % {"type": type})
758
759    outfile.write('%(modulename)s_API TOrangeType PyOr%(type)s_Type (PyOr%(type)s_Type_inh, typeid(T%(type)s)' % {"modulename": modulename.upper(), "type": type})
760    outfile.write(', ' + (fields.constructor and fields.constructor.type!="MANUAL" and type+'_default_constructor' or '0'))
761    if fields.datastructure == "TPyOrange":
762      outfile.write(', cc_%s, ccn_%s' % (type, type))
763    else:
764      outfile.write(', PyOr_noConversion, PyOr_noConversion')
765    outfile.write(', ' + (fields.constructor_keywords and type+'_constructor_keywords' or 'NULL'))
766    outfile.write(', ' + (fields.constructor and fields.constructor.allows_empty_args and 'true' or 'false'))
767    outfile.write(', ' + (fields.recognized_attributes and type+'_recognized_attributes' or 'NULL'))
768    outfile.write(', ' + (aliases.has_key(type) and type+'_aliases' or 'NULL'))
769    outfile.write(');\n\n\n\n')
770
771    if not (fields.abstract or fields.constructor and fields.constructor.allows_empty_args or fields.methods.has_key("__reduce__")):
772      printV0("Warning: class '%s' will not be picklable", type, False)
773     
774  outfile.close()
775
776
777def writeAppendices(classdefs):
778  filenamedef=re.compile(r"(?P<stem>.*)\.\w*$")
779  for filename in filenames:
780    found=filenamedef.match(filename)
781    if found:
782      filestem=found.group("stem")
783    else:
784      filestem=filename
785    writeAppendix(filename, filestem+".px", classdefs, aliases)
786    printV1()
787
788def writeExterns():
789  externsfile=open("px/externs.px.new", "wt")
790  newfiles.append("externs.px")
791
792  externsfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
793
794  externsfile.write("#ifdef _MSC_VER\n  #define IMPORT_DLL __declspec(dllimport)\n#else\n  #define IMPORT_DLL\n#endif\n\n")
795  ks=classdefs.keys()
796  ks.sort()
797  for type in ks:
798
799    if not classdefs[type].imported:
800      externsfile.write("extern %s_API TOrangeType PyOr%s_Type;\n" % (modulename.upper(), type))
801    else:
802      externsfile.write("extern IMPORT_DLL TOrangeType PyOr%s_Type;\n" % type)
803
804    externsfile.write('#define PyOr%s_Check(op) PyObject_TypeCheck(op, (PyTypeObject *)&PyOr%s_Type)\n' % (type, type))
805    if classdefs[type].datastructure == "TPyOrange":
806      externsfile.write('#define PyOrange_As%s(op) (*(GCPtr< T%s > *)(void *)(&PyOrange_AS_Orange(op)))\n' % (type, type))
807      externsfile.write('\n')
808
809  classdefi=classdefs.items()
810  classdefi.sort(lambda x,y:cmp(x[0],y[0]))
811  externsfile.write("#if defined(%s_EXPORTS) || !defined(_MSC_VER)\n\n" % modulename.upper()) 
812  for (type, fields) in classdefi:
813    if fields.datastructure == "TPyOrange":
814      if not fields.imported: 
815        externsfile.write("  int cc_func_"+type+"(PyObject *, void *);\n")
816        externsfile.write("  int ccn_func_"+type+"(PyObject *, void *);\n")
817        externsfile.write("  #define cc_%s cc_func_%s\n" % (type, type))
818        externsfile.write("  #define ccn_%s ccn_func_%s\n\n" % (type, type))
819      else:
820        externsfile.write("  #define cc_%s PyOr%s_Type.ot_converter\n" % (type, type))
821        externsfile.write("  #define ccn_%s PyOr%s_Type.ot_nconverter\n\n" % (type, type))
822  externsfile.write("#else\n\n")
823  for (type, fields) in classdefi:
824    if not fields.imported and fields.datastructure == "TPyOrange":
825      externsfile.write("  #define cc_%s PyOr%s_Type.ot_converter\n" % (type, type))
826      externsfile.write("  #define ccn_%s PyOr%s_Type.ot_nconverter\n\n" % (type, type))
827  externsfile.write("#endif\n")
828
829  externsfile.write("\n\n") 
830
831  externsfile.close()
832
833
834def writeInitialization(functions, constants):
835  functionsfile=open("px/initialization.px.new", "wt")
836  newfiles.append("initialization.px")
837  functionsfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
838  functionsfile.write('#include "externs.px"\n\n')
839
840  myclasses = dict(filter(lambda x:not x[1].imported, classdefs.items()))
841
842  classconstants = [(type, fields.subconstants) for type, fields in myclasses.items() if fields.subconstants]
843  if classconstants:
844    functions["__pickleLoaderNamedConstants"] = FunctionDefinition(cname="__pickleLoaderNamedConstants", argkw="METH_VARARGS", arguments="")
845   
846  if len(functions):
847    olist=functions.keys()
848    olist.sort()
849    for functionname in olist:
850      function=functions[functionname]
851      if function.definition:
852        functionsfile.write(function.definition+";\n")
853      else:
854        if keywargsdef.search(function.argkw):
855          functionsfile.write("PyObject *"+function.cname+"(PyObject *, PyObject *, PyObject *);\n")
856        else:
857          functionsfile.write("PyObject *"+function.cname+"(PyObject *, PyObject *);\n")
858  else:
859    olist = []
860
861  printV1NoNL("\nFunctions:")
862  functionsfile.write("\n\nPyMethodDef %sFunctions[]={\n" % modulename)
863  for functionname in olist:
864    function=functions[functionname]
865    printV1NoNL(functionname)
866    if function.arguments:
867      functionsfile.write('     {"'+functionname+'", (binaryfunc)'+function.cname+', '+function.argkw+', "'+function.arguments+'"},\n')
868    else:
869      functionsfile.write('     {"'+functionname+'", (binaryfunc)'+function.cname+', '+function.argkw+'},\n')
870  functionsfile.write("     {NULL, NULL}\n};\n\n")
871  printV1()
872   
873
874  olist=constants.keys()
875  olist.sort()
876
877  for constantname in olist:
878    constant=constants[constantname]
879    if constant.cfunc:
880      functionsfile.write("PyObject *"+constant.cfunc+"();\n")
881
882  addconstscalls = ""
883  if len(myclasses):
884    ks=myclasses.keys()
885    ks.sort()
886    printV1NoNL("\nClasses:")
887    functionsfile.write("int noOf%sClasses=%i;\n\n" % (modulename, len(ks)))
888    functionsfile.write("TOrangeType *%sClasses[]={\n" % modulename)
889    for i in ks:
890      functionsfile.write("    &PyOr%s_Type,\n" % i)
891      printV1NoNL(i)
892    functionsfile.write("    NULL};\n\n")
893    printV1()
894
895    for i in ks:
896      if classdefs[i].constants:
897        functionsfile.write('\nvoid %s_addConstants();' % i)
898        addconstscalls += ('     %s_addConstants();\n' % i)
899  functionsfile.write("\n")
900
901  printV1NoNL("\nConstants:")
902  if classconstants:
903    for type, subconstants in classconstants:
904      for constname in subconstants:
905        functionsfile.write('extern PyTypeObject Py%s_Type;\n' % (type+"_"+constname))
906
907    functionsfile.write("\nTNamedConstantRecord %sNamedConstants[] = {\n" % modulename)
908    for type, subconstants in classconstants:
909      for constname in subconstants:
910        functionsfile.write('    {"%s_%s", &Py%s_%s_Type},\n' % (type, constname, type, constname))
911    functionsfile.write('    {NULL, NULL}\n};\n\n')
912    functionsfile.write("PyObject *__pickleLoaderNamedConstants(PyObject *, PyObject *args)\n{ return unpickleConstant(%sNamedConstants, args); }\n\n" % modulename)
913   
914
915  functionsfile.write("\nvoid add%sConstants(PyObject *mod) {\n" % modulename)
916  if olist:
917    for constantname in olist:
918      constant=constants[constantname]
919      printV1NoNL(constantname)
920      if constant.cfunc:
921        functionsfile.write('     PyModule_AddObject(mod, "'+constantname+'", '+constant.cfunc+'());\n')
922      else:
923        functionsfile.write('     PyModule_AddObject(mod, "'+constantname+'", '+constant.ccode+');\n')
924    functionsfile.write("\n\n")
925
926  if addconstscalls:
927    functionsfile.write(addconstscalls + "\n\n")
928
929  if len(myclasses):
930    for classname in ks:
931      if not classdefs[i].hidden:
932        functionsfile.write('     PyModule_AddObject(mod, "%s", (PyObject *)&PyOr%s_Type);\n' % (classname, classname))
933
934  for type, fields in myclasses.items():
935      if fields.subconstants:
936        for constname in fields.subconstants:
937          functionsfile.write('\n     PyType_Ready(&Py%(wholename)s_Type);\n     Py%(wholename)s_Type.tp_print = 0;\n' %
938                              {"wholename": type+"_"+constname, "classname": type, "constname": constname})
939
940  functionsfile.write("}\n\n")
941
942  printV1("\n")
943
944  functionsfile.write("""
945#ifdef _MSC_VER
946  #define WIN32_LEAN_AND_MEAN
947  #include <windows.h>
948  BOOL APIENTRY DllMain( HANDLE, DWORD  ul_reason_for_call, LPVOID)  { return TRUE; }
949#endif
950
951extern %(MODULENAME)s_API PyObject *%(modulename)sModule;
952
953ORANGE_API void addClassList(TOrangeType **);
954
955extern "C" %(MODULENAME)s_API void init%(modulename)s()
956{
957  if (!init%(modulename)sExceptions())
958    return;
959""" % {"modulename" : modulename, "MODULENAME": modulename.upper()})
960
961  if len(myclasses):
962    functionsfile.write("""
963  for(TOrangeType **type=%(modulename)sClasses; *type; type++)
964    if (PyType_Ready((PyTypeObject *)*type)<0)
965      return;
966  addClassList(%(modulename)sClasses);
967""" % {"modulename" : modulename})
968
969  functionsfile.write("""
970  gc%(modulename)sUnsafeStaticInitialization();
971  %(modulename)sModule = Py_InitModule("%(modulename)s", %(modulename)sFunctions); 
972  add%(modulename)sConstants(%(modulename)sModule);
973}
974""" % {"modulename" : modulename, "MODULENAME": modulename.upper()})
975
976  functionsfile.close()
977
978
979def writeGlobals():
980  newfiles.append("%s_globals.hpp" % modulename)
981
982  globalsfile = file("px/%s_globals.hpp.new" % modulename, "wt")
983  globalsfile.write(r"""/* This file was generated by pyxtract \n   Do not edit.*/
984
985#ifdef _MSC_VER
986    #define %(MODULENAME)s_EXTERN
987
988    #ifdef %(MODULENAME)s_EXPORTS
989        #define %(MODULENAME)s_API __declspec(dllexport)
990
991    #else
992        #define %(MODULENAME)s_API __declspec(dllimport)
993        #ifdef _DEBUG
994            #pragma comment(lib, "%(modulename)s_d.lib")
995        #else
996            #pragma comment(lib, "%(modulename)s.lib")
997        #endif
998
999    #endif // exports
1000
1001    #define %(MODULENAME)s_VWRAPPER(x) \
1002        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API T##x; \
1003        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1004        typedef GCPtr< T##x > P##x;
1005   
1006    #define %(MODULENAME)s_WRAPPER(x) \
1007        class %(MODULENAME)s_API T##x; \
1008        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1009        typedef GCPtr< T##x > P##x;
1010
1011#else
1012#ifdef DARWIN
1013    #define %(MODULENAME)s_API
1014   
1015    #ifdef %(MODULENAME)s_EXPORTS
1016        #define %(MODULENAME)s_EXTERN
1017    #else
1018        #define %(MODULENAME)s_EXTERN extern
1019    #endif
1020
1021    #define %(MODULENAME)s_VWRAPPER(x) \
1022        typedef GCPtr< T##x > P##x;
1023 
1024    #define %(MODULENAME)s_WRAPPER(x) \
1025        class %(MODULENAME)s_API T##x; \
1026        typedef GCPtr< T##x > P##x;
1027
1028#else // not _MSC_VER
1029    #define %(MODULENAME)s_API
1030
1031    #ifdef %(MODULENAME)s_EXPORTS
1032        #define %(MODULENAME)s_EXTERN
1033    #else
1034        #define %(MODULENAME)s_EXTERN extern
1035    #endif
1036
1037    #define %(MODULENAME)s_VWRAPPER(x) \
1038        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API T##x; \
1039        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1040        typedef GCPtr< T##x > P##x;
1041   
1042    #define %(MODULENAME)s_WRAPPER(x) \
1043        class %(MODULENAME)s_API T##x; \
1044        typedef GCPtr< T##x > P##x;
1045
1046#endif
1047#endif
1048"""
1049 % {"modulename": modulename, "MODULENAME": modulename.upper()})
1050
1051  if wrapper_shortcut != None:
1052    globalsfile.write("""
1053#define %(SHORTCUT)sVWRAPPER %(MODULENAME)s_VWRAPPER
1054#define %(SHORTCUT)sWRAPPER %(MODULENAME)s_WRAPPER
1055""" % {"SHORTCUT": wrapper_shortcut, "MODULENAME": modulename.upper()})
1056
1057def samefiles(n1, n2):
1058  f1, f2 = open(n1, "rt"), open(n2, "rt")
1059  same = (f1.readlines()==f2.readlines())
1060  f1.close()
1061  f2.close()
1062  return same
1063 
1064def renewfiles(newfiles):
1065  for i in newfiles:
1066    oldexists=os.path.isfile("px/"+i)
1067    if recreate or not oldexists or not samefiles("px/"+i, "px/"+i+".new"):
1068      if oldexists:
1069        os.remove("px/"+i)
1070        printNQ("Renewing %s" % i)
1071      else:
1072        printNQ("Creating %s" % i)
1073      os.rename("px/"+i+".new", "px/"+i)
1074    else:
1075      os.remove("px/"+i+".new")
1076      printV1("Keeping %s", i)
1077
1078
1079#args=sys.argv[1:]
1080
1081
1082def make():
1083  if not os.path.isdir("px"):
1084    os.mkdir("px")
1085  writeAppendices(classdefs)
1086  writeExterns()
1087  writeInitialization(functions, constants)
1088  writeGlobals()
1089  renewfiles(newfiles)
1090
1091  f=open("px/stamp", "wt")
1092  pickle.dump(classdefs, f)
1093  pickle.dump(functions, f)
1094  pickle.dump(constants, f)
1095  f.close()
1096 
1097
1098def listOfExports():
1099  for name, c in classdefs.items():
1100    print "Class '%s', derived from %s" % (name, getattr(c, "basetype", "none (or unknown)"))
1101    if getattr(c, "constructor", None):
1102      print "\tConstructor visible from Python: %s" % c.constructor.arguments
1103    if getattr(c, "call", None):
1104      print "\tCallable from Python: %s" % c.call.arguments
1105    properties = ", ".join(getattr(c, "builtinproperties", {}).keys()) + ", ".join(getattr(c, "properties", {}).keys())
1106    if hasattr(c, "getattr"):
1107      if hasattr(c, "setattr"):
1108        print "\tSpecialized getattr and setattr"
1109      else:
1110        print "\tSpecialized getattr"
1111    elif hasattr(c, "setattr"):
1112        print "\tSpecialized setattr"
1113    if len(properties):
1114      print "\tProperties: %s" % reduce(lambda x, y: x+", "+y, properties)
1115    print
1116
1117  print "\n\n\nFunctions"
1118  for func in functions:
1119    print "%s %s" % (func[0], func[-1])
1120
1121  print "\n\n\nConstants"
1122  for cons in constants:
1123    print "%s" % cons[0]
1124
1125
1126def listNode(name, hier, level):
1127  print "     "*level + name
1128  for child in sorted(hier.get(name, [])):
1129    listNode(child, hier, level+1)
1130   
1131def listOfClasses():
1132  hier = {}
1133  for name, c in classdefs.items():
1134    base = getattr(c, "basetype", None)
1135    if base:
1136      if not base in hier:
1137        hier[base] = []
1138      hier[base].append(name)
1139  listNode("Orange", hier, 0)
1140  for name, c in classdefs.items():
1141    if not getattr(c, "basetype", None) or c.basetype=="ROOT":
1142      listNode(name, hier, 0)
1143     
1144   
1145 
1146
1147def saferemove(fname):
1148  if os.path.isfile(fname):
1149    os.remove(fname)
1150   
1151def removeFiles():
1152  print "Removing externs.px, initialization.px,"
1153  saferemove("externs.px")
1154  saferemove("initialization.px")
1155
1156  for filename in filenames:
1157    found=filenamedef.match(filename)
1158    if found:
1159      filestem=found.group("stem")
1160    else:
1161      filestem=filename
1162    print "%s," % (filestem+".px"),
1163    saferemove(filestem+".px")
1164
1165
1166def readArguments(args):
1167  global filenames, verbose, recreate, action, libraries, modulename, wrapper_shortcut, quiet
1168  filenames, libraries, verbose, recreate, modulename, wrapper_shortcut = [], [], 0, 0, "", None
1169  action, quiet = [], 0
1170  i=0
1171  while(i<len(args)):
1172    if args[i][0]=="-":
1173      opt=args[i][1:]
1174      if opt=="q":
1175        quiet = 1
1176      elif opt=="v":
1177        verbose=1
1178      elif opt=="V":
1179        verbose=2
1180      elif opt=="r":
1181        recreate=1
1182      elif opt=="c":
1183        action.append("clean")
1184      elif opt=="m":
1185        action.append("make")
1186      elif opt=="i":
1187        action.append("list")
1188      elif opt=="e":
1189        action.append("hierarchy")
1190      elif opt=="l":
1191        i=i+1
1192        libraries.append(args[i])
1193      elif opt=="n":
1194        i=i+1
1195        modulename = args[i].lower()
1196      elif opt=="d":
1197        import os
1198        i+=1
1199        os.chdir(args[i])
1200      elif opt=="w":
1201        i+=1
1202        wrapper_shortcut = args[i]
1203      else:
1204        print "Unrecognized option %s" % args[i]
1205    else:
1206      if not "pyxtract.py" in args[i]:
1207        filenames.append(args[i])
1208    i=i+1
1209
1210  if not modulename:
1211    print "Module name (-n) missing"
1212    sys.exit()
1213  if not len(action):
1214    action=["make"]
1215
1216def printNQ(str):
1217  if not quiet:
1218    print str
1219   
1220def printV0(str="", tup=(), printLine = True):
1221  if printLine:
1222    print "%20s:%4i:" % (parsedFile, lineno),
1223  print str % tup
1224
1225def printV2(str="", tup=(), printLine = True):
1226  if verbose==2:
1227    printV0(str, tup, printLine)
1228   
1229def printV1(str="", tup=(), printLine = True):
1230  if verbose>=1:
1231    printV0(str, tup, printLine)
1232
1233def printV1NoNL(str="", tup=()):
1234  if verbose>=1:
1235    print str % tup,
1236       
1237args = sys.argv
1238
1239readArguments(args)
1240parsedFile=""
1241
1242if action.count("clean"):
1243  removeFiles()
1244  action.remove("clean")
1245
1246if len(action):
1247  pyprops = pickle.load(open("../orange/ppp/stamp", "rt")) #home dir on linux is different from windows; changed ppp/stamp to ../orange/ppp/stamp
1248  newfiles=[]
1249  functions, constants, classdefs, aliases = parseFiles()
1250   
1251  if action.count("list"):
1252    listOfExports()
1253  if action.count("hierarchy"):
1254    listOfClasses()
1255  if action.count("make"):
1256    make()
1257
1258
1259
1260
Note: See TracBrowser for help on using the repository browser.