source: orange/source/pyxtract/pyxtract.py @ 11338:2006c70024f2

Revision 11338:2006c70024f2, 48.1 KB checked in by astaric, 14 months ago (diff)

Fixes for compiling with clang.

export CPPFLAGS=-Wno-address-of-temporary should no longer be needed.

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", "lenfunc"),
80                ("concat", "sq_concat", "binaryfunc"),
81                ("repeat", "sq_repeat", "ssizeargfunc"),
82                ("getitem_sq", "sq_item", "ssizeargfunc"),
83                ("getslice", "sq_slice", "ssizessizeargfunc"),
84                ("setitem_sq", "sq_ass_item", "ssizeobjargproc"),
85                ("setslice", "sq_ass_slice", "ssizessizeobjargproc"),
86                ("contains", "sq_contains", "objobjproc")
87                ]
88
89  specialmappingmethods=[
90                ("len", "mp_length", "lenfunc"),
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    displayname = getattr(fields, "displayname", "Orange.core."+type) # was: <modulename>.<type>
749    outfile.write('  "%s",\n' % displayname)
750    outfile.write('  sizeof(%s), 0,\n' % fields.datastructure)
751    innulls=writeslots(specialmethods, 1)
752    outfile.write((innulls and '\n' or '') + '};\n\n')
753
754    if fields.datastructure == "TPyOrange":
755      outfile.write(cc_functions % {"type": type})
756
757    outfile.write('%(modulename)s_API TOrangeType PyOr%(type)s_Type (PyOr%(type)s_Type_inh, typeid(T%(type)s)' % {"modulename": modulename.upper(), "type": type})
758    outfile.write(', ' + (fields.constructor and fields.constructor.type!="MANUAL" and type+'_default_constructor' or '0'))
759    if fields.datastructure == "TPyOrange":
760      outfile.write(', cc_%s, ccn_%s' % (type, type))
761    else:
762      outfile.write(', PyOr_noConversion, PyOr_noConversion')
763    outfile.write(', ' + (fields.constructor_keywords and type+'_constructor_keywords' or 'NULL'))
764    outfile.write(', ' + (fields.constructor and fields.constructor.allows_empty_args and 'true' or 'false'))
765    outfile.write(', ' + (fields.recognized_attributes and type+'_recognized_attributes' or 'NULL'))
766    outfile.write(', ' + (aliases.has_key(type) and type+'_aliases' or 'NULL'))
767    outfile.write(');\n\n\n\n')
768
769    if not (fields.abstract or fields.constructor and fields.constructor.allows_empty_args or fields.methods.has_key("__reduce__")):
770      printV0("Warning: class '%s' will not be picklable", type, False)
771     
772  outfile.close()
773
774
775def writeDisplayNames(filename, classdefs):
776  outfile = open("px/%s.new" % filename, "wt")
777  newfiles.append(filename)
778  for classname, fields in classdefs.items():
779    if hasattr(fields, "displayname"):
780        outfile.write('%s\t%s\n' % (classname, fields.displayname))
781
782
783def writeAppendices(classdefs):
784  filenamedef=re.compile(r"(?P<stem>.*)\.\w*$")
785  for filename in filenames:
786    found=filenamedef.match(filename)
787    if found:
788      filestem=found.group("stem")
789    else:
790      filestem=filename
791    writeAppendix(filename, filestem+".px", classdefs, aliases)
792    printV1()
793
794def writeExterns():
795  externsfile=open("px/externs.px.new", "wt")
796  newfiles.append("externs.px")
797
798  externsfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
799
800  externsfile.write("#ifdef _MSC_VER\n  #define IMPORT_DLL __declspec(dllimport)\n#else\n  #define IMPORT_DLL\n#endif\n\n")
801  ks=classdefs.keys()
802  ks.sort()
803  for type in ks:
804
805    if not classdefs[type].imported:
806      externsfile.write("extern %s_API TOrangeType PyOr%s_Type;\n" % (modulename.upper(), type))
807    else:
808      externsfile.write("extern IMPORT_DLL TOrangeType PyOr%s_Type;\n" % type)
809
810    externsfile.write('#define PyOr%s_Check(op) PyObject_TypeCheck(op, (PyTypeObject *)&PyOr%s_Type)\n' % (type, type))
811    if classdefs[type].datastructure == "TPyOrange":
812      externsfile.write('#define PyOrange_As%s(op) (static_cast<GCPtr< T%s > >(PyOrange_AS_Orange(op)))\n' % (type, type))
813      externsfile.write('\n')
814
815  classdefi=classdefs.items()
816  classdefi.sort(lambda x,y:cmp(x[0],y[0]))
817  externsfile.write("#if defined(%s_EXPORTS) || !defined(_MSC_VER)\n\n" % modulename.upper()) 
818  for (type, fields) in classdefi:
819    if fields.datastructure == "TPyOrange":
820      if not fields.imported: 
821        externsfile.write("  int cc_func_"+type+"(PyObject *, void *);\n")
822        externsfile.write("  int ccn_func_"+type+"(PyObject *, void *);\n")
823        externsfile.write("  #define cc_%s cc_func_%s\n" % (type, type))
824        externsfile.write("  #define ccn_%s ccn_func_%s\n\n" % (type, type))
825      else:
826        externsfile.write("  #define cc_%s PyOr%s_Type.ot_converter\n" % (type, type))
827        externsfile.write("  #define ccn_%s PyOr%s_Type.ot_nconverter\n\n" % (type, type))
828  externsfile.write("#else\n\n")
829  for (type, fields) in classdefi:
830    if not fields.imported and fields.datastructure == "TPyOrange":
831      externsfile.write("  #define cc_%s PyOr%s_Type.ot_converter\n" % (type, type))
832      externsfile.write("  #define ccn_%s PyOr%s_Type.ot_nconverter\n\n" % (type, type))
833  externsfile.write("#endif\n")
834
835  externsfile.write("\n\n") 
836
837  externsfile.close()
838
839
840def writeInitialization(functions, constants):
841  functionsfile=open("px/initialization.px.new", "wt")
842  newfiles.append("initialization.px")
843  functionsfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
844  functionsfile.write('#include "externs.px"\n\n')
845
846  myclasses = dict(filter(lambda x:not x[1].imported, classdefs.items()))
847
848  classconstants = [(type, fields.subconstants) for type, fields in myclasses.items() if fields.subconstants]
849  if classconstants:
850    functions["__pickleLoaderNamedConstants"] = FunctionDefinition(cname="__pickleLoaderNamedConstants", argkw="METH_VARARGS", arguments="")
851   
852  if len(functions):
853    olist=functions.keys()
854    olist.sort()
855    for functionname in olist:
856      function=functions[functionname]
857      if function.definition:
858        functionsfile.write(function.definition+";\n")
859      else:
860        if keywargsdef.search(function.argkw):
861          functionsfile.write("PyObject *"+function.cname+"(PyObject *, PyObject *, PyObject *);\n")
862        else:
863          functionsfile.write("PyObject *"+function.cname+"(PyObject *, PyObject *);\n")
864  else:
865    olist = []
866
867  printV1NoNL("\nFunctions:")
868  functionsfile.write("\n\nPyMethodDef %sFunctions[]={\n" % modulename)
869  for functionname in olist:
870    function=functions[functionname]
871    printV1NoNL(functionname)
872    if function.arguments:
873      functionsfile.write('     {"'+functionname+'", (binaryfunc)'+function.cname+', '+function.argkw+', "'+function.arguments+'"},\n')
874    else:
875      functionsfile.write('     {"'+functionname+'", (binaryfunc)'+function.cname+', '+function.argkw+'},\n')
876  functionsfile.write("     {NULL, NULL}\n};\n\n")
877  printV1()
878   
879
880  olist=constants.keys()
881  olist.sort()
882
883  for constantname in olist:
884    constant=constants[constantname]
885    if constant.cfunc:
886      functionsfile.write("PyObject *"+constant.cfunc+"();\n")
887
888  addconstscalls = ""
889  if len(myclasses):
890    ks=myclasses.keys()
891    ks.sort()
892    printV1NoNL("\nClasses:")
893    functionsfile.write("int noOf%sClasses=%i;\n\n" % (modulename, len(ks)))
894    functionsfile.write("TOrangeType *%sClasses[]={\n" % modulename)
895    for i in ks:
896      functionsfile.write("    &PyOr%s_Type,\n" % i)
897      printV1NoNL(i)
898    functionsfile.write("    NULL};\n\n")
899    printV1()
900
901    for i in ks:
902      if classdefs[i].constants:
903        functionsfile.write('\nvoid %s_addConstants();' % i)
904        addconstscalls += ('     %s_addConstants();\n' % i)
905  functionsfile.write("\n")
906
907  printV1NoNL("\nConstants:")
908  if classconstants:
909    for type, subconstants in classconstants:
910      for constname in subconstants:
911        functionsfile.write('extern PyTypeObject Py%s_Type;\n' % (type+"_"+constname))
912
913    functionsfile.write("\nTNamedConstantRecord %sNamedConstants[] = {\n" % modulename)
914    for type, subconstants in classconstants:
915      for constname in subconstants:
916        functionsfile.write('    {"%s_%s", &Py%s_%s_Type},\n' % (type, constname, type, constname))
917    functionsfile.write('    {NULL, NULL}\n};\n\n')
918    functionsfile.write("PyObject *__pickleLoaderNamedConstants(PyObject *, PyObject *args)\n{ return unpickleConstant(%sNamedConstants, args); }\n\n" % modulename)
919   
920
921  functionsfile.write("\nvoid add%sConstants(PyObject *mod) {\n" % modulename)
922  if olist:
923    for constantname in olist:
924      constant=constants[constantname]
925      printV1NoNL(constantname)
926      if constant.cfunc:
927        functionsfile.write('     PyModule_AddObject(mod, "'+constantname+'", '+constant.cfunc+'());\n')
928      else:
929        functionsfile.write('     PyModule_AddObject(mod, "'+constantname+'", '+constant.ccode+');\n')
930    functionsfile.write("\n\n")
931
932  if addconstscalls:
933    functionsfile.write(addconstscalls + "\n\n")
934
935  if len(myclasses):
936    for classname in ks:
937      exportedname = "OrangeBase" if classname=="Orange" else classname
938      if not classdefs[i].hidden:
939        functionsfile.write('     PyModule_AddObject(mod, "%s", ' \
940                            '(PyObject *)&PyOr%s_Type);\n' %
941                            (exportedname, classname))
942
943  for type, fields in myclasses.items():
944      if fields.subconstants:
945        for constname in fields.subconstants:
946          functionsfile.write('\n     PyType_Ready(&Py%(wholename)s_Type);\n     Py%(wholename)s_Type.tp_print = 0;\n' %
947                              {"wholename": type+"_"+constname, "classname": type, "constname": constname})
948
949  functionsfile.write("}\n\n")
950
951  printV1("\n")
952
953  functionsfile.write("""
954#ifdef _MSC_VER
955  #define WIN32_LEAN_AND_MEAN
956  #include <windows.h>
957  BOOL APIENTRY DllMain( HANDLE, DWORD  ul_reason_for_call, LPVOID)  { return TRUE; }
958#endif
959
960extern %(MODULENAME)s_API PyObject *%(modulename)sModule;
961
962ORANGE_API void addClassList(TOrangeType **);
963
964extern "C" %(MODULENAME)s_API void init%(modulename)s()
965{
966  if (!init%(modulename)sExceptions())
967    return;
968""" % {"modulename" : modulename, "MODULENAME": modulename.upper()})
969
970  if len(myclasses):
971    functionsfile.write("""
972  for(TOrangeType **type=%(modulename)sClasses; *type; type++)
973    if (PyType_Ready((PyTypeObject *)*type)<0)
974      return;
975  addClassList(%(modulename)sClasses);
976""" % {"modulename" : modulename})
977
978  functionsfile.write("""
979  gc%(modulename)sUnsafeStaticInitialization();
980  %(modulename)sModule = Py_InitModule("%(modulename)s", %(modulename)sFunctions); 
981  add%(modulename)sConstants(%(modulename)sModule);
982}
983""" % {"modulename" : modulename, "MODULENAME": modulename.upper()})
984
985  functionsfile.close()
986
987
988def writeGlobals():
989  newfiles.append("%s_globals.hpp" % modulename)
990
991  globalsfile = file("px/%s_globals.hpp.new" % modulename, "wt")
992  globalsfile.write(r"""/* This file was generated by pyxtract \n   Do not edit.*/
993
994#ifdef _MSC_VER
995    #define %(MODULENAME)s_EXTERN
996
997    #ifdef %(MODULENAME)s_EXPORTS
998        #define %(MODULENAME)s_API __declspec(dllexport)
999
1000    #else
1001        #define %(MODULENAME)s_API __declspec(dllimport)
1002        #ifdef _DEBUG
1003            #pragma comment(lib, "%(modulename)s_d.lib")
1004        #else
1005            #pragma comment(lib, "%(modulename)s.lib")
1006        #endif
1007
1008    #endif // exports
1009
1010    #define %(MODULENAME)s_VWRAPPER(x) \
1011        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API T##x; \
1012        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1013        typedef GCPtr< T##x > P##x;
1014   
1015    #define %(MODULENAME)s_WRAPPER(x) \
1016        class %(MODULENAME)s_API T##x; \
1017        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1018        typedef GCPtr< T##x > P##x;
1019
1020#else
1021#ifdef DARWIN
1022    #define %(MODULENAME)s_API
1023   
1024    #ifdef %(MODULENAME)s_EXPORTS
1025        #define %(MODULENAME)s_EXTERN
1026    #else
1027        #define %(MODULENAME)s_EXTERN extern
1028    #endif
1029
1030    #define %(MODULENAME)s_VWRAPPER(x) \
1031        typedef GCPtr< T##x > P##x;
1032 
1033    #define %(MODULENAME)s_WRAPPER(x) \
1034        class %(MODULENAME)s_API T##x; \
1035        typedef GCPtr< T##x > P##x;
1036
1037#else // not _MSC_VER
1038    #define %(MODULENAME)s_API
1039
1040    #ifdef %(MODULENAME)s_EXPORTS
1041        #define %(MODULENAME)s_EXTERN
1042    #else
1043        #define %(MODULENAME)s_EXTERN extern
1044    #endif
1045
1046    #define %(MODULENAME)s_VWRAPPER(x) \
1047        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API T##x; \
1048        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1049        typedef GCPtr< T##x > P##x;
1050   
1051    #define %(MODULENAME)s_WRAPPER(x) \
1052        class %(MODULENAME)s_API T##x; \
1053        typedef GCPtr< T##x > P##x;
1054
1055#endif
1056#endif
1057"""
1058 % {"modulename": modulename, "MODULENAME": modulename.upper()})
1059
1060  if wrapper_shortcut != None:
1061    globalsfile.write("""
1062#define %(SHORTCUT)sVWRAPPER %(MODULENAME)s_VWRAPPER
1063#define %(SHORTCUT)sWRAPPER %(MODULENAME)s_WRAPPER
1064""" % {"SHORTCUT": wrapper_shortcut, "MODULENAME": modulename.upper()})
1065
1066def samefiles(n1, n2):
1067  f1, f2 = open(n1, "rt"), open(n2, "rt")
1068  same = (f1.readlines()==f2.readlines())
1069  f1.close()
1070  f2.close()
1071  return same
1072 
1073def renewfiles(newfiles):
1074  for i in newfiles:
1075    oldexists=os.path.isfile("px/"+i)
1076    if recreate or not oldexists or not samefiles("px/"+i, "px/"+i+".new"):
1077      if oldexists:
1078        os.remove("px/"+i)
1079        printNQ("Renewing %s" % i)
1080      else:
1081        printNQ("Creating %s" % i)
1082      os.rename("px/"+i+".new", "px/"+i)
1083    else:
1084      os.remove("px/"+i+".new")
1085      printV1("Keeping %s", i)
1086
1087
1088#args=sys.argv[1:]
1089
1090
1091def make():
1092  if not os.path.isdir("px"):
1093    os.mkdir("px")
1094  writeAppendices(classdefs)
1095  writeDisplayNames("displaynames", classdefs)
1096  writeExterns()
1097  writeInitialization(functions, constants)
1098  writeGlobals()
1099  renewfiles(newfiles)
1100
1101  f=open("px/stamp", "wt")
1102  pickle.dump(classdefs, f)
1103  pickle.dump(functions, f)
1104  pickle.dump(constants, f)
1105  f.close()
1106 
1107
1108def listOfExports():
1109  for name, c in classdefs.items():
1110    print "Class '%s', derived from %s" % (name, getattr(c, "basetype", "none (or unknown)"))
1111    if getattr(c, "constructor", None):
1112      print "\tConstructor visible from Python: %s" % c.constructor.arguments
1113    if getattr(c, "call", None):
1114      print "\tCallable from Python: %s" % c.call.arguments
1115    properties = ", ".join(getattr(c, "builtinproperties", {}).keys()) + ", ".join(getattr(c, "properties", {}).keys())
1116    if hasattr(c, "getattr"):
1117      if hasattr(c, "setattr"):
1118        print "\tSpecialized getattr and setattr"
1119      else:
1120        print "\tSpecialized getattr"
1121    elif hasattr(c, "setattr"):
1122        print "\tSpecialized setattr"
1123    if len(properties):
1124      print "\tProperties: %s" % reduce(lambda x, y: x+", "+y, properties)
1125    print
1126
1127  print "\n\n\nFunctions"
1128  for func in functions:
1129    print "%s %s" % (func[0], func[-1])
1130
1131  print "\n\n\nConstants"
1132  for cons in constants:
1133    print "%s" % cons[0]
1134
1135
1136def listNode(name, hier, level):
1137  print "     "*level + name
1138  for child in sorted(hier.get(name, [])):
1139    listNode(child, hier, level+1)
1140   
1141def listOfClasses():
1142  hier = {}
1143  for name, c in classdefs.items():
1144    base = getattr(c, "basetype", None)
1145    if base:
1146      if not base in hier:
1147        hier[base] = []
1148      hier[base].append(name)
1149  listNode("Orange", hier, 0)
1150  for name, c in classdefs.items():
1151    if not getattr(c, "basetype", None) or c.basetype=="ROOT":
1152      listNode(name, hier, 0)
1153     
1154   
1155 
1156
1157def saferemove(fname):
1158  if os.path.isfile(fname):
1159    os.remove(fname)
1160   
1161def removeFiles():
1162  print "Removing externs.px, initialization.px,"
1163  saferemove("externs.px")
1164  saferemove("initialization.px")
1165
1166  for filename in filenames:
1167    found=filenamedef.match(filename)
1168    if found:
1169      filestem=found.group("stem")
1170    else:
1171      filestem=filename
1172    print "%s," % (filestem+".px"),
1173    saferemove(filestem+".px")
1174
1175
1176def readArguments(args):
1177  global filenames, verbose, recreate, action, libraries, modulename, wrapper_shortcut, quiet
1178  filenames, libraries, verbose, recreate, modulename, wrapper_shortcut = [], [], 0, 0, "", None
1179  action, quiet = [], 0
1180  i=0
1181  while(i<len(args)):
1182    if args[i][0]=="-":
1183      opt=args[i][1:]
1184      if opt=="q":
1185        quiet = 1
1186      elif opt=="v":
1187        verbose=1
1188      elif opt=="V":
1189        verbose=2
1190      elif opt=="r":
1191        recreate=1
1192      elif opt=="c":
1193        action.append("clean")
1194      elif opt=="m":
1195        action.append("make")
1196      elif opt=="i":
1197        action.append("list")
1198      elif opt=="e":
1199        action.append("hierarchy")
1200      elif opt=="l":
1201        i=i+1
1202        libraries.append(args[i])
1203      elif opt=="n":
1204        i=i+1
1205        modulename = args[i].lower()
1206      elif opt=="d":
1207        import os
1208        i+=1
1209        os.chdir(args[i])
1210      elif opt=="w":
1211        i+=1
1212        wrapper_shortcut = args[i]
1213      else:
1214        print "Unrecognized option %s" % args[i]
1215    else:
1216      if not "pyxtract.py" in args[i]:
1217        filenames.append(args[i])
1218    i=i+1
1219
1220  if not modulename:
1221    print "Module name (-n) missing"
1222    sys.exit()
1223  if not len(action):
1224    action=["make"]
1225
1226def printNQ(str):
1227  if not quiet:
1228    print str
1229   
1230def printV0(str="", tup=(), printLine = True):
1231  if printLine:
1232    print "%20s:%4i:" % (parsedFile, lineno),
1233  print str % tup
1234
1235def printV2(str="", tup=(), printLine = True):
1236  if verbose==2:
1237    printV0(str, tup, printLine)
1238   
1239def printV1(str="", tup=(), printLine = True):
1240  if verbose>=1:
1241    printV0(str, tup, printLine)
1242
1243def printV1NoNL(str="", tup=()):
1244  if verbose>=1:
1245    print str % tup,
1246       
1247args = sys.argv
1248
1249readArguments(args)
1250parsedFile=""
1251
1252if action.count("clean"):
1253  removeFiles()
1254  action.remove("clean")
1255
1256if len(action):
1257  pyprops = pickle.load(open("../orange/ppp/stamp", "rt")) #home dir on linux is different from windows; changed ppp/stamp to ../orange/ppp/stamp
1258  newfiles=[]
1259  functions, constants, classdefs, aliases = parseFiles()
1260   
1261  if action.count("list"):
1262    listOfExports()
1263  if action.count("hierarchy"):
1264    listOfClasses()
1265  if action.count("make"):
1266    make()
1267
1268
1269
1270
Note: See TracBrowser for help on using the repository browser.