source: orange/source/pyxtract/pyxtract.py @ 7704:e1ccfdd5f4e5

Revision 7704:e1ccfdd5f4e5, 47.1 KB checked in by ales_erjavec <ales.erjavec@…>, 3 years ago (diff)
  • fixed "..\_underscored" filename to "../_underscored"
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<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<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<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<doc>[^"]*)"\s*\)\s*(?P<allows_empty_args>ALLOWS_EMPTY)?')
111  basedondef=re.compile(r'BASED_ON\s*\(\s*(?P<typename>\w*)\s*,\s*(?P<basename>\w*)\s*\)')
112  hiddendef=re.compile(r'HIDDEN\s*\(\s*(?P<typename>\w*)\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=found.group("typename", "basename", "constype", "doc")
172    printV2("%s (%s): Macro constructor %s", (typename, basename, constype))
173    addClassDef(classdefs, typename, parsedFile, "basetype", basename)
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 = found.group("typename", "structurename", "dictfield")
295    addClassDef(classdefs, typename, parsedFile, "datastructure", structurename)
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 = found.group("typename", "basename", "doc")
303    allows_empty_args = bool(found.group("allows_empty_args"))
304    addClassDef(classdefs, typename, parsedFile, "basetype", basename, 0)
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 = found.group("typename", "basename")
311    addClassDef(classdefs, typename, parsedFile, "basetype", basename, 0)
312    return 1
313
314  found=hiddendef.match(line)
315  if found:
316    typename, basename = found.group("typename", "basename")
317    addClassDef(classdefs, typename, parsedFile, "basetype", basename, 0)
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
535  usedbases=usedbases.keys()
536  usedbases.sort()
537  #outfile.write("extern TOrangeType PyOrOrangeType_Type;\n")
538  for type in usedbases:
539    if type:
540      if classdefs[type].imported:
541        outfile.write("extern IMPORT_DLL TOrangeType PyOr"+type+"_Type;\n")
542      else:
543        outfile.write("extern %s_API TOrangeType PyOr%s_Type;\n" % (modulename.upper(), type))
544  outfile.write("\n\n")
545
546  for (type, fields) in classdefi:
547    if fields.infile!=filename:
548      continue
549
550    outfile.write('/* -------------- %s --------------*/\n\n' % type)
551
552    # Write PyMethodDef
553    if len(fields.methods):
554      methodnames=fields.methods.keys()
555      methodnames.sort()
556      outfile.write("PyMethodDef "+type+"_methods[] = {\n")
557      for methodname in methodnames:
558        method=fields.methods[methodname]
559        cname = method.cname[0] == "*" and method.cname[1:] or type+"_"+method.cname
560        if method.arguments:
561          outfile.write('     {"'+methodname+'", (binaryfunc)'+cname+", "+method.argkw+", \""+method.arguments+"\"},\n")
562        else:
563          outfile.write('     {"'+methodname+'", (binaryfunc)'+cname+", "+method.argkw+"},\n")
564      outfile.write("     {NULL, NULL}\n};\n\n")
565     
566
567    # Write GetSetDef
568    properties=filter(lambda (name, definition): not definition.builtin, fields.properties.items())
569    if len(properties):
570      properties.sort(lambda x,y:cmp(x[0], y[0]))
571      outfile.write("PyGetSetDef "+type+"_getset[]=  {\n")
572      for (name, definition) in properties:
573        camelname = camel2underscore(name)
574        outfile.write('  {"%s"' % camelname)
575        if definition.hasget:
576          outfile.write(", (getter)%s_get_%s" % (type, name))
577        else:
578          outfile.write(", NULL")
579        if definition.hasset:
580          outfile.write(", (setter)%s_set_%s" % (type, name))
581        else:
582          outfile.write(", NULL")
583        if definition.description:
584          outfile.write(', "'+definition.description+'"')
585        outfile.write("},\n")
586      outfile.write('  {NULL}};\n\n')
587
588    # Write doc strings
589    if fields.call and fields.call.arguments and len(fields.call.arguments):
590      outfile.write('char '+type+'[] = "'+fields.call.arguments+'";\n')
591    if fields.description:
592      outfile.write('char '+type+'_doc[] = "'+fields.description+'";\n')
593    outfile.write('\n')
594
595    if fields.subconstants:
596      for constname, constvalues in fields.subconstants.items():
597        outfile.write("""
598TNamedConstantsDef %(wholename)s_values[] = {%(valueslist)s, {0, 0}};
599static PyObject *%(wholename)s_repr(PyObject *self) { return stringFromList(self, %(wholename)s_values); }
600PyObject *%(wholename)s__reduce__(PyObject *self);
601PyMethodDef %(wholename)s_methods[] = { {"__reduce__", (binaryfunc)%(wholename)s__reduce__, METH_NOARGS, "reduce"}, {NULL, NULL}};
602PyTypeObject 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};
603PyObject *Py%(wholename)s_FromLong(long ok) { PyIntObject *r = PyObject_New(PyIntObject, &Py%(wholename)s_Type); r->ob_ival = ok; return (PyObject *)r; }
604void *PT%(wholename)s(void *l) { return Py%(wholename)s_FromLong(*(int *)l); }
605PyObject *%(wholename)s__reduce__(PyObject *self) { return Py_BuildValue("O(s(i))", getExportedFunction("__pickleLoaderNamedConstants"), "%(wholename)s", ((PyIntObject *)(self))->ob_ival); }
606
607""" % {"wholename": type+"_"+constname, "classname": type, "constname": constname, "valueslist": ", ".join('{"%s", %s}' % k for k in constvalues)})
608
609#PyObject *%(wholename)s__reduce__(PyObject *self) { return Py_BuildValue("O(i)", &PyInt_Type, ((PyIntObject *)(self))->ob_ival); }
610
611
612
613
614    # Write constants
615    if fields.constants:
616      outfile.write("void %s_addConstants()\n{ PyObject *&dict = PyOr%s_Type.ot_inherited.tp_dict;\n  if (!dict) dict = PyDict_New();\n" % (type, type))
617      for name, const in fields.constants.items():
618        if const.ccode:
619          outfile.write('  PyDict_SetItemString(dict, "%s", %s);\n' % (name, const.ccode))
620        else:
621          outfile.write('  PyDict_SetItemString(dict, "%s", %s());\n' % (name, const.cfunc))
622      outfile.write("}\n\n")
623
624    # Write default constructor
625    if fields.constructor:
626      if fields.constructor.type!="MANUAL":
627        outfile.write('POrange %s_default_constructor(PyTypeObject *type)\n{ return POrange(mlnew T%s(), type); }\n\n' % (type, type))
628    else:
629      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))
630
631    # Write constructor keywords
632    if fields.constructor_keywords:
633      outfile.write('char *%s_constructor_keywords[] = {%s, NULL};\n' % (type, reduce(lambda x, y: x + ", " + y, ['"%s"' % x for x in fields.constructor_keywords])))
634
635    if fields.recognized_attributes:
636      outfile.write('char *%s_recognized_attributes[] = {%s, NULL};\n' % (type, reduce(lambda x, y: x + ", " + y, ['"%s"' % x for x in fields.recognized_attributes])))
637     
638    outfile.write('\n')                   
639                   
640    # Write aliases   
641    if aliases.has_key(type):
642      outfile.write("TAttributeAlias "+type+"_aliases[] = {\n")
643      for alias in aliases[type]:
644        outfile.write('    {"%s", "%s"},\n' % tuple(alias))
645      outfile.write("    {NULL, NULL}};\n\n")
646   
647    # Write type object 
648
649    def hasany(methods, fields):
650      for smethod in methods:
651        if smethod[0] and fields.specialmethods.has_key(smethod[0]):
652          return 1
653      return 0
654
655    def writeslots(methods, isbase=0):
656      def write0(innulls):
657        outfile.write(innulls and ' 0,' or '  0,')
658        return 1
659
660      innulls=0
661      for smethod in methods:
662        if not smethod[0]:
663          if smethod[1]=="BASE":
664            if fields.basetype and (fields.basetype!="ROOT"):
665              name='(_typeobject *)&PyOr'+fields.basetype+'_Type,'
666              innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_base */\n' % name))
667            else:
668              innulls=write0(innulls)
669
670          elif smethod[1]=="DICTOFFSET":
671            if fields.dictfield and fields.dictfield!="0":
672              innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_dictoffset */\n' % ("offsetof(%s, %s)," % (fields.datastructure, fields.dictfield))))
673            else:
674              innulls=write0(innulls)
675
676          elif smethod[1]=="DOC":
677            innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_doc */\n' % ('"'+findConstructorDoc(classdefs, type)+'",')))
678
679          elif smethod[1]=="FLAGS":
680            fl = "Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_RICHCOMPARE"
681            for cond, flag in [(fields.specialmethods.has_key("traverse"), "Py_TPFLAGS_HAVE_GC")
682                              ]:
683              if cond:
684                fl += " | "+flag
685            innulls=outfile.write((innulls and '\n' or '') + (%s, /* tp_flags */\n' % fl))
686                       
687          else:
688            otherfields= [("as_number",    hasnumeric),
689                          ("as_sequence",  hassequence),
690                          ("as_mapping",   hasmapping),
691                          ("doc",          fields.description),
692                          ("methods",      fields.methods),
693                          ("getset",       len(properties))
694                         ] 
695                     
696            for (name, condition) in otherfields:
697              if smethod[1]==name:
698                if condition:
699                  slotcont='%s_%s,' % (type, name)
700                  if name[:3]=="as_":
701                     slotcont="&"+slotcont
702                  innulls=outfile.write((innulls and '\n' or '') + (%-50s /* tp_%s */\n' % (slotcont, name)))
703                else:
704                  innulls=write0(innulls)
705                break
706            else:
707              if len(smethod)==3:
708                if smethod[2]=='0':
709                  innulls=write0(innulls)
710                else:
711                  innulls=outfile.write((innulls and '\n' or '') + (%-50s /* %s */\n' % (smethod[2]+',', smethod[1])))
712              else:
713                raise "invalid slot name %s" % smethod[1]
714             
715        else: # smethod[0]!=""
716          if fields.specialmethods.has_key(smethod[0]):
717            innulls=outfile.write((innulls and '\n' or '') + (%-50s /* %s */\n' % ("(%s)%s_%s," % (smethod[2], type, smethod[0]), smethod[1])))
718           
719          elif smethod[0]=="new":
720            if fields.constructor:
721              innulls = outfile.write((innulls and '\n' or '') + (%-50s /* tp_new */\n' % ("(newfunc)%s," % genericconstrs[fields.constructor.type])))
722            else:
723              innulls = outfile.write((innulls and '\n' or '') + (%-50s /* tp_new */\n' % ("(newfunc)%s_abstract_constructor," % type)))
724
725          else:
726            innulls=write0(innulls)
727     
728      return innulls
729
730
731    additional=[]
732    for (subtype, submethods, subappendix) in [('PyNumberMethods', specialnumericmethods, '_as_number'),
733                                               ('PySequenceMethods', specialsequencemethods, '_as_sequence'),
734                                               ('PyMappingMethods', specialmappingmethods, '_as_mapping')]:
735      hasit = hasany(submethods, fields)
736      additional.append(hasit)
737      if hasit:
738        outfile.write(subtype+' '+type+subappendix +' = {\n')
739        innulls=writeslots(submethods, 0)
740        outfile.write((innulls and '\n' or '') + '};\n\n')
741
742    hasnumeric, hassequence, hasmapping = tuple(additional)
743
744    outfile.write('PyTypeObject PyOr'+type+'_Type_inh = {\n')
745    outfile.write('  PyObject_HEAD_INIT((_typeobject *)&PyType_Type)\n')
746    outfile.write('  0,\n')
747    outfile.write('  "%s.%s",\n' % (modulename, type))
748    outfile.write('  sizeof(%s), 0,\n' % fields.datastructure)
749    innulls=writeslots(specialmethods, 1)
750    outfile.write((innulls and '\n' or '') + '};\n\n')
751
752    if fields.datastructure == "TPyOrange":
753      outfile.write(cc_functions % {"type": type})
754
755    outfile.write('%(modulename)s_API TOrangeType PyOr%(type)s_Type (PyOr%(type)s_Type_inh, typeid(T%(type)s)' % {"modulename": modulename.upper(), "type": type})
756    outfile.write(', ' + (fields.constructor and fields.constructor.type!="MANUAL" and type+'_default_constructor' or '0'))
757    if fields.datastructure == "TPyOrange":
758      outfile.write(', cc_%s, ccn_%s' % (type, type))
759    else:
760      outfile.write(', PyOr_noConversion, PyOr_noConversion')
761    outfile.write(', ' + (fields.constructor_keywords and type+'_constructor_keywords' or 'NULL'))
762    outfile.write(', ' + (fields.constructor and fields.constructor.allows_empty_args and 'true' or 'false'))
763    outfile.write(', ' + (fields.recognized_attributes and type+'_recognized_attributes' or 'NULL'))
764    outfile.write(', ' + (aliases.has_key(type) and type+'_aliases' or 'NULL'))
765    outfile.write(');\n\n\n\n')
766
767    if not (fields.abstract or fields.constructor and fields.constructor.allows_empty_args or fields.methods.has_key("__reduce__")):
768      printV0("Warning: class '%s' will not be picklable", type, False)
769     
770  outfile.close()
771
772
773def writeAppendices(classdefs):
774  filenamedef=re.compile(r"(?P<stem>.*)\.\w*$")
775  for filename in filenames:
776    found=filenamedef.match(filename)
777    if found:
778      filestem=found.group("stem")
779    else:
780      filestem=filename
781    writeAppendix(filename, filestem+".px", classdefs, aliases)
782    printV1()
783
784def writeExterns():
785  externsfile=open("px/externs.px.new", "wt")
786  newfiles.append("externs.px")
787
788  externsfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
789
790  externsfile.write("#ifdef _MSC_VER\n  #define IMPORT_DLL __declspec(dllimport)\n#else\n  #define IMPORT_DLL\n#endif\n\n")
791  ks=classdefs.keys()
792  ks.sort()
793  for type in ks:
794
795    if not classdefs[type].imported:
796      externsfile.write("extern %s_API TOrangeType PyOr%s_Type;\n" % (modulename.upper(), type))
797    else:
798      externsfile.write("extern IMPORT_DLL TOrangeType PyOr%s_Type;\n" % type)
799
800    externsfile.write('#define PyOr%s_Check(op) PyObject_TypeCheck(op, (PyTypeObject *)&PyOr%s_Type)\n' % (type, type))
801    if classdefs[type].datastructure == "TPyOrange":
802      externsfile.write('#define PyOrange_As%s(op) (*(GCPtr< T%s > *)(void *)(&PyOrange_AS_Orange(op)))\n' % (type, type))
803      externsfile.write('\n')
804
805  classdefi=classdefs.items()
806  classdefi.sort(lambda x,y:cmp(x[0],y[0]))
807  externsfile.write("#if defined(%s_EXPORTS) || !defined(_MSC_VER)\n\n" % modulename.upper()) 
808  for (type, fields) in classdefi:
809    if fields.datastructure == "TPyOrange":
810      if not fields.imported: 
811        externsfile.write("  int cc_func_"+type+"(PyObject *, void *);\n")
812        externsfile.write("  int ccn_func_"+type+"(PyObject *, void *);\n")
813        externsfile.write("  #define cc_%s cc_func_%s\n" % (type, type))
814        externsfile.write("  #define ccn_%s ccn_func_%s\n\n" % (type, type))
815      else:
816        externsfile.write("  #define cc_%s PyOr%s_Type.ot_converter\n" % (type, type))
817        externsfile.write("  #define ccn_%s PyOr%s_Type.ot_nconverter\n\n" % (type, type))
818  externsfile.write("#else\n\n")
819  for (type, fields) in classdefi:
820    if not fields.imported and fields.datastructure == "TPyOrange":
821      externsfile.write("  #define cc_%s PyOr%s_Type.ot_converter\n" % (type, type))
822      externsfile.write("  #define ccn_%s PyOr%s_Type.ot_nconverter\n\n" % (type, type))
823  externsfile.write("#endif\n")
824
825  externsfile.write("\n\n") 
826
827  externsfile.close()
828
829
830def writeInitialization(functions, constants):
831  functionsfile=open("px/initialization.px.new", "wt")
832  newfiles.append("initialization.px")
833  functionsfile.write("/* This file was generated by pyxtract \n   Do not edit.*/\n\n")
834  functionsfile.write('#include "externs.px"\n\n')
835
836  myclasses = dict(filter(lambda x:not x[1].imported, classdefs.items()))
837
838  classconstants = [(type, fields.subconstants) for type, fields in myclasses.items() if fields.subconstants]
839  if classconstants:
840    functions["__pickleLoaderNamedConstants"] = FunctionDefinition(cname="__pickleLoaderNamedConstants", argkw="METH_VARARGS", arguments="")
841   
842  if len(functions):
843    olist=functions.keys()
844    olist.sort()
845    for functionname in olist:
846      function=functions[functionname]
847      if function.definition:
848        functionsfile.write(function.definition+";\n")
849      else:
850        if keywargsdef.search(function.argkw):
851          functionsfile.write("PyObject *"+function.cname+"(PyObject *, PyObject *, PyObject *);\n")
852        else:
853          functionsfile.write("PyObject *"+function.cname+"(PyObject *, PyObject *);\n")
854  else:
855    olist = []
856
857  printV1NoNL("\nFunctions:")
858  functionsfile.write("\n\nPyMethodDef %sFunctions[]={\n" % modulename)
859  for functionname in olist:
860    function=functions[functionname]
861    printV1NoNL(functionname)
862    if function.arguments:
863      functionsfile.write('     {"'+functionname+'", (binaryfunc)'+function.cname+', '+function.argkw+', "'+function.arguments+'"},\n')
864    else:
865      functionsfile.write('     {"'+functionname+'", (binaryfunc)'+function.cname+', '+function.argkw+'},\n')
866  functionsfile.write("     {NULL, NULL}\n};\n\n")
867  printV1()
868   
869
870  olist=constants.keys()
871  olist.sort()
872
873  for constantname in olist:
874    constant=constants[constantname]
875    if constant.cfunc:
876      functionsfile.write("PyObject *"+constant.cfunc+"();\n")
877
878  addconstscalls = ""
879  if len(myclasses):
880    ks=myclasses.keys()
881    ks.sort()
882    printV1NoNL("\nClasses:")
883    functionsfile.write("int noOf%sClasses=%i;\n\n" % (modulename, len(ks)))
884    functionsfile.write("TOrangeType *%sClasses[]={\n" % modulename)
885    for i in ks:
886      functionsfile.write("    &PyOr%s_Type,\n" % i)
887      printV1NoNL(i)
888    functionsfile.write("    NULL};\n\n")
889    printV1()
890
891    for i in ks:
892      if classdefs[i].constants:
893        functionsfile.write('\nvoid %s_addConstants();' % i)
894        addconstscalls += ('     %s_addConstants();\n' % i)
895  functionsfile.write("\n")
896
897  printV1NoNL("\nConstants:")
898  if classconstants:
899    for type, subconstants in classconstants:
900      for constname in subconstants:
901        functionsfile.write('extern PyTypeObject Py%s_Type;\n' % (type+"_"+constname))
902
903    functionsfile.write("\nTNamedConstantRecord %sNamedConstants[] = {\n" % modulename)
904    for type, subconstants in classconstants:
905      for constname in subconstants:
906        functionsfile.write('    {"%s_%s", &Py%s_%s_Type},\n' % (type, constname, type, constname))
907    functionsfile.write('    {NULL, NULL}\n};\n\n')
908    functionsfile.write("PyObject *__pickleLoaderNamedConstants(PyObject *, PyObject *args)\n{ return unpickleConstant(%sNamedConstants, args); }\n\n" % modulename)
909   
910
911  functionsfile.write("\nvoid add%sConstants(PyObject *mod) {\n" % modulename)
912  if olist:
913    for constantname in olist:
914      constant=constants[constantname]
915      printV1NoNL(constantname)
916      if constant.cfunc:
917        functionsfile.write('     PyModule_AddObject(mod, "'+constantname+'", '+constant.cfunc+'());\n')
918      else:
919        functionsfile.write('     PyModule_AddObject(mod, "'+constantname+'", '+constant.ccode+');\n')
920    functionsfile.write("\n\n")
921
922  if addconstscalls:
923    functionsfile.write(addconstscalls + "\n\n")
924
925  if len(myclasses):
926    for classname in ks:
927      if not classdefs[i].hidden:
928        functionsfile.write('     PyModule_AddObject(mod, "%s", (PyObject *)&PyOr%s_Type);\n' % (classname, classname))
929
930  for type, fields in myclasses.items():
931      if fields.subconstants:
932        for constname in fields.subconstants:
933          functionsfile.write('\n     PyType_Ready(&Py%(wholename)s_Type);\n     Py%(wholename)s_Type.tp_print = 0;\n' %
934                              {"wholename": type+"_"+constname, "classname": type, "constname": constname})
935
936  functionsfile.write("}\n\n")
937
938  printV1("\n")
939
940  functionsfile.write("""
941#ifdef _MSC_VER
942  #define WIN32_LEAN_AND_MEAN
943  #include <windows.h>
944  BOOL APIENTRY DllMain( HANDLE, DWORD  ul_reason_for_call, LPVOID)  { return TRUE; }
945#endif
946
947extern %(MODULENAME)s_API PyObject *%(modulename)sModule;
948
949ORANGE_API void addClassList(TOrangeType **);
950
951extern "C" %(MODULENAME)s_API void init%(modulename)s()
952{
953  if (!init%(modulename)sExceptions())
954    return;
955""" % {"modulename" : modulename, "MODULENAME": modulename.upper()})
956
957  if len(myclasses):
958    functionsfile.write("""
959  for(TOrangeType **type=%(modulename)sClasses; *type; type++)
960    if (PyType_Ready((PyTypeObject *)*type)<0)
961      return;
962  addClassList(%(modulename)sClasses);
963""" % {"modulename" : modulename})
964
965  functionsfile.write("""
966  gc%(modulename)sUnsafeStaticInitialization();
967  %(modulename)sModule = Py_InitModule("%(modulename)s", %(modulename)sFunctions); 
968  add%(modulename)sConstants(%(modulename)sModule);
969}
970""" % {"modulename" : modulename, "MODULENAME": modulename.upper()})
971
972  functionsfile.close()
973
974
975def writeGlobals():
976  newfiles.append("%s_globals.hpp" % modulename)
977
978  globalsfile = file("px/%s_globals.hpp.new" % modulename, "wt")
979  globalsfile.write(r"""/* This file was generated by pyxtract \n   Do not edit.*/
980
981#ifdef _MSC_VER
982    #define %(MODULENAME)s_EXTERN
983
984    #ifdef %(MODULENAME)s_EXPORTS
985        #define %(MODULENAME)s_API __declspec(dllexport)
986
987    #else
988        #define %(MODULENAME)s_API __declspec(dllimport)
989        #ifdef _DEBUG
990            #pragma comment(lib, "%(modulename)s_d.lib")
991        #else
992            #pragma comment(lib, "%(modulename)s.lib")
993        #endif
994
995    #endif // exports
996
997    #define %(MODULENAME)s_VWRAPPER(x) \
998        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API T##x; \
999        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1000        typedef GCPtr< T##x > P##x;
1001   
1002    #define %(MODULENAME)s_WRAPPER(x) \
1003        class %(MODULENAME)s_API T##x; \
1004        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1005        typedef GCPtr< T##x > P##x;
1006
1007#else
1008#ifdef DARWIN
1009    #define %(MODULENAME)s_API
1010   
1011    #ifdef %(MODULENAME)s_EXPORTS
1012        #define %(MODULENAME)s_EXTERN
1013    #else
1014        #define %(MODULENAME)s_EXTERN extern
1015    #endif
1016
1017    #define %(MODULENAME)s_VWRAPPER(x) \
1018        typedef GCPtr< T##x > P##x;
1019 
1020    #define %(MODULENAME)s_WRAPPER(x) \
1021        class %(MODULENAME)s_API T##x; \
1022        typedef GCPtr< T##x > P##x;
1023
1024#else // not _MSC_VER
1025    #define %(MODULENAME)s_API
1026
1027    #ifdef %(MODULENAME)s_EXPORTS
1028        #define %(MODULENAME)s_EXTERN
1029    #else
1030        #define %(MODULENAME)s_EXTERN extern
1031    #endif
1032
1033    #define %(MODULENAME)s_VWRAPPER(x) \
1034        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API T##x; \
1035        %(MODULENAME)s_EXTERN template class %(MODULENAME)s_API GCPtr< T##x >; \
1036        typedef GCPtr< T##x > P##x;
1037   
1038    #define %(MODULENAME)s_WRAPPER(x) \
1039        class %(MODULENAME)s_API T##x; \
1040        typedef GCPtr< T##x > P##x;
1041
1042#endif
1043#endif
1044"""
1045 % {"modulename": modulename, "MODULENAME": modulename.upper()})
1046
1047  if wrapper_shortcut != None:
1048    globalsfile.write("""
1049#define %(SHORTCUT)sVWRAPPER %(MODULENAME)s_VWRAPPER
1050#define %(SHORTCUT)sWRAPPER %(MODULENAME)s_WRAPPER
1051""" % {"SHORTCUT": wrapper_shortcut, "MODULENAME": modulename.upper()})
1052
1053def samefiles(n1, n2):
1054  f1, f2 = open(n1, "rt"), open(n2, "rt")
1055  same = (f1.readlines()==f2.readlines())
1056  f1.close()
1057  f2.close()
1058  return same
1059 
1060def renewfiles(newfiles):
1061  for i in newfiles:
1062    oldexists=os.path.isfile("px/"+i)
1063    if recreate or not oldexists or not samefiles("px/"+i, "px/"+i+".new"):
1064      if oldexists:
1065        os.remove("px/"+i)
1066        printNQ("Renewing %s" % i)
1067      else:
1068        printNQ("Creating %s" % i)
1069      os.rename("px/"+i+".new", "px/"+i)
1070    else:
1071      os.remove("px/"+i+".new")
1072      printV1("Keeping %s", i)
1073
1074
1075#args=sys.argv[1:]
1076
1077
1078def make():
1079  if not os.path.isdir("px"):
1080    os.mkdir("px")
1081  writeAppendices(classdefs)
1082  writeExterns()
1083  writeInitialization(functions, constants)
1084  writeGlobals()
1085  renewfiles(newfiles)
1086
1087  f=open("px/stamp", "wt")
1088  pickle.dump(classdefs, f)
1089  pickle.dump(functions, f)
1090  pickle.dump(constants, f)
1091  f.close()
1092 
1093
1094def listOfExports():
1095  for name, c in classdefs.items():
1096    print "Class '%s', derived from %s" % (name, getattr(c, "basetype", "none (or unknown)"))
1097    if getattr(c, "constructor", None):
1098      print "\tConstructor visible from Python: %s" % c.constructor.arguments
1099    if getattr(c, "call", None):
1100      print "\tCallable from Python: %s" % c.call.arguments
1101    properties = ", ".join(getattr(c, "builtinproperties", {}).keys()) + ", ".join(getattr(c, "properties", {}).keys())
1102    if hasattr(c, "getattr"):
1103      if hasattr(c, "setattr"):
1104        print "\tSpecialized getattr and setattr"
1105      else:
1106        print "\tSpecialized getattr"
1107    elif hasattr(c, "setattr"):
1108        print "\tSpecialized setattr"
1109    if len(properties):
1110      print "\tProperties: %s" % reduce(lambda x, y: x+", "+y, properties)
1111    print
1112
1113  print "\n\n\nFunctions"
1114  for func in functions:
1115    print "%s %s" % (func[0], func[-1])
1116
1117  print "\n\n\nConstants"
1118  for cons in constants:
1119    print "%s" % cons[0]
1120
1121
1122def listNode(name, hier, level):
1123  print "     "*level + name
1124  for child in sorted(hier.get(name, [])):
1125    listNode(child, hier, level+1)
1126   
1127def listOfClasses():
1128  hier = {}
1129  for name, c in classdefs.items():
1130    base = getattr(c, "basetype", None)
1131    if base:
1132      if not base in hier:
1133        hier[base] = []
1134      hier[base].append(name)
1135  listNode("Orange", hier, 0)
1136  for name, c in classdefs.items():
1137    if not getattr(c, "basetype", None) or c.basetype=="ROOT":
1138      listNode(name, hier, 0)
1139     
1140   
1141 
1142
1143def saferemove(fname):
1144  if os.path.isfile(fname):
1145    os.remove(fname)
1146   
1147def removeFiles():
1148  print "Removing externs.px, initialization.px,"
1149  saferemove("externs.px")
1150  saferemove("initialization.px")
1151
1152  for filename in filenames:
1153    found=filenamedef.match(filename)
1154    if found:
1155      filestem=found.group("stem")
1156    else:
1157      filestem=filename
1158    print "%s," % (filestem+".px"),
1159    saferemove(filestem+".px")
1160
1161
1162def readArguments(args):
1163  global filenames, verbose, recreate, action, libraries, modulename, wrapper_shortcut, quiet
1164  filenames, libraries, verbose, recreate, modulename, wrapper_shortcut = [], [], 0, 0, "", None
1165  action, quiet = [], 0
1166  i=0
1167  while(i<len(args)):
1168    if args[i][0]=="-":
1169      opt=args[i][1:]
1170      if opt=="q":
1171        quiet = 1
1172      elif opt=="v":
1173        verbose=1
1174      elif opt=="V":
1175        verbose=2
1176      elif opt=="r":
1177        recreate=1
1178      elif opt=="c":
1179        action.append("clean")
1180      elif opt=="m":
1181        action.append("make")
1182      elif opt=="i":
1183        action.append("list")
1184      elif opt=="e":
1185        action.append("hierarchy")
1186      elif opt=="l":
1187        i=i+1
1188        libraries.append(args[i])
1189      elif opt=="n":
1190        i=i+1
1191        modulename = args[i].lower()
1192      elif opt=="d":
1193        import os
1194        i+=1
1195        os.chdir(args[i])
1196      elif opt=="w":
1197        i+=1
1198        wrapper_shortcut = args[i]
1199      else:
1200        print "Unrecognized option %s" % args[i]
1201    else:
1202      if not "pyxtract.py" in args[i]:
1203        filenames.append(args[i])
1204    i=i+1
1205
1206  if not modulename:
1207    print "Module name (-n) missing"
1208    sys.exit()
1209  if not len(action):
1210    action=["make"]
1211
1212def printNQ(str):
1213  if not quiet:
1214    print str
1215   
1216def printV0(str="", tup=(), printLine = True):
1217  if printLine:
1218    print "%20s:%4i:" % (parsedFile, lineno),
1219  print str % tup
1220
1221def printV2(str="", tup=(), printLine = True):
1222  if verbose==2:
1223    printV0(str, tup, printLine)
1224   
1225def printV1(str="", tup=(), printLine = True):
1226  if verbose>=1:
1227    printV0(str, tup, printLine)
1228
1229def printV1NoNL(str="", tup=()):
1230  if verbose>=1:
1231    print str % tup,
1232       
1233args = sys.argv
1234
1235readArguments(args)
1236parsedFile=""
1237
1238if action.count("clean"):
1239  removeFiles()
1240  action.remove("clean")
1241
1242if len(action):
1243  pyprops = pickle.load(open("../orange/ppp/stamp", "rt")) #home dir on linux is different from windows; changed ppp/stamp to ../orange/ppp/stamp
1244  newfiles=[]
1245  functions, constants, classdefs, aliases = parseFiles()
1246   
1247  if action.count("list"):
1248    listOfExports()
1249  if action.count("hierarchy"):
1250    listOfClasses()
1251  if action.count("make"):
1252    make()
1253
1254
1255
1256
Note: See TracBrowser for help on using the repository browser.