mirror of
https://github.com/boostorg/python.git
synced 2026-01-20 16:52:15 +00:00
Compare commits
100 Commits
boost-0.9.
...
boost-0.9.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59e42fe22f | ||
|
|
dc7ae9ed20 | ||
|
|
929badf4c6 | ||
|
|
c4a3f2c04f | ||
|
|
a933e458b3 | ||
|
|
06b8320815 | ||
|
|
7f3aceafd2 | ||
|
|
da5979931c | ||
|
|
d8c7e75095 | ||
|
|
187506c97f | ||
|
|
145c6d1e4f | ||
|
|
e2973f27f9 | ||
|
|
976b8180ae | ||
|
|
37acf41d43 | ||
|
|
6f26778491 | ||
|
|
834d815c87 | ||
|
|
57e58c445b | ||
|
|
8a1a8342d6 | ||
|
|
fa70ddc2c5 | ||
|
|
8ca32bb494 | ||
|
|
f6c82eba0c | ||
|
|
344044a315 | ||
|
|
b10805dc4c | ||
|
|
07f397e2ed | ||
|
|
054dc439d2 | ||
|
|
5008dcbdd4 | ||
|
|
9c6650963f | ||
|
|
d482d57689 | ||
|
|
edf6516085 | ||
|
|
957ac66e14 | ||
|
|
07ce84c4e7 | ||
|
|
918636ff03 | ||
|
|
83a6adbfa9 | ||
|
|
fcbc1d562f | ||
|
|
c3b4b58075 | ||
|
|
568b62a8a4 | ||
|
|
da34e7f507 | ||
|
|
a0c31b47e5 | ||
|
|
5fb677c0c5 | ||
|
|
168476382a | ||
|
|
7fa6a29814 | ||
|
|
f2b51da0ab | ||
|
|
53726746b8 | ||
|
|
fe0b59f559 | ||
|
|
c014dee6dc | ||
|
|
90c69d961e | ||
|
|
342f7db678 | ||
|
|
9eb704f85a | ||
|
|
7754a91929 | ||
|
|
e4dc639e54 | ||
|
|
5d90101671 | ||
|
|
437fb70852 | ||
|
|
d598404c48 | ||
|
|
32c7088600 | ||
|
|
ccede29816 | ||
|
|
b55b7e2f7b | ||
|
|
9217a6a253 | ||
|
|
07c1319b99 | ||
|
|
714b5dc26e | ||
|
|
1f715958f9 | ||
|
|
0922aca873 | ||
|
|
30ec6181b5 | ||
|
|
b28d586612 | ||
|
|
f48aacf477 | ||
|
|
bfa868a440 | ||
|
|
f01ff3a277 | ||
|
|
d88e6bf688 | ||
|
|
a3cdacd088 | ||
|
|
81d99c855f | ||
|
|
5cd110f625 | ||
|
|
416895ff30 | ||
|
|
e41abb6e92 | ||
|
|
a6440a3fa6 | ||
|
|
2dece7ecaf | ||
|
|
7aae525587 | ||
|
|
ac5314093b | ||
|
|
1524fb9fa9 | ||
|
|
957549460b | ||
|
|
3b33f54fb8 | ||
|
|
42ab6b6b66 | ||
|
|
f59a5bbabc | ||
|
|
0be371d747 | ||
|
|
2b52210291 | ||
|
|
96a7bce78e | ||
|
|
c1e1ea697c | ||
|
|
874d6ebf2c | ||
|
|
77f5eb703c | ||
|
|
af53ae8329 | ||
|
|
8f76b8880e | ||
|
|
fa398734be | ||
|
|
362d20a8c7 | ||
|
|
6a33b8aeeb | ||
|
|
d4e06ac436 | ||
|
|
817dcd37e0 | ||
|
|
25bfd3c50f | ||
|
|
b13c902fb0 | ||
|
|
c95ef44b02 | ||
|
|
162727590c | ||
|
|
7e159844fb | ||
|
|
787b79cc2c |
22
pyste/NEWS
22
pyste/NEWS
@@ -1,3 +1,25 @@
|
||||
17 August 2003
|
||||
Added support for insertion of user code in the generated code.
|
||||
|
||||
16 August 2003
|
||||
Applied a patch by Gottfried Ganssauge that adds exception specifiers to
|
||||
wrapper functions and pointer declarations. Thanks a lot Gottfried!!
|
||||
|
||||
Applied a patch by Prabhu Ramachandran that fixes ae problem with the
|
||||
pure virtual method generation. Thanks again Prabhu!
|
||||
|
||||
10 August 2003
|
||||
Support for incremental generation of the code has been added. This changes
|
||||
how --multiple works; documentation of this new feature will follow. Thanks
|
||||
to Prabhu Ramachandran, that saw the need for this feature and discussed a
|
||||
solution.
|
||||
|
||||
Automatically convert \ to / in Windows systems before passing the paths to
|
||||
gccxml.
|
||||
|
||||
Fixed a bug reported by Prabhu Ramachandran, where in some classes the virtual
|
||||
methods were being definied incorrectly. Thanks a lot Prabhu!
|
||||
|
||||
7 July 2003
|
||||
Applied 2 patches by Prabhu Ramachandran: a fix in the new --multiple method,
|
||||
and two new functions "hold_with_shared_ptr" and its counterpart for auto_ptr.
|
||||
|
||||
@@ -8,3 +8,5 @@
|
||||
instance)
|
||||
|
||||
- Virtual operators
|
||||
|
||||
- args() support
|
||||
|
||||
@@ -48,25 +48,23 @@ class ClassExporter(Exporter):
|
||||
return makeid(self.class_.FullName()) + '_scope'
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return makeid(self.class_.name)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.class_.FullName()
|
||||
return self.info.name
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
if isinstance(decl, Typedef):
|
||||
self.class_ = self.GetDeclaration(decl.type.name)
|
||||
if not self.info.rename:
|
||||
self.info.rename = decl.name
|
||||
if self.declarations:
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
if isinstance(decl, Typedef):
|
||||
self.class_ = self.GetDeclaration(decl.type.name)
|
||||
if not self.info.rename:
|
||||
self.info.rename = decl.name
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.class_ = copy.deepcopy(self.class_)
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.class_ = copy.deepcopy(self.class_)
|
||||
|
||||
self.class_ = None
|
||||
|
||||
|
||||
def ClassBases(self):
|
||||
@@ -82,7 +80,8 @@ class ClassExporter(Exporter):
|
||||
bases' bases. Do this because base classes must be instantialized
|
||||
before the derived classes in the module definition.
|
||||
'''
|
||||
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
|
||||
num_bases = len(self.ClassBases())
|
||||
return num_bases, self.class_.FullName()
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
@@ -101,7 +100,7 @@ class ClassExporter(Exporter):
|
||||
self.ExportSmartPointer()
|
||||
self.ExportOpaquePointerPolicies()
|
||||
self.Write(codeunit)
|
||||
exported_names[self.class_.FullName()] = 1
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def InheritMethods(self, exported_names):
|
||||
@@ -111,8 +110,12 @@ class ClassExporter(Exporter):
|
||||
just export one type and automatically get all the members from the
|
||||
base classes.
|
||||
'''
|
||||
valid_members = (Method, ClassVariable, NestedClass, ClassOperator,
|
||||
ConverterOperator, ClassEnumeration)
|
||||
valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration)
|
||||
# these don't work INVESTIGATE!: (ClassOperator, ConverterOperator)
|
||||
fullnames = [x.FullName() for x in self.class_]
|
||||
pointers = [x.PointerDeclaration(True) for x in self.class_ if isinstance(x, Method)]
|
||||
fullnames = dict([(x, None) for x in fullnames])
|
||||
pointers = dict([(x, None) for x in pointers])
|
||||
for level in self.class_.hierarchy:
|
||||
level_exported = False
|
||||
for base in level:
|
||||
@@ -120,17 +123,22 @@ class ClassExporter(Exporter):
|
||||
if base.FullName() not in exported_names:
|
||||
for member in base:
|
||||
if type(member) in valid_members:
|
||||
member = copy.deepcopy(member)
|
||||
#if type(member) not in (ClassVariable,:
|
||||
# member.class_ = self.class_.FullName()
|
||||
self.class_.AddMember(member)
|
||||
member_copy = copy.deepcopy(member)
|
||||
member_copy.class_ = self.class_.FullName()
|
||||
if isinstance(member_copy, Method):
|
||||
pointer = member_copy.PointerDeclaration(True)
|
||||
if pointer not in pointers:
|
||||
self.class_.AddMember(member)
|
||||
pointers[pointer] = None
|
||||
elif member_copy.FullName() not in fullnames:
|
||||
self.class_.AddMember(member)
|
||||
else:
|
||||
level_exported = True
|
||||
if level_exported:
|
||||
break
|
||||
def IsValid(member):
|
||||
return isinstance(member, valid_members) and member.visibility == Scope.public
|
||||
self.public_members = [x for x in self.class_ if IsValid(x)]
|
||||
self.public_members = [x for x in self.class_ if IsValid(x)]
|
||||
|
||||
|
||||
def Write(self, codeunit):
|
||||
@@ -195,14 +203,9 @@ class ClassExporter(Exporter):
|
||||
|
||||
|
||||
def ExportBasics(self):
|
||||
'''Export the name of the class and its class_ statement.
|
||||
Also export the held_type if specified.'''
|
||||
'''Export the name of the class and its class_ statement.'''
|
||||
class_name = self.class_.FullName()
|
||||
self.Add('template', class_name)
|
||||
held_type = self.info.held_type
|
||||
if held_type:
|
||||
held_type = held_type % class_name
|
||||
self.Add('template', held_type)
|
||||
name = self.info.rename or self.class_.name
|
||||
self.Add('constructor', '"%s"' % name)
|
||||
|
||||
@@ -210,14 +213,14 @@ class ClassExporter(Exporter):
|
||||
def ExportBases(self, exported_names):
|
||||
'Expose the bases of the class into the template section'
|
||||
hierarchy = self.class_.hierarchy
|
||||
exported = []
|
||||
for level in hierarchy:
|
||||
exported = []
|
||||
for base in level:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
exported.append(base.name)
|
||||
if exported:
|
||||
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
|
||||
self.Add('template', code)
|
||||
if exported:
|
||||
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
|
||||
self.Add('template', code)
|
||||
|
||||
|
||||
def ExportConstructors(self):
|
||||
@@ -407,13 +410,19 @@ class ClassExporter(Exporter):
|
||||
has_virtual_methods = True
|
||||
break
|
||||
|
||||
holder = self.info.holder
|
||||
if has_virtual_methods:
|
||||
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info)
|
||||
self.Add('template', generator.FullName())
|
||||
if holder:
|
||||
self.Add('template', holder(generator.FullName()))
|
||||
else:
|
||||
self.Add('template', generator.FullName())
|
||||
for definition in generator.GenerateDefinitions():
|
||||
self.Add('inside', definition)
|
||||
self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT))
|
||||
|
||||
else:
|
||||
if holder:
|
||||
self.Add('template', holder(self.class_.FullName()))
|
||||
|
||||
# operators natively supported by boost
|
||||
BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -='\
|
||||
@@ -609,7 +618,7 @@ class ClassExporter(Exporter):
|
||||
if smart_ptr:
|
||||
class_name = self.class_.FullName()
|
||||
smart_ptr = smart_ptr % class_name
|
||||
self.Add('scope', '%s::register_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
|
||||
self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
|
||||
|
||||
|
||||
def ExportOpaquePointerPolicies(self):
|
||||
@@ -645,7 +654,7 @@ class _VirtualWrapperGenerator(object):
|
||||
'Generates code to export the virtual methods of the given class'
|
||||
|
||||
def __init__(self, class_, bases, info):
|
||||
self.class_ = class_
|
||||
self.class_ = copy.deepcopy(class_)
|
||||
self.bases = bases[:]
|
||||
self.info = info
|
||||
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
|
||||
@@ -686,7 +695,7 @@ class _VirtualWrapperGenerator(object):
|
||||
constantness = ' const'
|
||||
|
||||
# call_method callback
|
||||
decl = indent + '%s %s(%s)%s {\n' % (result, method.name, params, constantness)
|
||||
decl = indent + '%s %s(%s)%s%s {\n' % (result, method.name, params, constantness, method.Exceptions())
|
||||
param_names_str = ', '.join(param_names)
|
||||
if param_names_str:
|
||||
param_names_str = ', ' + param_names_str
|
||||
@@ -697,17 +706,26 @@ class _VirtualWrapperGenerator(object):
|
||||
# default implementations (with overloading)
|
||||
def DefaultImpl(method, param_names):
|
||||
'Return the body of a default implementation wrapper'
|
||||
indent2 = indent * 2
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if not wrapper:
|
||||
# return the default implementation of the class
|
||||
return '%s%s(%s);\n' % \
|
||||
(return_str, method.FullName(), ', '.join(param_names))
|
||||
if method.abstract:
|
||||
s = indent2 + 'PyErr_SetString(PyExc_RuntimeError, "pure virtual function called");\n' +\
|
||||
indent2 + 'throw_error_already_set();\n'
|
||||
params = ', '.join(param_names)
|
||||
s += indent2 + '%s%s(%s);\n' % \
|
||||
(return_str, method.name, params)
|
||||
return s
|
||||
else:
|
||||
return indent2 + '%s%s(%s);\n' % \
|
||||
(return_str, method.FullName(), ', '.join(param_names))
|
||||
else:
|
||||
# return a call for the wrapper
|
||||
params = ', '.join(['this'] + param_names)
|
||||
return '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
|
||||
return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
|
||||
|
||||
if not method.abstract and method.visibility != Scope.private:
|
||||
if method.visibility != Scope.private:
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
impl_names = self.DefaultImplementationNames(method)
|
||||
@@ -715,7 +733,7 @@ class _VirtualWrapperGenerator(object):
|
||||
params, param_names, param_types = _ParamsInfo(method, argNum)
|
||||
decl += '\n'
|
||||
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
|
||||
decl += indent*2 + DefaultImpl(method, param_names)
|
||||
decl += DefaultImpl(method, param_names)
|
||||
decl += indent + '}\n'
|
||||
return decl
|
||||
|
||||
@@ -780,21 +798,14 @@ class _VirtualWrapperGenerator(object):
|
||||
return type(m) is Method and \
|
||||
m.virtual and \
|
||||
m.visibility != Scope.private
|
||||
|
||||
all_methods = [x for x in self.class_ if IsVirtual(x)]
|
||||
for base in self.bases:
|
||||
base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)]
|
||||
for base_method in base_methods:
|
||||
base_method.class_ = self.class_.FullName()
|
||||
all_methods.append(base_method)
|
||||
|
||||
|
||||
# extract the virtual methods, avoiding duplications. The duplication
|
||||
# must take in account the full signature without the class name, so
|
||||
# that inherited members are correctly excluded if the subclass overrides
|
||||
# them.
|
||||
def MethodSig(method):
|
||||
if method.const:
|
||||
const = 'const'
|
||||
const = ' const'
|
||||
else:
|
||||
const = ''
|
||||
if method.result:
|
||||
@@ -802,10 +813,23 @@ class _VirtualWrapperGenerator(object):
|
||||
else:
|
||||
result = ''
|
||||
params = ', '.join([x.FullName() for x in method.parameters])
|
||||
return '%s %s(%s) %s' % (result, method.name, params, const)
|
||||
|
||||
self.virtual_methods = []
|
||||
return '%s %s(%s)%s%s' % (
|
||||
result, method.name, params, const, method.Exceptions())
|
||||
|
||||
already_added = {}
|
||||
self.virtual_methods = []
|
||||
for member in self.class_:
|
||||
if IsVirtual(member):
|
||||
already_added[MethodSig(member)] = None
|
||||
self.virtual_methods.append(member)
|
||||
|
||||
for base in self.bases:
|
||||
base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)]
|
||||
for base_method in base_methods:
|
||||
self.class_.AddMember(base_method)
|
||||
|
||||
all_methods = [x for x in self.class_ if IsVirtual(x)]
|
||||
|
||||
for member in all_methods:
|
||||
sig = MethodSig(member)
|
||||
if IsVirtual(member) and not sig in already_added:
|
||||
@@ -822,7 +846,7 @@ class _VirtualWrapperGenerator(object):
|
||||
for method in self.virtual_methods:
|
||||
exclude = self.info[method.name].exclude
|
||||
# generate definitions only for public methods and non-abstract methods
|
||||
if method.visibility == Scope.public and not method.abstract and not exclude:
|
||||
if method.visibility == Scope.public and not exclude:
|
||||
defs.extend(self.MethodDefinition(method))
|
||||
return defs
|
||||
|
||||
|
||||
21
pyste/src/Pyste/CodeExporter.py
Normal file
21
pyste/src/Pyste/CodeExporter.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from Exporter import Exporter
|
||||
|
||||
#==============================================================================
|
||||
# CodeExporter
|
||||
#==============================================================================
|
||||
class CodeExporter(Exporter):
|
||||
|
||||
def __init__(self, info):
|
||||
Exporter.__init__(self, info)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.code
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
codeunit.Write(self.info.section, self.info.code)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
pass
|
||||
@@ -2,16 +2,25 @@ from GCCXMLParser import ParseDeclarations
|
||||
import tempfile
|
||||
import shutil
|
||||
import os
|
||||
import sys
|
||||
import os.path
|
||||
import settings
|
||||
import shutil
|
||||
import shelve
|
||||
from cPickle import dump, load
|
||||
|
||||
#==============================================================================
|
||||
# exceptions
|
||||
#==============================================================================
|
||||
class CppParserError(Exception): pass
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# CppParser
|
||||
#==============================================================================
|
||||
class CppParser:
|
||||
'Parses a header file and returns a list of declarations'
|
||||
|
||||
def __init__(self, includes=None, defines=None):
|
||||
def __init__(self, includes=None, defines=None, cache_dir=None):
|
||||
'includes and defines ar the directives given to gcc'
|
||||
if includes is None:
|
||||
includes = []
|
||||
@@ -19,9 +28,27 @@ class CppParser:
|
||||
defines = []
|
||||
self.includes = includes
|
||||
self.defines = defines
|
||||
#if cache_dir is None:
|
||||
# cache_dir = tempfile.mktemp()
|
||||
# self.delete_cache = True
|
||||
#else:
|
||||
# self.delete_cache = False
|
||||
self.delete_cache = False
|
||||
self.cache_dir = cache_dir
|
||||
self.cache_files = []
|
||||
self.mem_cache = {}
|
||||
# create the cache dir
|
||||
if cache_dir:
|
||||
try:
|
||||
os.makedirs(cache_dir)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def _includeparams(self, filename):
|
||||
def __del__(self):
|
||||
self.Close()
|
||||
|
||||
|
||||
def _IncludeParams(self, filename):
|
||||
includes = self.includes[:]
|
||||
filedir = os.path.dirname(filename)
|
||||
if not filedir:
|
||||
@@ -31,64 +58,164 @@ class CppParser:
|
||||
return ' '.join(includes)
|
||||
|
||||
|
||||
def _defineparams(self):
|
||||
def _DefineParams(self):
|
||||
defines = ['-D "%s"' % x for x in self.defines]
|
||||
return ' '.join(defines)
|
||||
|
||||
|
||||
def FindFileName(self, include):
|
||||
if os.path.isfile(include):
|
||||
return include
|
||||
def FindHeader(self, header):
|
||||
if os.path.isfile(header):
|
||||
return header
|
||||
for path in self.includes:
|
||||
filename = os.path.join(path, include)
|
||||
filename = os.path.join(path, header)
|
||||
if os.path.isfile(filename):
|
||||
return filename
|
||||
name = os.path.basename(include)
|
||||
raise RuntimeError, 'Header file "%s" not found!' % name
|
||||
else:
|
||||
name = os.path.basename(header)
|
||||
raise RuntimeError, 'Header file "%s" not found!' % name
|
||||
|
||||
|
||||
def parse(self, include, tail=None, decl_name=None):
|
||||
'''Parses the given filename, and returns (declaration, header). The
|
||||
header returned is normally the same as the given to this method,
|
||||
except if tail is not None: in this case, the header is copied to a temp
|
||||
filename and the tail code is appended to it before being passed on to gcc.
|
||||
This temp filename is then returned.
|
||||
'''
|
||||
filename = self.FindFileName(include)
|
||||
# copy file to temp folder, if needed
|
||||
def AppendTail(self, filename, tail):
|
||||
'''Creates a temporary file, appends the text tail to it, and returns
|
||||
the filename of the file.
|
||||
'''
|
||||
temp = tempfile.mktemp('.h')
|
||||
shutil.copyfile(filename, temp)
|
||||
f = file(temp, 'a')
|
||||
f.write('\n\n'+tail)
|
||||
f.close()
|
||||
return temp
|
||||
|
||||
|
||||
def ParseWithGCCXML(self, header, tail):
|
||||
'''Parses the given header using gccxml and GCCXMLParser.
|
||||
'''
|
||||
header = self.FindHeader(header)
|
||||
if tail:
|
||||
tempfilename = tempfile.mktemp('.h')
|
||||
infilename = tempfilename
|
||||
shutil.copyfile(filename, infilename)
|
||||
f = file(infilename, 'a')
|
||||
f.write('\n\n'+tail)
|
||||
f.close()
|
||||
filename = self.AppendTail(header, tail)
|
||||
else:
|
||||
infilename = filename
|
||||
filename = header
|
||||
xmlfile = tempfile.mktemp('.xml')
|
||||
try:
|
||||
# get the params
|
||||
includes = self._includeparams(filename)
|
||||
defines = self._defineparams()
|
||||
includes = self._IncludeParams(filename)
|
||||
defines = self._DefineParams()
|
||||
# call gccxml
|
||||
cmd = 'gccxml %s %s %s -fxml=%s' \
|
||||
% (includes, defines, infilename, xmlfile)
|
||||
if decl_name is not None:
|
||||
cmd += ' "-fxml-start=%s"' % decl_name
|
||||
status = os.system(cmd)
|
||||
cmd = 'gccxml %s %s %s -fxml=%s'
|
||||
status = os.system(cmd % (includes, defines, filename, xmlfile))
|
||||
if status != 0 or not os.path.isfile(xmlfile):
|
||||
raise CppParserError, 'Error executing gccxml'
|
||||
# parse the resulting xml
|
||||
declarations = ParseDeclarations(xmlfile)
|
||||
# make the declarations' location to point to the original file
|
||||
if tail:
|
||||
for decl in declarations:
|
||||
decl_filename = os.path.normpath(os.path.normcase(decl.location[0]))
|
||||
filename = os.path.normpath(os.path.normcase(filename))
|
||||
if decl_filename == filename:
|
||||
decl.location = header, decl.location[1]
|
||||
# return the declarations
|
||||
return declarations, infilename
|
||||
return declarations
|
||||
finally:
|
||||
if settings.DEBUG and os.path.isfile(xmlfile):
|
||||
filename = os.path.basename(include)
|
||||
shutil.copy(xmlfile, os.path.splitext(filename)[0] + '.xml')
|
||||
filename = os.path.basename(header)
|
||||
filename = os.path.splitext(filename)[0] + '.xml'
|
||||
shutil.copy(xmlfile, filename)
|
||||
# delete the temporary files
|
||||
try:
|
||||
os.remove(xmlfile)
|
||||
if tail:
|
||||
os.remove(tempfilename)
|
||||
except OSError: pass
|
||||
os.remove(filename)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def Parse(self, header, interface, tail=None):
|
||||
'''Parses the given filename related to the given interface and returns
|
||||
the (declarations, headerfile). The header returned is normally the
|
||||
same as the given to this method (except that it is the full path),
|
||||
except if tail is not None: in this case, the header is copied to a temp
|
||||
filename and the tail code is appended to it before being passed on to
|
||||
gccxml. This temp filename is then returned.
|
||||
'''
|
||||
if tail is None:
|
||||
tail = ''
|
||||
tail.strip()
|
||||
declarations = self.GetCache(header, interface, tail)
|
||||
if declarations is None:
|
||||
declarations = self.ParseWithGCCXML(header, tail)
|
||||
self.CreateCache(header, interface, tail, declarations)
|
||||
return declarations, header
|
||||
|
||||
|
||||
def CacheFileName(self, interface):
|
||||
interface_name = os.path.basename(interface)
|
||||
cache_file = os.path.splitext(interface_name)[0] + '.pystec'
|
||||
cache_file = os.path.join(self.cache_dir, cache_file)
|
||||
return cache_file
|
||||
|
||||
|
||||
def GetCache(self, header, interface, tail):
|
||||
key = (header, interface, tail)
|
||||
# try memory cache first
|
||||
if key in self.mem_cache:
|
||||
return self.mem_cache[key]
|
||||
|
||||
# get the cache from the disk
|
||||
if self.cache_dir is None:
|
||||
return None
|
||||
header = self.FindHeader(header)
|
||||
cache_file = self.CacheFileName(interface)
|
||||
if os.path.isfile(cache_file):
|
||||
f = file(cache_file, 'rb')
|
||||
try:
|
||||
cache = load(f)
|
||||
if cache.has_key(key):
|
||||
self.cache_files.append(cache_file)
|
||||
return cache[key]
|
||||
else:
|
||||
return None
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def CreateCache(self, header, interface, tail, declarations):
|
||||
key = (header, interface, tail)
|
||||
|
||||
# our memory cache only holds one item
|
||||
self.mem_cache.clear()
|
||||
self.mem_cache[key] = declarations
|
||||
|
||||
# save the cache in the disk
|
||||
if self.cache_dir is None:
|
||||
return
|
||||
header = self.FindHeader(header)
|
||||
cache_file = self.CacheFileName(interface)
|
||||
if os.path.isfile(cache_file):
|
||||
f = file(cache_file, 'rb')
|
||||
try:
|
||||
cache = load(f)
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
cache = {}
|
||||
cache[key] = declarations
|
||||
self.cache_files.append(cache_file)
|
||||
f = file(cache_file, 'wb')
|
||||
try:
|
||||
dump(cache, f, 1)
|
||||
finally:
|
||||
f.close()
|
||||
return cache_file
|
||||
|
||||
|
||||
def Close(self):
|
||||
if self.delete_cache and self.cache_files:
|
||||
for filename in self.cache_files:
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError:
|
||||
pass
|
||||
self.cache_files = []
|
||||
shutil.rmtree(self.cache_dir)
|
||||
|
||||
@@ -14,7 +14,10 @@ class EnumExporter(Exporter):
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
self.enum = self.GetDeclaration(self.info.name)
|
||||
if self.declarations:
|
||||
self.enum = self.GetDeclaration(self.info.name)
|
||||
else:
|
||||
self.enum = None
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
@@ -34,12 +37,8 @@ class EnumExporter(Exporter):
|
||||
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
|
||||
code += indent + ';\n\n'
|
||||
codeunit.Write('module', code)
|
||||
exported_names[self.enum.FullName()] = 1
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
|
||||
|
||||
def Order(self):
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
@@ -12,10 +12,11 @@ class Exporter(object):
|
||||
self.info = info
|
||||
self.parser_tail = parser_tail
|
||||
self.interface_file = None
|
||||
self.declarations = []
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
raise NotImplementedError(self.__class__.__name__)
|
||||
|
||||
|
||||
def Tail(self):
|
||||
@@ -73,12 +74,15 @@ class Exporter(object):
|
||||
'''Returns a string that uniquely identifies this instance. All
|
||||
exporters will be sorted by Order before being exported.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return self.info.include
|
||||
return 0, self.info.name
|
||||
|
||||
|
||||
def Header(self):
|
||||
return self.info.include
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.Name() == other.Name()
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.Name() != other.Name()
|
||||
|
||||
@@ -24,7 +24,7 @@ class FunctionExporter(Exporter):
|
||||
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
|
||||
self.ExportOpaquePointer(decl, codeunit)
|
||||
self.GenerateOverloads(decls, codeunit)
|
||||
exported_names[decl.FullName()] = 1
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def ExportDeclaration(self, decl, unique, codeunit):
|
||||
@@ -44,7 +44,7 @@ class FunctionExporter(Exporter):
|
||||
codeunit.Write('module', self.INDENT + defs + '\n')
|
||||
# add the code of the wrapper
|
||||
if wrapper and wrapper.code:
|
||||
codeunit.Write('declaration', code + '\n')
|
||||
codeunit.Write('declaration', wrapper.code + '\n')
|
||||
|
||||
|
||||
def OverloadName(self, decl):
|
||||
@@ -82,9 +82,6 @@ class FunctionExporter(Exporter):
|
||||
if macro:
|
||||
codeunit.Write('declaration-outside', macro)
|
||||
|
||||
def Order(self):
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
|
||||
@@ -193,6 +193,17 @@ class GCCXMLParser(object):
|
||||
return args
|
||||
|
||||
|
||||
def GetExceptions(self, exception_list):
|
||||
if exception_list is None:
|
||||
return None
|
||||
|
||||
exceptions = []
|
||||
for t in exception_list.split():
|
||||
exceptions.append(self.GetType(t))
|
||||
|
||||
return exceptions
|
||||
|
||||
|
||||
def ParseFunction(self, id, element, functionType=Function):
|
||||
'''functionType is used because a Operator is identical to a normal
|
||||
function, only the type of the function changes.'''
|
||||
@@ -202,7 +213,8 @@ class GCCXMLParser(object):
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
incomplete = bool(int(element.get('incomplete', 0)))
|
||||
function = functionType(name, namespace, returns, params)
|
||||
throws = self.GetExceptions(element.get('throw', None))
|
||||
function = functionType(name, namespace, returns, params, throws)
|
||||
function.location = location
|
||||
self.AddDecl(function)
|
||||
self.Update(id, function)
|
||||
@@ -366,9 +378,10 @@ class GCCXMLParser(object):
|
||||
abstract = bool(int(element.get('pure_virtual', '0')))
|
||||
const = bool(int(element.get('const', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
throws = self.GetExceptions(element.get('throw', None))
|
||||
params = self.GetArguments(element)
|
||||
method = methodType(
|
||||
name, classname, result, params, visib, virtual, abstract, static, const)
|
||||
name, classname, result, params, visib, virtual, abstract, static, const, throws)
|
||||
method.location = location
|
||||
self.Update(id, method)
|
||||
|
||||
|
||||
@@ -66,17 +66,11 @@ class HeaderExporter(Exporter):
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
exporter.SetParsedHeader(self.parser_header)
|
||||
if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit):
|
||||
codeunit.SetCurrent(self.interface_file, exporter.Unit())
|
||||
codeunit.SetCurrent(self.interface_file, exporter.Name())
|
||||
else:
|
||||
codeunit.SetCurrent(exporter.Unit())
|
||||
codeunit.SetCurrent(exporter.Name())
|
||||
exporter.GenerateCode(codeunit, exported_names)
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return None # doesn't write anything by itself
|
||||
|
||||
|
||||
def Order(self):
|
||||
def Name(self):
|
||||
return self.info.include
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import os.path
|
||||
from Exporter import Exporter
|
||||
|
||||
#==============================================================================
|
||||
# IncludeExporter
|
||||
#==============================================================================
|
||||
class IncludeExporter(Exporter):
|
||||
'''Writes an include declaration to the module. Useful to add extra code
|
||||
for use in the Wrappers.
|
||||
This class just reimplements the Parse method to do nothing: the
|
||||
WriteInclude in Exporter already does the work for us.
|
||||
'''
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
Exporter.__init__(self, info, parser_tail)
|
||||
|
||||
def Parse(self, parser):
|
||||
pass
|
||||
|
||||
def Order(self):
|
||||
return self.info.include
|
||||
|
||||
def Unit(self):
|
||||
return '__all__' # include it in all generated cpps (multiple mode)
|
||||
|
||||
def Header(self):
|
||||
return None # means "don't try to parse me!"
|
||||
@@ -22,8 +22,9 @@ class MultipleCodeUnit(object):
|
||||
self.all = SingleCodeUnit(None, None)
|
||||
|
||||
|
||||
def _FunctionName(self, export_name):
|
||||
return 'Export_%s' % utils.makeid(export_name)
|
||||
def _FunctionName(self, interface_file):
|
||||
name = os.path.splitext(interface_file)[0]
|
||||
return 'Export_%s' % utils.makeid(name)
|
||||
|
||||
|
||||
def _FileName(self, interface_file):
|
||||
@@ -40,13 +41,13 @@ class MultipleCodeUnit(object):
|
||||
self._current = self.all
|
||||
else:
|
||||
filename = self._FileName(interface_file)
|
||||
function = self._FunctionName(export_name)
|
||||
function = self._FunctionName(interface_file)
|
||||
try:
|
||||
codeunit = self.codeunits[(filename, function)]
|
||||
codeunit = self.codeunits[filename]
|
||||
except KeyError:
|
||||
codeunit = SingleCodeUnit(None, filename)
|
||||
codeunit.module_definition = 'void %s()' % function
|
||||
self.codeunits[(filename, function)] = codeunit
|
||||
self.codeunits[filename] = codeunit
|
||||
if function not in self.functions:
|
||||
self.functions.append(function)
|
||||
self._current = codeunit
|
||||
@@ -84,7 +85,7 @@ class MultipleCodeUnit(object):
|
||||
# unit in the list of code units is used as the main unit
|
||||
# which dumps all the include, declaration and
|
||||
# declaration-outside sections at the top of the file.
|
||||
for (filename, _), codeunit in self.codeunits.items():
|
||||
for filename, codeunit in self.codeunits.items():
|
||||
if filename not in codeunits:
|
||||
# this codeunit is the main codeunit.
|
||||
codeunits[filename] = [codeunit]
|
||||
@@ -103,20 +104,24 @@ class MultipleCodeUnit(object):
|
||||
codeunit.Save(append)
|
||||
if not append:
|
||||
append = True
|
||||
|
||||
|
||||
def GenerateMain(self, interfaces):
|
||||
# generate the main cpp
|
||||
filename = os.path.join(self.outdir, '_main.cpp')
|
||||
fout = SmartFile(filename, 'w')
|
||||
fout.write(utils.left_equals('Include'))
|
||||
fout.write('#include <boost/python.hpp>\n\n')
|
||||
fout.write('#include <boost/python/module.hpp>\n\n')
|
||||
fout.write(utils.left_equals('Exports'))
|
||||
for function in self.functions:
|
||||
functions = [self._FunctionName(x) for x in interfaces]
|
||||
for function in functions:
|
||||
fout.write('void %s();\n' % function)
|
||||
fout.write('\n')
|
||||
fout.write(utils.left_equals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
|
||||
fout.write('{\n')
|
||||
indent = ' ' * 4
|
||||
for function in self.functions:
|
||||
for function in functions:
|
||||
fout.write(indent)
|
||||
fout.write('%s();\n' % function)
|
||||
fout.write('}\n')
|
||||
|
||||
@@ -50,7 +50,7 @@ class SingleCodeUnit:
|
||||
return self.code[section]
|
||||
|
||||
|
||||
def SetCurrent(self, current):
|
||||
def SetCurrent(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
@@ -85,13 +85,14 @@ class SingleCodeUnit:
|
||||
fout.write(declaration_outside + '\n\n')
|
||||
if declaration:
|
||||
pyste_namespace = namespaces.pyste[:-2]
|
||||
fout.write('namespace %s {\n\n\n' % pyste_namespace)
|
||||
fout.write('namespace %s {\n\n' % pyste_namespace)
|
||||
fout.write(declaration)
|
||||
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write('\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write(space)
|
||||
# module
|
||||
fout.write(left_equals('Module'))
|
||||
fout.write(self.module_definition + '\n')
|
||||
fout.write('{\n')
|
||||
fout.write(self.code['module'])
|
||||
fout.write('}\n')
|
||||
fout.write('}\n\n')
|
||||
fout.close()
|
||||
|
||||
@@ -28,8 +28,8 @@ class VarExporter(Exporter):
|
||||
|
||||
|
||||
def Order(self):
|
||||
return 0, self.info.name
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
|
||||
@@ -123,7 +123,7 @@ class Class(Declaration):
|
||||
m.is_unique = False
|
||||
else:
|
||||
member.is_unique = True
|
||||
self.__member_names[member.name] = 1
|
||||
self.__member_names[member.name] = 1
|
||||
self.__members.append(member)
|
||||
if isinstance(member, ClassOperator):
|
||||
self.operator[member.name] = member
|
||||
@@ -196,14 +196,24 @@ class Function(Declaration):
|
||||
'''The declaration of a function.
|
||||
@ivar _result: instance of L{Type} or None.
|
||||
@ivar _parameters: list of L{Type} instances.
|
||||
@ivar _throws: exception specifiers or None
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace, result, params):
|
||||
def __init__(self, name, namespace, result, params, throws=None):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# the result type: instance of Type, or None (constructors)
|
||||
self.result = result
|
||||
# the parameters: instances of Type
|
||||
self.parameters = params
|
||||
# the exception specification
|
||||
self.throws = throws
|
||||
|
||||
|
||||
def Exceptions(self):
|
||||
if self.throws is None:
|
||||
return ""
|
||||
else:
|
||||
return " throw(%s)" % ', '.join (self.throws)
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
@@ -264,10 +274,11 @@ class Method(Function):
|
||||
@ivar _static: if this method is static.
|
||||
@ivar _class: the full name of the class where this method was declared.
|
||||
@ivar _const: if this method is declared as const.
|
||||
@ivar _throws: list of exception specificiers or None
|
||||
'''
|
||||
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const):
|
||||
Function.__init__(self, name, None, result, params)
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const, throws=None):
|
||||
Function.__init__(self, name, None, result, params, throws)
|
||||
self.visibility = visib
|
||||
self.virtual = virtual
|
||||
self.abstract = abstract
|
||||
@@ -296,8 +307,8 @@ class Method(Function):
|
||||
const = ''
|
||||
if self.const:
|
||||
const = 'const'
|
||||
return '(%s (%s::*)(%s) %s)&%s' %\
|
||||
(result, self.class_, params, const, self.FullName())
|
||||
return '(%s (%s::*)(%s) %s%s)&%s' %\
|
||||
(result, self.class_, params, const, self.Exceptions(), self.FullName())
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -329,6 +340,10 @@ class Constructor(Method):
|
||||
return param_reference and class_as_param and param.const and is_public
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
return ''
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Destructor
|
||||
#==============================================================================
|
||||
@@ -342,6 +357,10 @@ class Destructor(Method):
|
||||
return self.class_ + '::~' + self.name
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassOperator
|
||||
|
||||
@@ -7,6 +7,7 @@ from IncludeExporter import IncludeExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
from VarExporter import VarExporter
|
||||
from CodeExporter import CodeExporter
|
||||
from exporterutils import FunctionWrapper
|
||||
from utils import makeid
|
||||
|
||||
@@ -58,7 +59,8 @@ class FunctionInfo(DeclarationInfo):
|
||||
self._Attribute('exclude', False)
|
||||
# create a FunctionExporter
|
||||
exporter = FunctionExporter(InfoWrapper(self), tail)
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
@@ -74,23 +76,11 @@ class ClassInfo(DeclarationInfo):
|
||||
self._Attribute('exclude', False)
|
||||
# create a ClassExporter
|
||||
exporter = ClassExporter(InfoWrapper(self), tail)
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# IncludeInfo
|
||||
#==============================================================================
|
||||
class IncludeInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, include):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = IncludeExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# templates
|
||||
#==============================================================================
|
||||
@@ -137,7 +127,8 @@ class EnumInfo(DeclarationInfo):
|
||||
self._Attribute('include', include)
|
||||
self._Attribute('exclude', False)
|
||||
exporter = EnumExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
@@ -150,7 +141,8 @@ class HeaderInfo(DeclarationInfo):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = HeaderExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
@@ -164,10 +156,26 @@ class VarInfo(DeclarationInfo):
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
exporter = VarExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# CodeInfo
|
||||
#==============================================================================
|
||||
class CodeInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, code, section):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('code', code)
|
||||
self._Attribute('section', section)
|
||||
exporter = CodeExporter(InfoWrapper(self))
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# InfoWrapper
|
||||
#==============================================================================
|
||||
@@ -215,11 +223,10 @@ def use_shared_ptr(info):
|
||||
def use_auto_ptr(info):
|
||||
info._Attribute('smart_ptr', 'std::auto_ptr< %s >')
|
||||
|
||||
def hold_with_shared_ptr(info):
|
||||
info._Attribute('held_type', 'boost::shared_ptr< %s >')
|
||||
|
||||
def hold_with_auto_ptr(info):
|
||||
info._Attribute('held_type', 'std::auto_ptr< %s >')
|
||||
def holder(info, function):
|
||||
msg = "Expected a callable that accepts one string argument."
|
||||
assert callable(function), msg
|
||||
info._Attribute('holder', function)
|
||||
|
||||
def add_method(info, name, rename=None):
|
||||
added = info._Attribute('__added__')
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import profile
|
||||
import pstats
|
||||
import pyste
|
||||
|
||||
import psyco
|
||||
import elementtree.XMLTreeBuilder as XMLTreeBuilder
|
||||
import GCCXMLParser
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#psyco.bind(XMLTreeBuilder.fixtext)
|
||||
#psyco.bind(XMLTreeBuilder.fixname)
|
||||
#psyco.bind(XMLTreeBuilder.TreeBuilder)
|
||||
#psyco.bind(GCCXMLParser.GCCXMLParser)
|
||||
profile.run('pyste.Main()', 'profile')
|
||||
p = pstats.Stats('profile')
|
||||
p.strip_dirs().sort_stats(-1).print_stats()
|
||||
@@ -1,28 +1,31 @@
|
||||
'''
|
||||
"""
|
||||
Pyste version %s
|
||||
|
||||
Usage:
|
||||
pyste [options] interface-files
|
||||
|
||||
where options are:
|
||||
--module=<name> the name of the module that will be generated.
|
||||
Defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug writes the xml for each file parsed in the current
|
||||
directory
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information
|
||||
'''
|
||||
--module=<name> The name of the module that will be generated;
|
||||
defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> Add an include path
|
||||
-D <symbol> Define symbol
|
||||
--multiple Create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out=<name> Specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using Do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> Set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug Writes the xml for each file parsed in the current
|
||||
directory
|
||||
--cache-dir=<dir> Directory for cache files (speeds up future runs)
|
||||
--only-create-cache Recreates all caches (doesn't generate code).
|
||||
--generate-main Generates the _main.cpp file (in multiple mode)
|
||||
-h, --help Print this help and exit
|
||||
-v, --version Print version information
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
@@ -38,8 +41,9 @@ import sys
|
||||
from policies import *
|
||||
from CppParser import CppParser, CppParserError
|
||||
import time
|
||||
from declarations import Typedef
|
||||
|
||||
__VERSION__ = '0.9.10'
|
||||
__version__ = '0.9.16'
|
||||
|
||||
def RecursiveIncludes(include):
|
||||
'Return a list containg the include dir and all its subdirectories'
|
||||
@@ -60,26 +64,40 @@ def GetDefaultIncludes():
|
||||
return []
|
||||
|
||||
|
||||
def ProcessIncludes(includes):
|
||||
if sys.platform == 'win32':
|
||||
index = 0
|
||||
for include in includes:
|
||||
includes[index] = include.replace('\\', '/')
|
||||
index += 1
|
||||
|
||||
|
||||
def ParseArguments():
|
||||
|
||||
def Usage():
|
||||
print __doc__ % __VERSION__
|
||||
print __doc__ % __version__
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
options, files = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'R:I:D:vh',
|
||||
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'version', 'help'])
|
||||
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=',
|
||||
'only-create-cache', 'version', 'generate-main', 'help'])
|
||||
except getopt.GetoptError, e:
|
||||
print
|
||||
print 'ERROR:', e
|
||||
Usage()
|
||||
|
||||
includes = GetDefaultIncludes()
|
||||
defines = []
|
||||
module = None
|
||||
out = None
|
||||
multiple = False
|
||||
cache_dir = None
|
||||
create_cache = False
|
||||
generate_main = False
|
||||
|
||||
for opt, value in options:
|
||||
if opt == '-I':
|
||||
includes.append(value)
|
||||
@@ -100,11 +118,17 @@ def ParseArguments():
|
||||
settings.DEBUG = True
|
||||
elif opt == '--multiple':
|
||||
multiple = True
|
||||
elif opt == '--cache-dir':
|
||||
cache_dir = value
|
||||
elif opt == '--only-create-cache':
|
||||
create_cache = True
|
||||
elif opt in ['-h', '--help']:
|
||||
Usage()
|
||||
elif opt in ['-v', '--version']:
|
||||
print 'Pyste version %s' % __VERSION__
|
||||
print 'Pyste version %s' % __version__
|
||||
sys.exit(2)
|
||||
elif opt == '--generate-main':
|
||||
generate_main = True
|
||||
else:
|
||||
print 'Unknown option:', opt
|
||||
Usage()
|
||||
@@ -122,16 +146,28 @@ def ParseArguments():
|
||||
if d not in sys.path:
|
||||
sys.path.append(d)
|
||||
|
||||
return includes, defines, module, out, files, multiple
|
||||
if create_cache and not cache_dir:
|
||||
print 'Error: Use --cache-dir to indicate where to create the cache files!'
|
||||
Usage()
|
||||
sys.exit(3)
|
||||
|
||||
if generate_main and not multiple:
|
||||
print 'Error: --generate-main only valid in multiple mode.'
|
||||
Usage()
|
||||
sys.exit(3)
|
||||
|
||||
ProcessIncludes(includes)
|
||||
return includes, defines, module, out, files, multiple, cache_dir, create_cache, generate_main
|
||||
|
||||
|
||||
def CreateContext():
|
||||
'create the context where a interface file will be executed'
|
||||
context = {}
|
||||
context['Import'] = ExecuteInterface
|
||||
# infos
|
||||
context['Function'] = infos.FunctionInfo
|
||||
context['Class'] = infos.ClassInfo
|
||||
context['Include'] = infos.IncludeInfo
|
||||
context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include')
|
||||
context['Template'] = infos.ClassTemplateInfo
|
||||
context['Enum'] = infos.EnumInfo
|
||||
context['AllFromHeader'] = infos.HeaderInfo
|
||||
@@ -143,8 +179,7 @@ def CreateContext():
|
||||
context['set_wrapper'] = infos.set_wrapper
|
||||
context['use_shared_ptr'] = infos.use_shared_ptr
|
||||
context['use_auto_ptr'] = infos.use_auto_ptr
|
||||
context['hold_with_shared_ptr'] = infos.hold_with_shared_ptr
|
||||
context['hold_with_auto_ptr'] = infos.hold_with_auto_ptr
|
||||
context['holder'] = infos.holder
|
||||
context['add_method'] = infos.add_method
|
||||
context['final'] = infos.final
|
||||
# policies
|
||||
@@ -158,77 +193,166 @@ def CreateContext():
|
||||
context['manage_new_object'] = manage_new_object
|
||||
# utils
|
||||
context['Wrapper'] = exporterutils.FunctionWrapper
|
||||
context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration')
|
||||
context['global_declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside')
|
||||
context['module_code'] = lambda code: infos.CodeInfo(code, 'module')
|
||||
return context
|
||||
|
||||
|
||||
def Begin():
|
||||
includes, defines, module, out, interfaces, multiple = ParseArguments()
|
||||
# execute the interface files
|
||||
# parse arguments
|
||||
includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main = ParseArguments()
|
||||
# run pyste scripts
|
||||
for interface in interfaces:
|
||||
exporters.current_interface = interface
|
||||
context = CreateContext()
|
||||
execfile(interface, context)
|
||||
ExecuteInterface(interface)
|
||||
# create the parser
|
||||
parser = CppParser(includes, defines)
|
||||
parser = CppParser(includes, defines, cache_dir)
|
||||
try:
|
||||
if not create_cache:
|
||||
if not generate_main:
|
||||
return GenerateCode(parser, module, out, interfaces, multiple)
|
||||
else:
|
||||
return GenerateMain(module, out, OrderInterfaces(interfaces))
|
||||
else:
|
||||
return CreateCaches(parser)
|
||||
finally:
|
||||
parser.Close()
|
||||
|
||||
|
||||
def CreateCaches(parser):
|
||||
# There is one cache file per interface so we organize the headers
|
||||
# by interfaces. For each interface collect the tails from the
|
||||
# exporters sharing the same header.
|
||||
tails = JoinTails(exporters.exporters)
|
||||
|
||||
# now for each interface file take each header, and using the tail
|
||||
# get the declarations and cache them.
|
||||
for interface, header in tails:
|
||||
tail = tails[(interface, header)]
|
||||
declarations = parser.ParseWithGCCXML(header, tail)
|
||||
cachefile = parser.CreateCache(header, interface, tail, declarations)
|
||||
print 'Cached', cachefile
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
_imported_count = {} # interface => count
|
||||
|
||||
def ExecuteInterface(interface):
|
||||
old_interface = exporters.current_interface
|
||||
if not os.path.exists(interface):
|
||||
if old_interface and os.path.exists(old_interface):
|
||||
d = os.path.dirname(old_interface)
|
||||
interface = os.path.join(d, interface)
|
||||
if not os.path.exists(interface):
|
||||
raise IOError, "Cannot find interface file %s."%interface
|
||||
|
||||
_imported_count[interface] = _imported_count.get(interface, 0) + 1
|
||||
exporters.current_interface = interface
|
||||
context = CreateContext()
|
||||
execfile(interface, context)
|
||||
exporters.current_interface = old_interface
|
||||
|
||||
|
||||
def JoinTails(exports):
|
||||
'''Returns a dict of {(interface, header): tail}, where tail is the
|
||||
joining of all tails of all exports for the header.
|
||||
'''
|
||||
tails = {}
|
||||
for export in exports:
|
||||
interface = export.interface_file
|
||||
header = export.Header()
|
||||
tail = export.Tail() or ''
|
||||
if (interface, header) in tails:
|
||||
all_tails = tails[(interface,header)]
|
||||
all_tails += '\n' + tail
|
||||
tails[(interface, header)] = all_tails
|
||||
else:
|
||||
tails[(interface, header)] = tail
|
||||
|
||||
return tails
|
||||
|
||||
|
||||
|
||||
def OrderInterfaces(interfaces):
|
||||
interfaces_order = [(_imported_count[x], x) for x in interfaces]
|
||||
interfaces_order.sort()
|
||||
interfaces_order.reverse()
|
||||
return [x for _, x in interfaces_order]
|
||||
|
||||
|
||||
|
||||
def GenerateMain(module, out, interfaces):
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
codeunit.GenerateMain(interfaces)
|
||||
return 0
|
||||
|
||||
|
||||
def GenerateCode(parser, module, out, interfaces, multiple):
|
||||
# prepare to generate the wrapper code
|
||||
if multiple:
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
else:
|
||||
codeunit = SingleCodeUnit.SingleCodeUnit(module, out)
|
||||
# group exporters by header files
|
||||
groups = {}
|
||||
for export in exporters.exporters:
|
||||
header = export.Header()
|
||||
if header in groups:
|
||||
groups[header].append(export)
|
||||
else:
|
||||
groups[header] = [export]
|
||||
# stop referencing the exporters here
|
||||
exports = exporters.exporters
|
||||
exporters.exporters = None
|
||||
# export all the exporters in each group, releasing memory as doing so
|
||||
while len(groups) > 0:
|
||||
# get the first group
|
||||
header = groups.keys()[0]
|
||||
exports = groups[header]
|
||||
del groups[header]
|
||||
# gather all tails into one
|
||||
all_tails = []
|
||||
for export in exports:
|
||||
if export.Tail():
|
||||
all_tails.append(export.Tail())
|
||||
all_tails = '\n'.join(all_tails)
|
||||
# parse header (if there's one)
|
||||
exported_names = dict([(x.Name(), None) for x in exports])
|
||||
|
||||
# order the exports
|
||||
interfaces_order = OrderInterfaces(interfaces)
|
||||
order = {}
|
||||
for export in exports:
|
||||
if export.interface_file in order:
|
||||
order[export.interface_file].append(export)
|
||||
else:
|
||||
order[export.interface_file] = [export]
|
||||
exports = []
|
||||
for interface in interfaces_order:
|
||||
exports.extend(order[interface])
|
||||
del order
|
||||
del interfaces_order
|
||||
|
||||
# now generate the code in the correct order
|
||||
#print exported_names
|
||||
tails = JoinTails(exports)
|
||||
for i in xrange(len(exports)):
|
||||
export = exports[i]
|
||||
interface = export.interface_file
|
||||
header = export.Header()
|
||||
if header:
|
||||
try:
|
||||
declarations, parsed_header = parser.parse(header, all_tails)
|
||||
except CppParserError, e:
|
||||
print>>sys.stderr, '\n\n***', e, ': exitting'
|
||||
return 2
|
||||
tail = tails[(interface, header)]
|
||||
declarations, parsed_header = parser.Parse(header, interface, tail)
|
||||
else:
|
||||
declarations = []
|
||||
parsed_header = None
|
||||
# first set the declarations and parsed_header for all the exporters
|
||||
for export in exports:
|
||||
export.SetDeclarations(declarations)
|
||||
export.SetParsedHeader(parsed_header)
|
||||
# sort the exporters by their order
|
||||
exports = [(x.Order(), x) for x in exports]
|
||||
exports.sort()
|
||||
exports = [x for _, x in exports]
|
||||
# maintain a dict of exported_names for this group
|
||||
exported_names = {}
|
||||
for export in exports:
|
||||
if multiple:
|
||||
codeunit.SetCurrent(export.interface_file, export.Unit())
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
ExpandTypedefs(declarations, exported_names)
|
||||
export.SetDeclarations(declarations)
|
||||
export.SetParsedHeader(parsed_header)
|
||||
if multiple:
|
||||
codeunit.SetCurrent(export.interface_file, export.Name())
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
# force collect of cyclic references
|
||||
exports[i] = None
|
||||
del declarations
|
||||
del export
|
||||
gc.collect()
|
||||
# finally save the code unit
|
||||
codeunit.Save()
|
||||
print 'Module %s generated' % module
|
||||
codeunit.Save()
|
||||
if not multiple:
|
||||
print 'Module %s generated' % module
|
||||
return 0
|
||||
|
||||
|
||||
def ExpandTypedefs(declarations, exported_names):
|
||||
'''Check if the names in exported_names are a typedef, and add the real class
|
||||
name in the dict.
|
||||
'''
|
||||
for name in exported_names.keys():
|
||||
for decl in declarations:
|
||||
if isinstance(decl, Typedef):
|
||||
exported_names[decl.type.FullName()] = None
|
||||
|
||||
def UsePsyco():
|
||||
'Tries to use psyco if possible'
|
||||
try:
|
||||
|
||||
17
pyste/tests/abstract_test.h
Normal file
17
pyste/tests/abstract_test.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace abstract {
|
||||
|
||||
struct A {
|
||||
virtual ~A() {}
|
||||
virtual std::string f()=0;
|
||||
};
|
||||
|
||||
struct B: A {
|
||||
std::string f() { return "B::f"; }
|
||||
};
|
||||
|
||||
std::string call(A* a) { return a->f(); }
|
||||
|
||||
}
|
||||
3
pyste/tests/abstract_test.pyste
Normal file
3
pyste/tests/abstract_test.pyste
Normal file
@@ -0,0 +1,3 @@
|
||||
Class('abstract::A', 'abstract_test.h')
|
||||
Class('abstract::B', 'abstract_test.h')
|
||||
Function('abstract::call', 'abstract_test.h')
|
||||
22
pyste/tests/abstract_testUT.py
Normal file
22
pyste/tests/abstract_testUT.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import unittest
|
||||
from _abstract_test import *
|
||||
|
||||
class AbstractTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
class C(A):
|
||||
def f(self):
|
||||
return 'C::f'
|
||||
|
||||
a = A()
|
||||
b = B()
|
||||
c = C()
|
||||
self.assertRaises(RuntimeError, a.f)
|
||||
self.assertEqual(b.f(), 'B::f')
|
||||
self.assertEqual(call(b), 'B::f')
|
||||
self.assertEqual(c.f(), 'C::f')
|
||||
self.assertEqual(call(c), 'C::f')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
4
pyste/tests/code_test.h
Normal file
4
pyste/tests/code_test.h
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
struct A {
|
||||
int x;
|
||||
};
|
||||
9
pyste/tests/code_test.pyste
Normal file
9
pyste/tests/code_test.pyste
Normal file
@@ -0,0 +1,9 @@
|
||||
Class('A', 'code_test.h')
|
||||
Include('string')
|
||||
global_declaration_code('''
|
||||
int get(A& a) { return a.x; }
|
||||
|
||||
std::string foo() { return "Hello!"; }
|
||||
''')
|
||||
module_code(' def("get", &get);\n')
|
||||
module_code(' def("foo", &foo);\n')
|
||||
14
pyste/tests/code_testUT.py
Normal file
14
pyste/tests/code_testUT.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import unittest
|
||||
from _code_test import *
|
||||
|
||||
class CodeTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
a = A()
|
||||
a.x = 12
|
||||
self.assertEqual(get(a), 12)
|
||||
self.assertEqual(foo(), "Hello!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -4,12 +4,15 @@ struct A
|
||||
{
|
||||
int x;
|
||||
int getx() { return x; }
|
||||
int foo() { return 0; }
|
||||
int foo(int x) { return x; }
|
||||
};
|
||||
|
||||
struct B : A
|
||||
{
|
||||
int y;
|
||||
int gety() { return y; }
|
||||
int foo() { return 1; }
|
||||
};
|
||||
|
||||
struct C : B
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
header = AllFromHeader('inherit2.h')
|
||||
exclude(header.A)
|
||||
exclude(header.C)
|
||||
Class('inherit2::B', 'inherit2.h')
|
||||
Class('inherit2::D', 'inherit2.h')
|
||||
|
||||
@@ -16,6 +16,8 @@ class InheritExampleTest(unittest.TestCase):
|
||||
self.assertEqual(d.gety(), 15)
|
||||
self.assertEqual(d.getz(), 10)
|
||||
self.assertEqual(d.getw(), 5)
|
||||
self.assertEqual(b.foo(), 1)
|
||||
self.assertEqual(b.foo(3), 3)
|
||||
|
||||
def wrong():
|
||||
return b.getw()
|
||||
|
||||
39
pyste/tests/inherit3.h
Normal file
39
pyste/tests/inherit3.h
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
namespace inherit3 {
|
||||
|
||||
struct A
|
||||
{
|
||||
struct X { int y; };
|
||||
int x;
|
||||
virtual int foo() { return 0; }
|
||||
virtual int foo(int x) { return x; }
|
||||
A operator+(A o) const
|
||||
{
|
||||
A r;
|
||||
r.x = o.x + x;
|
||||
return r;
|
||||
}
|
||||
enum E { i, j };
|
||||
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
struct X { int y; };
|
||||
int x;
|
||||
int foo() { return 1; }
|
||||
A operator+(A o) const
|
||||
{
|
||||
A r;
|
||||
r.x = o.x + x;
|
||||
return r;
|
||||
}
|
||||
enum E { i, j };
|
||||
|
||||
};
|
||||
|
||||
struct C: A
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
2
pyste/tests/inherit3.pyste
Normal file
2
pyste/tests/inherit3.pyste
Normal file
@@ -0,0 +1,2 @@
|
||||
Class('inherit3::B', 'inherit3.h')
|
||||
Class('inherit3::C', 'inherit3.h')
|
||||
23
pyste/tests/inherit3UT.py
Normal file
23
pyste/tests/inherit3UT.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import unittest
|
||||
from _inherit3 import *
|
||||
|
||||
class testInherit3(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
def testInst(c):
|
||||
self.assertEqual(c.x, 0)
|
||||
self.assertEqual(c.foo(3), 3)
|
||||
x = c.X()
|
||||
self.assertEqual(x.y, 0)
|
||||
self.assertEqual(c.E.i, 0)
|
||||
self.assertEqual(c.E.j, 1)
|
||||
b = B()
|
||||
c = C()
|
||||
testInst(b)
|
||||
testInst(c)
|
||||
self.assertEqual(b.foo(), 1)
|
||||
self.assertEqual(c.foo(), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -10,12 +10,12 @@ import sys
|
||||
#=============================================================================
|
||||
if sys.platform == 'win32':
|
||||
|
||||
includes = '-ID:/programming/libraries/boost-cvs/boost -IC:/Python/include'
|
||||
build_pyste_cmd = 'python ../src/Pyste/pyste.py %s ' % includes
|
||||
includes = '-ID:/programming/libraries/boost-cvs/boost -ID:/Bin/Python/include'
|
||||
build_pyste_cmd = 'python ../src/Pyste/pyste.py --cache-dir=cache %s ' % includes
|
||||
compile_single_cmd = 'icl /nologo /GR /GX -c %s -I. ' % includes
|
||||
link_single_cmd = 'link /nologo /DLL '\
|
||||
'/libpath:D:/programming/libraries/boost-cvs/lib /libpath:C:/Python/libs '\
|
||||
'boost_python.lib python22.lib /out:_%s.dll '
|
||||
'/libpath:D:/programming/libraries/boost-cvs/lib /libpath:D:/Bin/Python/libs '\
|
||||
'boost_python.lib python23.lib /out:_%s.dll '
|
||||
obj_ext = 'obj'
|
||||
|
||||
#=============================================================================
|
||||
@@ -118,7 +118,7 @@ if __name__ == '__main__':
|
||||
else:
|
||||
module = None
|
||||
try:
|
||||
#main('--multiple', module)
|
||||
# main('--multiple', module)
|
||||
main('', module)
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
|
||||
Reference in New Issue
Block a user