summaryrefslogtreecommitdiff
path: root/libs/python/pyste/src
diff options
context:
space:
mode:
Diffstat (limited to 'libs/python/pyste/src')
-rw-r--r--libs/python/pyste/src/Pyste/ClassExporter.py918
-rw-r--r--libs/python/pyste/src/Pyste/CodeExporter.py26
-rw-r--r--libs/python/pyste/src/Pyste/CppParser.py247
-rw-r--r--libs/python/pyste/src/Pyste/EnumExporter.py58
-rw-r--r--libs/python/pyste/src/Pyste/Exporter.py94
-rw-r--r--libs/python/pyste/src/Pyste/FunctionExporter.py92
-rw-r--r--libs/python/pyste/src/Pyste/GCCXMLParser.py478
-rw-r--r--libs/python/pyste/src/Pyste/HeaderExporter.py81
-rw-r--r--libs/python/pyste/src/Pyste/MultipleCodeUnit.py135
-rw-r--r--libs/python/pyste/src/Pyste/SingleCodeUnit.py121
-rw-r--r--libs/python/pyste/src/Pyste/SmartFile.py60
-rw-r--r--libs/python/pyste/src/Pyste/VarExporter.py40
-rw-r--r--libs/python/pyste/src/Pyste/__init__.py6
-rw-r--r--libs/python/pyste/src/Pyste/declarations.py653
-rw-r--r--libs/python/pyste/src/Pyste/exporters.py12
-rw-r--r--libs/python/pyste/src/Pyste/exporterutils.py87
-rw-r--r--libs/python/pyste/src/Pyste/infos.py259
-rw-r--r--libs/python/pyste/src/Pyste/policies.py95
-rw-r--r--libs/python/pyste/src/Pyste/pyste.py424
-rw-r--r--libs/python/pyste/src/Pyste/settings.py21
-rw-r--r--libs/python/pyste/src/Pyste/utils.py78
21 files changed, 3985 insertions, 0 deletions
diff --git a/libs/python/pyste/src/Pyste/ClassExporter.py b/libs/python/pyste/src/Pyste/ClassExporter.py
new file mode 100644
index 000000000..decaf628e
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/ClassExporter.py
@@ -0,0 +1,918 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import exporters
+from Exporter import Exporter
+from declarations import *
+from settings import *
+from policies import *
+from SingleCodeUnit import SingleCodeUnit
+from EnumExporter import EnumExporter
+from utils import makeid, enumerate
+import copy
+import exporterutils
+import re
+
+#==============================================================================
+# ClassExporter
+#==============================================================================
+class ClassExporter(Exporter):
+ 'Generates boost.python code to export a class declaration'
+
+ def __init__(self, info, parser_tail=None):
+ Exporter.__init__(self, info, parser_tail)
+ # sections of code
+ self.sections = {}
+ # template: each item in the list is an item into the class_<...>
+ # section.
+ self.sections['template'] = []
+ # constructor: each item in the list is a parameter to the class_
+ # constructor, like class_<C>(...)
+ self.sections['constructor'] = []
+ # inside: everything within the class_<> statement
+ self.sections['inside'] = []
+ # scope: items outside the class statement but within its scope.
+ # scope* s = new scope(class<>());
+ # ...
+ # delete s;
+ self.sections['scope'] = []
+ # declarations: outside the BOOST_PYTHON_MODULE macro
+ self.sections['declaration'] = []
+ self.sections['declaration-outside'] = []
+ self.sections['include'] = []
+ # a list of Constructor instances
+ self.constructors = []
+ # a list of code units, generated by nested declarations
+ self.nested_codeunits = []
+
+
+ def ScopeName(self):
+ return makeid(self.class_.FullName()) + '_scope'
+
+
+ def Name(self):
+ return self.info.name
+
+
+ def SetDeclarations(self, declarations):
+ Exporter.SetDeclarations(self, declarations)
+ 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_ = None
+
+
+ def ClassBases(self):
+ all_bases = []
+ for level in self.class_.hierarchy:
+ for base in level:
+ all_bases.append(base)
+ return [self.GetDeclaration(x.name) for x in all_bases]
+
+
+ def Order(self):
+ '''Return the TOTAL number of bases that this class has, including the
+ bases' bases. Do this because base classes must be instantialized
+ before the derived classes in the module definition.
+ '''
+ num_bases = len(self.ClassBases())
+ return num_bases, self.class_.FullName()
+
+
+ def Export(self, codeunit, exported_names):
+ self.InheritMethods(exported_names)
+ self.MakeNonVirtual()
+ if not self.info.exclude:
+ self.ExportBasics()
+ self.ExportBases(exported_names)
+ self.ExportConstructors()
+ self.ExportVariables()
+ self.ExportVirtualMethods(codeunit)
+ self.ExportMethods()
+ self.ExportOperators()
+ self.ExportNestedClasses(exported_names)
+ self.ExportNestedEnums(exported_names)
+ self.ExportSmartPointer()
+ self.ExportOpaquePointerPolicies()
+ self.ExportAddedCode()
+ self.Write(codeunit)
+ exported_names[self.Name()] = 1
+
+
+ def InheritMethods(self, exported_names):
+ '''Go up in the class hierarchy looking for classes that were not
+ exported yet, and then add their public members to this classes
+ members, as if they were members of this class. This allows the user to
+ just export one type and automatically get all the members from the
+ base classes.
+ '''
+ valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration)
+ 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:
+ base = self.GetDeclaration(base.name)
+ if base.FullName() not in exported_names:
+ for member in base:
+ if type(member) in valid_members:
+ 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)]
+
+
+ def Write(self, codeunit):
+ indent = self.INDENT
+ boost_ns = namespaces.python
+ pyste_ns = namespaces.pyste
+ code = ''
+ # begin a scope for this class if needed
+ nested_codeunits = self.nested_codeunits
+ needs_scope = self.sections['scope'] or nested_codeunits
+ if needs_scope:
+ scope_name = self.ScopeName()
+ code += indent + boost_ns + 'scope* %s = new %sscope(\n' %\
+ (scope_name, boost_ns)
+ # export the template section
+ template_params = ', '.join(self.sections['template'])
+ code += indent + boost_ns + 'class_< %s >' % template_params
+ # export the constructor section
+ constructor_params = ', '.join(self.sections['constructor'])
+ code += '(%s)\n' % constructor_params
+ # export the inside section
+ in_indent = indent*2
+ for line in self.sections['inside']:
+ code += in_indent + line + '\n'
+ # write the scope section and end it
+ if not needs_scope:
+ code += indent + ';\n'
+ else:
+ code += indent + ');\n'
+ for line in self.sections['scope']:
+ code += indent + line + '\n'
+ # write the contents of the nested classes
+ for nested_unit in nested_codeunits:
+ code += '\n' + nested_unit.Section('module')
+ # close the scope
+ code += indent + 'delete %s;\n' % scope_name
+
+ # write the code to the module section in the codeunit
+ codeunit.Write('module', code + '\n')
+
+ # write the declarations to the codeunit
+ declarations = '\n'.join(self.sections['declaration'])
+ for nested_unit in nested_codeunits:
+ declarations += nested_unit.Section('declaration')
+ if declarations:
+ codeunit.Write('declaration', declarations + '\n')
+ declarations_outside = '\n'.join(self.sections['declaration-outside'])
+ if declarations_outside:
+ codeunit.Write('declaration-outside', declarations_outside + '\n')
+
+ # write the includes to the codeunit
+ includes = '\n'.join(self.sections['include'])
+ for nested_unit in nested_codeunits:
+ includes += nested_unit.Section('include')
+ if includes:
+ codeunit.Write('include', includes)
+
+
+ def Add(self, section, item):
+ 'Add the item into the corresponding section'
+ self.sections[section].append(item)
+
+
+ def ExportBasics(self):
+ '''Export the name of the class and its class_ statement.'''
+ class_name = self.class_.FullName()
+ self.Add('template', class_name)
+ name = self.info.rename or self.class_.name
+ self.Add('constructor', '"%s"' % name)
+
+
+ def ExportBases(self, exported_names):
+ 'Expose the bases of the class into the template section'
+ hierarchy = self.class_.hierarchy
+ exported = []
+ for level in hierarchy:
+ for base in level:
+ if base.visibility == Scope.public and base.name in exported_names:
+ exported.append(base.name)
+ if exported:
+ break
+ if exported:
+ code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
+ self.Add('template', code)
+
+
+ def ExportConstructors(self):
+ '''Exports all the public contructors of the class, plus indicates if the
+ class is noncopyable.
+ '''
+ py_ns = namespaces.python
+ indent = self.INDENT
+
+ def init_code(cons):
+ 'return the init<>() code for the given contructor'
+ param_list = [p.FullName() for p in cons.parameters]
+ min_params_list = param_list[:cons.minArgs]
+ max_params_list = param_list[cons.minArgs:]
+ min_params = ', '.join(min_params_list)
+ max_params = ', '.join(max_params_list)
+ init = py_ns + 'init< '
+ init += min_params
+ if max_params:
+ if min_params:
+ init += ', '
+ init += py_ns + ('optional< %s >' % max_params)
+ init += ' >()'
+ return init
+
+ constructors = [x for x in self.public_members if isinstance(x, Constructor)]
+ # don't export copy constructors if the class is abstract
+ # we could remove all constructors, but this will have the effect of
+ # inserting no_init in the declaration, which would not allow
+ # even subclasses to be instantiated.
+ self.constructors = constructors[:]
+ if self.class_.abstract:
+ for cons in constructors:
+ if cons.IsCopy():
+ constructors.remove(cons)
+ break
+
+ if not constructors:
+ # declare no_init
+ self.Add('constructor', py_ns + 'no_init')
+ else:
+ # write the constructor with less parameters to the constructor section
+ smaller = None
+ for cons in constructors:
+ if smaller is None or len(cons.parameters) < len(smaller.parameters):
+ smaller = cons
+ assert smaller is not None
+ self.Add('constructor', init_code(smaller))
+ constructors.remove(smaller)
+ # write the rest to the inside section, using def()
+ for cons in constructors:
+ code = '.def(%s)' % init_code(cons)
+ self.Add('inside', code)
+
+ # check if the class is copyable
+ if not self.class_.HasCopyConstructor() or self.class_.abstract:
+ self.Add('template', namespaces.boost + 'noncopyable')
+
+
+ def ExportVariables(self):
+ 'Export the variables of the class, both static and simple variables'
+ vars = [x for x in self.public_members if isinstance(x, Variable)]
+ for var in vars:
+ if self.info[var.name].exclude:
+ continue
+ name = self.info[var.name].rename or var.name
+ fullname = var.FullName()
+ if var.type.const:
+ def_ = '.def_readonly'
+ else:
+ def_ = '.def_readwrite'
+ code = '%s("%s", &%s)' % (def_, name, fullname)
+ self.Add('inside', code)
+
+
+ def OverloadName(self, method):
+ 'Returns the name of the overloads struct for the given method'
+ name = makeid(method.FullName())
+ overloads = '_overloads_%i_%i' % (method.minArgs, method.maxArgs)
+ return name + overloads
+
+
+ def GetAddedMethods(self):
+ added_methods = self.info.__added__
+ result = []
+ if added_methods:
+ for name, rename in added_methods:
+ decl = self.GetDeclaration(name)
+ self.info[name].rename = rename
+ result.append(decl)
+ return result
+
+
+ def ExportMethods(self):
+ '''Export all the non-virtual methods of this class, plus any function
+ that is to be exported as a method'''
+
+ declared = {}
+ def DeclareOverloads(m):
+ 'Declares the macro for the generation of the overloads'
+ if (isinstance(m, Method) and m.static) or type(m) == Function:
+ func = m.FullName()
+ macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS'
+ else:
+ func = m.name
+ macro = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS'
+ code = '%s(%s, %s, %i, %i)\n' % (macro, self.OverloadName(m), func, m.minArgs, m.maxArgs)
+ if code not in declared:
+ declared[code] = True
+ self.Add('declaration', code)
+
+
+ def Pointer(m):
+ 'returns the correct pointer declaration for the method m'
+ # check if this method has a wrapper set for him
+ wrapper = self.info[m.name].wrapper
+ if wrapper:
+ return '&' + wrapper.FullName()
+ else:
+ return m.PointerDeclaration()
+
+ def IsExportable(m):
+ 'Returns true if the given method is exportable by this routine'
+ ignore = (Constructor, ClassOperator, Destructor)
+ return isinstance(m, Function) and not isinstance(m, ignore) and not m.virtual
+
+ methods = [x for x in self.public_members if IsExportable(x)]
+ methods.extend(self.GetAddedMethods())
+
+ staticmethods = {}
+
+ for method in methods:
+ method_info = self.info[method.name]
+
+ # skip this method if it was excluded by the user
+ if method_info.exclude:
+ continue
+
+ # rename the method if the user requested
+ name = method_info.rename or method.name
+
+ # warn the user if this method needs a policy and doesn't have one
+ method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
+
+ # check for policies
+ policy = method_info.policy or ''
+ if policy:
+ policy = ', %s%s()' % (namespaces.python, policy.Code())
+ # check for overloads
+ overload = ''
+ if method.minArgs != method.maxArgs and not method_info.wrapper:
+ # add the overloads for this method
+ DeclareOverloads(method)
+ overload_name = self.OverloadName(method)
+ overload = ', %s%s()' % (namespaces.pyste, overload_name)
+
+ # build the .def string to export the method
+ pointer = Pointer(method)
+ code = '.def("%s", %s' % (name, pointer)
+ code += policy
+ code += overload
+ code += ')'
+ self.Add('inside', code)
+ # static method
+ if isinstance(method, Method) and method.static:
+ staticmethods[name] = 1
+ # add wrapper code if this method has one
+ wrapper = method_info.wrapper
+ if wrapper and wrapper.code:
+ self.Add('declaration', wrapper.code)
+
+ # export staticmethod statements
+ for name in staticmethods:
+ code = '.staticmethod("%s")' % name
+ self.Add('inside', code)
+
+
+
+ def MakeNonVirtual(self):
+ '''Make all methods that the user indicated to no_override no more virtual, delegating their
+ export to the ExportMethods routine'''
+ for member in self.class_:
+ if type(member) == Method and member.virtual:
+ member.virtual = not self.info[member.name].no_override
+
+
+ def ExportVirtualMethods(self, codeunit):
+ # check if this class has any virtual methods
+ has_virtual_methods = False
+ for member in self.class_:
+ if type(member) == Method and member.virtual:
+ has_virtual_methods = True
+ break
+
+ holder = self.info.holder
+ if has_virtual_methods:
+ generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info, codeunit)
+ 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 = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -= '\
+ '*= /= %= ^= &= |= <<= >>='.split()
+ # create a map for faster lookup
+ BOOST_SUPPORTED_OPERATORS = dict(zip(BOOST_SUPPORTED_OPERATORS, range(len(BOOST_SUPPORTED_OPERATORS))))
+
+ # a dict of operators that are not directly supported by boost, but can be exposed
+ # simply as a function with a special name
+ BOOST_RENAME_OPERATORS = {
+ '()' : '__call__',
+ }
+
+ # converters which have a special name in python
+ # it's a map of a regular expression of the converter's result to the
+ # appropriate python name
+ SPECIAL_CONVERTERS = {
+ re.compile(r'(const)?\s*double$') : '__float__',
+ re.compile(r'(const)?\s*float$') : '__float__',
+ re.compile(r'(const)?\s*int$') : '__int__',
+ re.compile(r'(const)?\s*long$') : '__long__',
+ re.compile(r'(const)?\s*char\s*\*?$') : '__str__',
+ re.compile(r'(const)?.*::basic_string<.*>\s*(\*|\&)?$') : '__str__',
+ }
+
+
+ def ExportOperators(self):
+ 'Export all member operators and free operators related to this class'
+
+ def GetFreeOperators():
+ 'Get all the free (global) operators related to this class'
+ operators = []
+ for decl in self.declarations:
+ if isinstance(decl, Operator):
+ # check if one of the params is this class
+ for param in decl.parameters:
+ if param.name == self.class_.FullName():
+ operators.append(decl)
+ break
+ return operators
+
+ def GetOperand(param):
+ 'Returns the operand of this parameter (either "self", or "other<type>")'
+ if param.name == self.class_.FullName():
+ return namespaces.python + 'self'
+ else:
+ return namespaces.python + ('other< %s >()' % param.name)
+
+
+ def HandleSpecialOperator(operator):
+ # gatter information about the operator and its parameters
+ result_name = operator.result.name
+ param1_name = ''
+ if operator.parameters:
+ param1_name = operator.parameters[0].name
+
+ # check for str
+ ostream = 'basic_ostream'
+ is_str = result_name.find(ostream) != -1 and param1_name.find(ostream) != -1
+ if is_str:
+ namespace = namespaces.python + 'self_ns::'
+ self_ = namespaces.python + 'self'
+ return '.def(%sstr(%s))' % (namespace, self_)
+
+ # is not a special operator
+ return None
+
+
+
+ frees = GetFreeOperators()
+ members = [x for x in self.public_members if type(x) == ClassOperator]
+ all_operators = frees + members
+ operators = [x for x in all_operators if not self.info['operator'][x.name].exclude]
+
+ for operator in operators:
+ # gatter information about the operator, for use later
+ wrapper = self.info['operator'][operator.name].wrapper
+ if wrapper:
+ pointer = '&' + wrapper.FullName()
+ if wrapper.code:
+ self.Add('declaration-outside', wrapper.code)
+ else:
+ pointer = operator.PointerDeclaration()
+ rename = self.info['operator'][operator.name].rename
+
+ # check if this operator will be exported as a method
+ export_as_method = wrapper or rename or operator.name in self.BOOST_RENAME_OPERATORS
+
+ # check if this operator has a special representation in boost
+ special_code = HandleSpecialOperator(operator)
+ has_special_representation = special_code is not None
+
+ if export_as_method:
+ # export this operator as a normal method, renaming or using the given wrapper
+ if not rename:
+ if wrapper:
+ rename = wrapper.name
+ else:
+ rename = self.BOOST_RENAME_OPERATORS[operator.name]
+ policy = ''
+ policy_obj = self.info['operator'][operator.name].policy
+ if policy_obj:
+ policy = ', %s()' % policy_obj.Code()
+ self.Add('inside', '.def("%s", %s%s)' % (rename, pointer, policy))
+
+ elif has_special_representation:
+ self.Add('inside', special_code)
+
+ elif operator.name in self.BOOST_SUPPORTED_OPERATORS:
+ # export this operator using boost's facilities
+ op = operator
+ is_unary = isinstance(op, Operator) and len(op.parameters) == 1 or\
+ isinstance(op, ClassOperator) and len(op.parameters) == 0
+ if is_unary:
+ self.Add('inside', '.def( %s%sself )' % \
+ (operator.name, namespaces.python))
+ else:
+ # binary operator
+ if len(operator.parameters) == 2:
+ left_operand = GetOperand(operator.parameters[0])
+ right_operand = GetOperand(operator.parameters[1])
+ else:
+ left_operand = namespaces.python + 'self'
+ right_operand = GetOperand(operator.parameters[0])
+ self.Add('inside', '.def( %s %s %s )' % \
+ (left_operand, operator.name, right_operand))
+
+ # export the converters.
+ # export them as simple functions with a pre-determined name
+
+ converters = [x for x in self.public_members if type(x) == ConverterOperator]
+
+ def ConverterMethodName(converter):
+ result_fullname = converter.result.FullName()
+ result_name = converter.result.name
+ for regex, method_name in self.SPECIAL_CONVERTERS.items():
+ if regex.match(result_fullname):
+ return method_name
+ else:
+ # extract the last name from the full name
+ result_name = makeid(result_name)
+ return 'to_' + result_name
+
+ for converter in converters:
+ info = self.info['operator'][converter.result.FullName()]
+ # check if this operator should be excluded
+ if info.exclude:
+ continue
+
+ special_code = HandleSpecialOperator(converter)
+ if info.rename or not special_code:
+ # export as method
+ name = info.rename or ConverterMethodName(converter)
+ pointer = converter.PointerDeclaration()
+ policy_code = ''
+ if info.policy:
+ policy_code = ', %s()' % info.policy.Code()
+ self.Add('inside', '.def("%s", %s%s)' % (name, pointer, policy_code))
+
+ elif special_code:
+ self.Add('inside', special_code)
+
+
+
+ def ExportNestedClasses(self, exported_names):
+ nested_classes = [x for x in self.public_members if isinstance(x, NestedClass)]
+ for nested_class in nested_classes:
+ nested_info = self.info[nested_class.name]
+ nested_info.include = self.info.include
+ nested_info.name = nested_class.FullName()
+ exporter = self.__class__(nested_info)
+ exporter.SetDeclarations(self.declarations)
+ codeunit = SingleCodeUnit(None, None)
+ exporter.Export(codeunit, exported_names)
+ self.nested_codeunits.append(codeunit)
+
+
+ def ExportNestedEnums(self, exported_names):
+ nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)]
+ for enum in nested_enums:
+ enum_info = self.info[enum.name]
+ enum_info.include = self.info.include
+ enum_info.name = enum.FullName()
+ exporter = EnumExporter(enum_info)
+ exporter.SetDeclarations(self.declarations)
+ codeunit = SingleCodeUnit(None, None)
+ exporter.Export(codeunit, exported_names)
+ self.nested_codeunits.append(codeunit)
+
+
+ def ExportSmartPointer(self):
+ smart_ptr = self.info.smart_ptr
+ if smart_ptr:
+ class_name = self.class_.FullName()
+ smart_ptr = smart_ptr % class_name
+ self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
+
+
+ def ExportOpaquePointerPolicies(self):
+ # check all methods for 'return_opaque_pointer' policies
+ methods = [x for x in self.public_members if isinstance(x, Method)]
+ for method in methods:
+ return_opaque_policy = return_value_policy(return_opaque_pointer)
+ if self.info[method.name].policy == return_opaque_policy:
+ macro = exporterutils.EspecializeTypeID(method.result.name)
+ if macro:
+ self.Add('declaration-outside', macro)
+
+ def ExportAddedCode(self):
+ if self.info.__code__:
+ for code in self.info.__code__:
+ self.Add('inside', code)
+
+
+#==============================================================================
+# Virtual Wrapper utils
+#==============================================================================
+
+def _ParamsInfo(m, count=None):
+ if count is None:
+ count = len(m.parameters)
+ param_names = ['p%i' % i for i in range(count)]
+ param_types = [x.FullName() for x in m.parameters[:count]]
+ params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)]
+ #for i, p in enumerate(m.parameters[:count]):
+ # if p.default is not None:
+ # #params[i] += '=%s' % p.default
+ # params[i] += '=%s' % (p.name + '()')
+ params = ', '.join(params)
+ return params, param_names, param_types
+
+
+class _VirtualWrapperGenerator(object):
+ 'Generates code to export the virtual methods of the given class'
+
+ def __init__(self, class_, bases, info, codeunit):
+ self.class_ = copy.deepcopy(class_)
+ self.bases = bases[:]
+ self.info = info
+ self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
+ self.virtual_methods = None
+ self._method_count = {}
+ self.codeunit = codeunit
+ self.GenerateVirtualMethods()
+
+
+ SELF = 'py_self'
+
+
+ def DefaultImplementationNames(self, method):
+ '''Returns a list of default implementations for this method, one for each
+ number of default arguments. Always returns at least one name, and return from
+ the one with most arguments to the one with the least.
+ '''
+ base_name = 'default_' + method.name
+ minArgs = method.minArgs
+ maxArgs = method.maxArgs
+ if minArgs == maxArgs:
+ return [base_name]
+ else:
+ return [base_name + ('_%i' % i) for i in range(minArgs, maxArgs+1)]
+
+
+ def Declaration(self, method, indent):
+ '''Returns a string with the declarations of the virtual wrapper and
+ its default implementations. This string must be put inside the Wrapper
+ body.
+ '''
+ pyste = namespaces.pyste
+ python = namespaces.python
+ rename = self.info[method.name].rename or method.name
+ result = method.result.FullName()
+ return_str = 'return '
+ if result == 'void':
+ return_str = ''
+ params, param_names, param_types = _ParamsInfo(method)
+ constantness = ''
+ if method.const:
+ constantness = ' const'
+
+ # call_method callback
+ 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
+
+ self_str = self.SELF
+
+ decl += indent*2 + '%(return_str)s%(python)scall_method< %(result)s >' \
+ '(%(self_str)s, "%(rename)s"%(param_names_str)s);\n' % locals()
+ decl += indent + '}\n'
+
+ # 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 indent2 + '%s%s(%s);\n' % \
+ (return_str, method.FullName(), ', '.join(param_names))
+ else:
+ if wrapper.code:
+ self.codeunit.Write('declaration-outside', wrapper.code)
+ # return a call for the wrapper
+ params = ', '.join(['this'] + param_names)
+ return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
+
+ if not method.abstract and method.visibility != Scope.private:
+ minArgs = method.minArgs
+ maxArgs = method.maxArgs
+ impl_names = self.DefaultImplementationNames(method)
+ for impl_name, argNum in zip(impl_names, range(minArgs, maxArgs+1)):
+ params, param_names, param_types = _ParamsInfo(method, argNum)
+ decl += '\n'
+ decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
+ decl += DefaultImpl(method, param_names)
+ decl += indent + '}\n'
+ return decl
+
+
+ def MethodDefinition(self, method):
+ '''Returns a list of lines, which should be put inside the class_
+ statement to export this method.'''
+ # dont define abstract methods
+ pyste = namespaces.pyste
+ rename = self.info[method.name].rename or method.name
+ default_names = self.DefaultImplementationNames(method)
+ class_name = self.class_.FullName()
+ wrapper_name = pyste + self.wrapper_name
+ result = method.result.FullName()
+ is_method_unique = method.is_unique
+ constantness = ''
+ if method.const:
+ constantness = ' const'
+
+ # create a list of default-impl pointers
+ minArgs = method.minArgs
+ maxArgs = method.maxArgs
+ if method.abstract:
+ default_pointers = []
+ elif is_method_unique:
+ default_pointers = ['&%s::%s' % (wrapper_name, x) for x in default_names]
+ else:
+ default_pointers = []
+ for impl_name, argNum in zip(default_names, range(minArgs, maxArgs+1)):
+ param_list = [x.FullName() for x in method.parameters[:argNum]]
+ params = ', '.join(param_list)
+ signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness)
+ default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name)
+ default_pointers.append(default_pointer)
+
+ # get the pointer of the method
+ pointer = method.PointerDeclaration()
+ if method.abstract:
+ pointer = namespaces.python + ('pure_virtual(%s)' % pointer)
+
+ # warn the user if this method needs a policy and doesn't have one
+ method_info = self.info[method.name]
+ method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
+
+ # Add policy to overloaded methods also
+ policy = method_info.policy or ''
+ if policy:
+ policy = ', %s%s()' % (namespaces.python, policy.Code())
+
+ # generate the defs
+ definitions = []
+ # basic def
+ if default_pointers:
+ definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy))
+ for default_pointer in default_pointers[:-1]:
+ definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy))
+ else:
+ definitions.append('.def("%s", %s%s)' % (rename, pointer, policy))
+ return definitions
+
+
+ def FullName(self):
+ return namespaces.pyste + self.wrapper_name
+
+
+ def GenerateVirtualMethods(self):
+ '''To correctly export all virtual methods, we must also make wrappers
+ for the virtual methods of the bases of this class, as if the methods
+ were from this class itself.
+ This method creates the instance variable self.virtual_methods.
+ '''
+ def IsVirtual(m):
+ if type(m) is Method:
+ pure_virtual = m.abstract and m.virtual
+ virtual = m.virtual and m.visibility != Scope.private
+ return virtual or pure_virtual
+ else:
+ return False
+
+ # 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'
+ else:
+ const = ''
+ if method.result:
+ result = method.result.FullName()
+ else:
+ result = ''
+ params = ', '.join([x.FullName() for x in method.parameters])
+ 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:
+ self.virtual_methods.append(member)
+ already_added[sig] = 0
+
+
+ def Constructors(self):
+ return self.class_.Constructors(publics_only=True)
+
+
+ def GenerateDefinitions(self):
+ defs = []
+ 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 exclude:
+ defs.extend(self.MethodDefinition(method))
+ return defs
+
+
+ def GenerateVirtualWrapper(self, indent):
+ 'Return the wrapper for this class'
+
+ # generate the class code
+ class_name = self.class_.FullName()
+ code = 'struct %s: %s\n' % (self.wrapper_name, class_name)
+ code += '{\n'
+ # generate constructors (with the overloads for each one)
+ for cons in self.Constructors(): # only public constructors
+ minArgs = cons.minArgs
+ maxArgs = cons.maxArgs
+ # from the min number of arguments to the max number, generate
+ # all version of the given constructor
+ cons_code = ''
+ for argNum in range(minArgs, maxArgs+1):
+ params, param_names, param_types = _ParamsInfo(cons, argNum)
+ if params:
+ params = ', ' + params
+ cons_code += indent + '%s(PyObject* %s_%s):\n' % \
+ (self.wrapper_name, self.SELF, params)
+ cons_code += indent*2 + '%s(%s), %s(%s_) {}\n\n' % \
+ (class_name, ', '.join(param_names), self.SELF, self.SELF)
+ code += cons_code
+ # generate the body
+ body = []
+ for method in self.virtual_methods:
+ if not self.info[method.name].exclude:
+ body.append(self.Declaration(method, indent))
+ body = '\n'.join(body)
+ code += body + '\n'
+ # add the self member
+ code += indent + 'PyObject* %s;\n' % self.SELF
+ code += '};\n'
+ return code
diff --git a/libs/python/pyste/src/Pyste/CodeExporter.py b/libs/python/pyste/src/Pyste/CodeExporter.py
new file mode 100644
index 000000000..382fffbd5
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/CodeExporter.py
@@ -0,0 +1,26 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+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
diff --git a/libs/python/pyste/src/Pyste/CppParser.py b/libs/python/pyste/src/Pyste/CppParser.py
new file mode 100644
index 000000000..be68a448a
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/CppParser.py
@@ -0,0 +1,247 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+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, cache_dir=None, version=None, gccxml_path = 'gccxml'):
+ 'includes and defines ar the directives given to gcc'
+ if includes is None:
+ includes = []
+ if defines is None:
+ defines = []
+ self.includes = includes
+ self.gccxml_path = gccxml_path
+ self.defines = defines
+ self.version = version
+ #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 __del__(self):
+ self.Close()
+
+
+ def _IncludeParams(self, filename):
+ includes = self.includes[:]
+ filedir = os.path.dirname(filename)
+ if not filedir:
+ filedir = '.'
+ includes.insert(0, filedir)
+ includes = ['-I "%s"' % self.Unixfy(x) for x in includes]
+ return ' '.join(includes)
+
+
+ def _DefineParams(self):
+ defines = ['-D "%s"' % x for x in self.defines]
+ return ' '.join(defines)
+
+
+ def FindHeader(self, header):
+ if os.path.isfile(header):
+ return header
+ for path in self.includes:
+ filename = os.path.join(path, header)
+ if os.path.isfile(filename):
+ return filename
+ else:
+ name = os.path.basename(header)
+ raise RuntimeError, 'Header file "%s" not found!' % name
+
+
+ def AppendTail(self, filename, tail):
+ '''Creates a temporary file, appends the text tail to it, and returns
+ the filename of the file.
+ '''
+ if hasattr(tempfile, 'mkstemp'):
+ f_no, temp = tempfile.mkstemp('.h')
+ f = file(temp, 'a')
+ os.close(f_no)
+ else:
+ temp = tempfile.mktemp('.h')
+ f = file(temp, 'a')
+ f.write('#include "%s"\n\n' % os.path.abspath(filename))
+ f.write(tail)
+ f.write('\n')
+ f.close()
+ return temp
+
+
+ def Unixfy(self, path):
+ return path.replace('\\', '/')
+
+
+ def ParseWithGCCXML(self, header, tail):
+ '''Parses the given header using gccxml and GCCXMLParser.
+ '''
+ header = self.FindHeader(header)
+ if tail:
+ filename = self.AppendTail(header, tail)
+ else:
+ filename = header
+ xmlfile = tempfile.mktemp('.xml')
+ try:
+ # get the params
+ includes = self._IncludeParams(filename)
+ defines = self._DefineParams()
+ # call gccxml
+ cmd = '%s %s %s "%s" -fxml=%s'
+ filename = self.Unixfy(filename)
+ xmlfile = self.Unixfy(xmlfile)
+ status = os.system(cmd % (self.gccxml_path, 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
+ finally:
+ if settings.DEBUG and os.path.isfile(xmlfile):
+ debugname = os.path.basename(header)
+ debugname = os.path.splitext(debugname)[0] + '.xml'
+ print 'DEBUG:', debugname
+ shutil.copy(xmlfile, debugname)
+ # delete the temporary files
+ try:
+ os.remove(xmlfile)
+ if tail:
+ 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 = tail.strip()
+ declarations = self.GetCache(header, interface, tail)
+ if declarations is None:
+ declarations = self.ParseWithGCCXML(header, tail)
+ self.CreateCache(header, interface, tail, declarations)
+ header_fullpath = os.path.abspath(self.FindHeader(header))
+ return declarations, header_fullpath
+
+
+ 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:
+ version = load(f)
+ if version != self.version:
+ return None
+ 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:
+ version = load(f)
+ cache = load(f)
+ finally:
+ f.close()
+ else:
+ cache = {}
+ cache[key] = declarations
+ self.cache_files.append(cache_file)
+ f = file(cache_file, 'wb')
+ try:
+ dump(self.version, f, 1)
+ 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)
diff --git a/libs/python/pyste/src/Pyste/EnumExporter.py b/libs/python/pyste/src/Pyste/EnumExporter.py
new file mode 100644
index 000000000..0107fbee3
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/EnumExporter.py
@@ -0,0 +1,58 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from Exporter import Exporter
+from settings import *
+import utils
+
+#==============================================================================
+# EnumExporter
+#==============================================================================
+class EnumExporter(Exporter):
+ 'Exports enumerators'
+
+ def __init__(self, info):
+ Exporter.__init__(self, info)
+
+
+ def SetDeclarations(self, declarations):
+ Exporter.SetDeclarations(self, declarations)
+ if self.declarations:
+ self.enum = self.GetDeclaration(self.info.name)
+ else:
+ self.enum = None
+
+ def Export(self, codeunit, exported_names):
+ if self.info.exclude:
+ return
+ indent = self.INDENT
+ in_indent = self.INDENT*2
+ rename = self.info.rename or self.enum.name
+ full_name = self.enum.FullName()
+ unnamed_enum = False
+ if rename.startswith('$_') or rename.startswith('._'):
+ unnamed_enum = True
+ code = ''
+ if not unnamed_enum:
+ code += indent + namespaces.python
+ code += 'enum_< %s >("%s")\n' % (full_name, rename)
+ for name in self.enum.values:
+ rename = self.info[name].rename or name
+ value_fullname = self.enum.ValueFullName(name)
+ if not unnamed_enum:
+ code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
+ else:
+ code += indent + namespaces.python
+ code += 'scope().attr("%s") = (int)%s;\n' % (rename, value_fullname )
+ if self.info.export_values and not unnamed_enum:
+ code += in_indent + '.export_values()\n'
+ if not unnamed_enum:
+ code += indent + ';\n'
+ code += '\n'
+ codeunit.Write('module', code)
+ exported_names[self.enum.FullName()] = 1
+
+ def Name(self):
+ return self.info.name
diff --git a/libs/python/pyste/src/Pyste/Exporter.py b/libs/python/pyste/src/Pyste/Exporter.py
new file mode 100644
index 000000000..d87b37c58
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/Exporter.py
@@ -0,0 +1,94 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import os.path
+
+#==============================================================================
+# Exporter
+#==============================================================================
+class Exporter(object):
+ 'Base class for objects capable to generate boost.python code.'
+
+ INDENT = ' ' * 4
+
+ def __init__(self, info, parser_tail=None):
+ self.info = info
+ self.parser_tail = parser_tail
+ self.interface_file = None
+ self.declarations = []
+
+
+ def Name(self):
+ raise NotImplementedError(self.__class__.__name__)
+
+
+ def Tail(self):
+ return self.parser_tail
+
+
+ def Parse(self, parser):
+ self.parser = parser
+ header = self.info.include
+ tail = self.parser_tail
+ declarations, parser_header = parser.parse(header, tail)
+ self.parser_header = parser_header
+ self.SetDeclarations(declarations)
+
+
+ def SetParsedHeader(self, parsed_header):
+ self.parser_header = parsed_header
+
+
+ def SetDeclarations(self, declarations):
+ self.declarations = declarations
+
+
+ def GenerateCode(self, codeunit, exported_names):
+ self.WriteInclude(codeunit)
+ self.Export(codeunit, exported_names)
+
+
+ def WriteInclude(self, codeunit):
+ codeunit.Write('include', '#include <%s>\n' % self.info.include)
+
+
+ def Export(self, codeunit, exported_names):
+ 'subclasses must override this to do the real work'
+ pass
+
+
+ def GetDeclarations(self, fullname):
+ decls = []
+ for decl in self.declarations:
+ if decl.FullName() == fullname:
+ decls.append(decl)
+ if not decls:
+ raise RuntimeError, 'no %s declaration found!' % fullname
+ return decls
+
+
+ def GetDeclaration(self, fullname):
+ decls = self.GetDeclarations(fullname)
+ #assert len(decls) == 1
+ return decls[0]
+
+
+ def Order(self):
+ '''Returns a string that uniquely identifies this instance. All
+ exporters will be sorted by Order before being exported.
+ '''
+ return 0, self.info.name
+
+
+ def Header(self):
+ return self.info.include
+
+
+ def __eq__(self, other):
+ return type(self) is type(other) and self.Name() == other.Name() \
+ and self.interface_file == other.interface_file
+
+ def __ne__(self, other):
+ return not self == other
diff --git a/libs/python/pyste/src/Pyste/FunctionExporter.py b/libs/python/pyste/src/Pyste/FunctionExporter.py
new file mode 100644
index 000000000..5765f65e9
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/FunctionExporter.py
@@ -0,0 +1,92 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from Exporter import Exporter
+from policies import *
+from declarations import *
+from settings import *
+import utils
+import exporterutils
+
+
+#==============================================================================
+# FunctionExporter
+#==============================================================================
+class FunctionExporter(Exporter):
+ 'Generates boost.python code to export the given function.'
+
+ def __init__(self, info, tail=None):
+ Exporter.__init__(self, info, tail)
+
+
+ def Export(self, codeunit, exported_names):
+ if not self.info.exclude:
+ decls = self.GetDeclarations(self.info.name)
+ for decl in decls:
+ self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy)
+ self.ExportDeclaration(decl, len(decls) == 1, codeunit)
+ self.ExportOpaquePointer(decl, codeunit)
+ self.GenerateOverloads(decls, codeunit)
+ exported_names[self.Name()] = 1
+
+
+ def ExportDeclaration(self, decl, unique, codeunit):
+ name = self.info.rename or decl.name
+ defs = namespaces.python + 'def("%s", ' % name
+ wrapper = self.info.wrapper
+ if wrapper:
+ pointer = '&' + wrapper.FullName()
+ else:
+ pointer = decl.PointerDeclaration()
+ defs += pointer
+ defs += self.PolicyCode()
+ overload = self.OverloadName(decl)
+ if overload:
+ defs += ', %s()' % (namespaces.pyste + overload)
+ defs += ');'
+ codeunit.Write('module', self.INDENT + defs + '\n')
+ # add the code of the wrapper
+ if wrapper and wrapper.code:
+ codeunit.Write('declaration', wrapper.code + '\n')
+
+
+ def OverloadName(self, decl):
+ if decl.minArgs != decl.maxArgs:
+ return '%s_overloads_%i_%i' % \
+ (decl.name, decl.minArgs, decl.maxArgs)
+ else:
+ return ''
+
+
+ def GenerateOverloads(self, declarations, codeunit):
+ codes = {}
+ for decl in declarations:
+ overload = self.OverloadName(decl)
+ if overload and overload not in codes:
+ code = 'BOOST_PYTHON_FUNCTION_OVERLOADS(%s, %s, %i, %i)' %\
+ (overload, decl.FullName(), decl.minArgs, decl.maxArgs)
+ codeunit.Write('declaration', code + '\n')
+ codes[overload] = None
+
+
+ def PolicyCode(self):
+ policy = self.info.policy
+ if policy is not None:
+ assert isinstance(policy, Policy)
+ return ', %s()' % policy.Code()
+ else:
+ return ''
+
+
+ def ExportOpaquePointer(self, function, codeunit):
+ if self.info.policy == return_value_policy(return_opaque_pointer):
+ typename = function.result.name
+ macro = exporterutils.EspecializeTypeID(typename)
+ if macro:
+ codeunit.Write('declaration-outside', macro)
+
+
+ def Name(self):
+ return self.info.name
diff --git a/libs/python/pyste/src/Pyste/GCCXMLParser.py b/libs/python/pyste/src/Pyste/GCCXMLParser.py
new file mode 100644
index 000000000..4a1017204
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/GCCXMLParser.py
@@ -0,0 +1,478 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from declarations import *
+try:
+ # try to use internal elementtree
+ from xml.etree.cElementTree import ElementTree
+except ImportError:
+ # try to use cElementTree if avaiable
+ try:
+ from cElementTree import ElementTree
+ except ImportError:
+ # fall back to the normal elementtree
+ from elementtree.ElementTree import ElementTree
+from xml.parsers.expat import ExpatError
+from copy import deepcopy
+from utils import enumerate
+
+
+#==============================================================================
+# Exceptions
+#==============================================================================
+class InvalidXMLError(Exception): pass
+
+class ParserError(Exception): pass
+
+class InvalidContextError(ParserError): pass
+
+
+#==============================================================================
+# GCCXMLParser
+#==============================================================================
+class GCCXMLParser(object):
+ 'Parse a GCC_XML file and extract the top-level declarations.'
+
+ interested_tags = {'Class':0, 'Function':0, 'Variable':0, 'Enumeration':0}
+
+ def Parse(self, filename):
+ self.elements = self.GetElementsFromXML(filename)
+ # high level declarations
+ self.declarations = []
+ self._names = {}
+ # parse the elements
+ for id in self.elements:
+ element, decl = self.elements[id]
+ if decl is None:
+ try:
+ self.ParseElement(id, element)
+ except InvalidContextError:
+ pass # ignore those nodes with invalid context
+ # (workaround gccxml bug)
+
+
+ def Declarations(self):
+ return self.declarations
+
+
+ def AddDecl(self, decl):
+ if decl.FullName() in self._names:
+ decl.is_unique= False
+ for d in self.declarations:
+ if d.FullName() == decl.FullName():
+ d.is_unique = False
+ self._names[decl.FullName()] = 0
+ self.declarations.append(decl)
+
+
+ def ParseElement(self, id, element):
+ method = 'Parse' + element.tag
+ if hasattr(self, method):
+ func = getattr(self, method)
+ func(id, element)
+ else:
+ self.ParseUnknown(id, element)
+
+
+ def GetElementsFromXML(self,filename):
+ 'Extracts a dictionary of elements from the gcc_xml file.'
+
+ tree = ElementTree()
+ try:
+ tree.parse(filename)
+ except ExpatError:
+ raise InvalidXMLError, 'Not a XML file: %s' % filename
+
+ root = tree.getroot()
+ if root.tag != 'GCC_XML':
+ raise InvalidXMLError, 'Not a valid GCC_XML file'
+
+ # build a dictionary of id -> element, None
+ elementlist = root.getchildren()
+ elements = {}
+ for element in elementlist:
+ id = element.get('id')
+ if id:
+ elements[id] = element, None
+ return elements
+
+
+ def GetDecl(self, id):
+ if id not in self.elements:
+ if id == '_0':
+ raise InvalidContextError, 'Invalid context found in the xml file.'
+ else:
+ msg = 'ID not found in elements: %s' % id
+ raise ParserError, msg
+
+ elem, decl = self.elements[id]
+ if decl is None:
+ self.ParseElement(id, elem)
+ elem, decl = self.elements[id]
+ if decl is None:
+ raise ParserError, 'Could not parse element: %s' % elem.tag
+ return decl
+
+
+ def GetType(self, id):
+ def Check(id, feature):
+ pos = id.find(feature)
+ if pos != -1:
+ id = id[:pos] + id[pos+1:]
+ return True, id
+ else:
+ return False, id
+ const, id = Check(id, 'c')
+ volatile, id = Check(id, 'v')
+ restricted, id = Check(id, 'r')
+ decl = self.GetDecl(id)
+ if isinstance(decl, Type):
+ res = deepcopy(decl)
+ if const:
+ res.const = const
+ if volatile:
+ res.volatile = volatile
+ if restricted:
+ res.restricted = restricted
+ else:
+ res = Type(decl.FullName(), const)
+ res.volatile = volatile
+ res.restricted = restricted
+ return res
+
+
+ def GetLocation(self, location):
+ file, line = location.split(':')
+ file = self.GetDecl(file)
+ return file, int(line)
+
+
+ def Update(self, id, decl):
+ element, _ = self.elements[id]
+ self.elements[id] = element, decl
+
+
+ def ParseUnknown(self, id, element):
+ name = '__Unknown_Element_%s' % id
+ decl = Unknown(name)
+ self.Update(id, decl)
+
+
+ def ParseNamespace(self, id, element):
+ namespace = element.get('name')
+ context = element.get('context')
+ if context:
+ outer = self.GetDecl(context)
+ if not outer.endswith('::'):
+ outer += '::'
+ namespace = outer + namespace
+ if namespace.startswith('::'):
+ namespace = namespace[2:]
+ self.Update(id, namespace)
+
+
+ def ParseFile(self, id, element):
+ filename = element.get('name')
+ self.Update(id, filename)
+
+
+ def ParseVariable(self, id, element):
+ # in gcc_xml, a static Field is declared as a Variable, so we check
+ # this and call the Field parser.
+ context = self.GetDecl(element.get('context'))
+ if isinstance(context, Class):
+ self.ParseField(id, element)
+ elem, decl = self.elements[id]
+ decl.static = True
+ else:
+ namespace = context
+ name = element.get('name')
+ type_ = self.GetType(element.get('type'))
+ location = self.GetLocation(element.get('location'))
+ variable = Variable(type_, name, namespace)
+ variable.location = location
+ self.AddDecl(variable)
+ self.Update(id, variable)
+
+
+ def GetArguments(self, element):
+ args = []
+ for child in element:
+ if child.tag == 'Argument':
+ type = self.GetType(child.get('type'))
+ type.default = child.get('default')
+ args.append(type)
+ 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.'''
+ name = element.get('name')
+ returns = self.GetType(element.get('returns'))
+ namespace = self.GetDecl(element.get('context'))
+ location = self.GetLocation(element.get('location'))
+ params = self.GetArguments(element)
+ incomplete = bool(int(element.get('incomplete', 0)))
+ throws = self.GetExceptions(element.get('throw', None))
+ function = functionType(name, namespace, returns, params, throws)
+ function.location = location
+ self.AddDecl(function)
+ self.Update(id, function)
+
+
+ def ParseOperatorFunction(self, id, element):
+ self.ParseFunction(id, element, Operator)
+
+
+ def GetHierarchy(self, bases):
+ '''Parses the string "bases" from the xml into a list of tuples of Base
+ instances. The first tuple is the most direct inheritance, and then it
+ goes up in the hierarchy.
+ '''
+
+ if bases is None:
+ return []
+ base_names = bases.split()
+ this_level = []
+ next_levels = []
+ for base in base_names:
+ # get the visibility
+ split = base.split(':')
+ if len(split) == 2:
+ visib = split[0]
+ base = split[1]
+ else:
+ visib = Scope.public
+ decl = self.GetDecl(base)
+ if not isinstance(decl, Class):
+ # on windows, there are some classes which "bases" points to an
+ # "Unimplemented" tag, but we are not interested in this classes
+ # anyway
+ continue
+ base = Base(decl.FullName(), visib)
+ this_level.append(base)
+ # normalize with the other levels
+ for index, level in enumerate(decl.hierarchy):
+ if index < len(next_levels):
+ next_levels[index] = next_levels[index] + level
+ else:
+ next_levels.append(level)
+ hierarchy = []
+ if this_level:
+ hierarchy.append(tuple(this_level))
+ if next_levels:
+ hierarchy.extend(next_levels)
+ return hierarchy
+
+
+ def GetMembers(self, member_list):
+ # members must be a string with the ids of the members
+ if member_list is None:
+ return []
+ members = []
+ for member in member_list.split():
+ decl = self.GetDecl(member)
+ if type(decl) in Class.ValidMemberTypes():
+ members.append(decl)
+ return members
+
+
+ def ParseClass(self, id, element):
+ name = element.get('name')
+ abstract = bool(int(element.get('abstract', '0')))
+ location = self.GetLocation(element.get('location'))
+ context = self.GetDecl(element.get('context'))
+ incomplete = bool(int(element.get('incomplete', 0)))
+ if isinstance(context, str):
+ class_ = Class(name, context, [], abstract)
+ else:
+ # a nested class
+ visib = element.get('access', Scope.public)
+ class_ = NestedClass(
+ name, context.FullName(), visib, [], abstract)
+ class_.incomplete = incomplete
+ # we have to add the declaration of the class before trying
+ # to parse its members and bases, to avoid recursion.
+ self.AddDecl(class_)
+ class_.location = location
+ self.Update(id, class_)
+ # now we can get the members and the bases
+ class_.hierarchy = self.GetHierarchy(element.get('bases'))
+ if class_.hierarchy:
+ class_.bases = class_.hierarchy[0]
+ members = self.GetMembers(element.get('members'))
+ for member in members:
+ class_.AddMember(member)
+
+
+ def ParseStruct(self, id, element):
+ self.ParseClass(id, element)
+
+
+ FUNDAMENTAL_RENAME = {
+ 'long long int' : 'boost::int64_t',
+ 'long long unsigned int' : 'boost::uint64_t',
+ }
+
+ def ParseFundamentalType(self, id, element):
+ name = element.get('name')
+ name = self.FUNDAMENTAL_RENAME.get(name, name)
+ type_ = FundamentalType(name)
+ self.Update(id, type_)
+
+
+ def ParseArrayType(self, id, element):
+ type = self.GetType(element.get('type'))
+ min = element.get('min')
+ max = element.get('max')
+ array = ArrayType(type.name, type.const, min, max)
+ self.Update(id, array)
+
+
+ def ParseReferenceType(self, id, element):
+ type = self.GetType(element.get('type'))
+ expand = not isinstance(type, FunctionType)
+ ref = ReferenceType(type.name, type.const, None, expand, type.suffix)
+ self.Update(id, ref)
+
+
+ def ParsePointerType(self, id, element):
+ type = self.GetType(element.get('type'))
+ expand = not isinstance(type, FunctionType)
+ ref = PointerType(type.name, type.const, None, expand, type.suffix)
+ self.Update(id, ref)
+
+
+ def ParseFunctionType(self, id, element):
+ result = self.GetType(element.get('returns'))
+ args = self.GetArguments(element)
+ func = FunctionType(result, args)
+ self.Update(id, func)
+
+
+ def ParseMethodType(self, id, element):
+ class_ = self.GetDecl(element.get('basetype')).FullName()
+ result = self.GetType(element.get('returns'))
+ args = self.GetArguments(element)
+ method = MethodType(result, args, class_)
+ self.Update(id, method)
+
+
+ def ParseField(self, id, element):
+ name = element.get('name')
+ visib = element.get('access', Scope.public)
+ classname = self.GetDecl(element.get('context')).FullName()
+ type_ = self.GetType(element.get('type'))
+ static = bool(int(element.get('extern', '0')))
+ location = self.GetLocation(element.get('location'))
+ var = ClassVariable(type_, name, classname, visib, static)
+ var.location = location
+ self.Update(id, var)
+
+
+ def ParseMethod(self, id, element, methodType=Method):
+ name = element.get('name')
+ result = self.GetType(element.get('returns'))
+ classname = self.GetDecl(element.get('context')).FullName()
+ visib = element.get('access', Scope.public)
+ static = bool(int(element.get('static', '0')))
+ virtual = bool(int(element.get('virtual', '0')))
+ 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, throws)
+ method.location = location
+ self.Update(id, method)
+
+
+ def ParseOperatorMethod(self, id, element):
+ self.ParseMethod(id, element, ClassOperator)
+
+
+ def ParseConstructor(self, id, element):
+ name = element.get('name')
+ visib = element.get('access', Scope.public)
+ classname = self.GetDecl(element.get('context')).FullName()
+ location = self.GetLocation(element.get('location'))
+ params = self.GetArguments(element)
+ artificial = element.get('artificial', False)
+ ctor = Constructor(name, classname, params, visib)
+ ctor.location = location
+ self.Update(id, ctor)
+
+
+ def ParseDestructor(self, id, element):
+ name = element.get('name')
+ visib = element.get('access', Scope.public)
+ classname = self.GetDecl(element.get('context')).FullName()
+ virtual = bool(int(element.get('virtual', '0')))
+ location = self.GetLocation(element.get('location'))
+ des = Destructor(name, classname, visib, virtual)
+ des.location = location
+ self.Update(id, des)
+
+
+ def ParseConverter(self, id, element):
+ self.ParseMethod(id, element, ConverterOperator)
+
+
+ def ParseTypedef(self, id, element):
+ name = element.get('name')
+ type = self.GetType(element.get('type'))
+ context = self.GetDecl(element.get('context'))
+ if isinstance(context, Class):
+ context = context.FullName()
+ typedef = Typedef(type, name, context)
+ self.Update(id, typedef)
+ self.AddDecl(typedef)
+
+
+ def ParseEnumeration(self, id, element):
+ name = element.get('name')
+ location = self.GetLocation(element.get('location'))
+ context = self.GetDecl(element.get('context'))
+ incomplete = bool(int(element.get('incomplete', 0)))
+ if isinstance(context, str):
+ enum = Enumeration(name, context)
+ else:
+ visib = element.get('access', Scope.public)
+ enum = ClassEnumeration(name, context.FullName(), visib)
+ self.AddDecl(enum)
+ enum.location = location
+ for child in element:
+ if child.tag == 'EnumValue':
+ name = child.get('name')
+ value = int(child.get('init'))
+ enum.values[name] = value
+ enum.incomplete = incomplete
+ self.Update(id, enum)
+
+
+
+def ParseDeclarations(filename):
+ 'Returns a list of the top declarations found in the gcc_xml file.'
+
+ parser = GCCXMLParser()
+ parser.Parse(filename)
+ return parser.Declarations()
+
+
+if __name__ == '__main__':
+ ParseDeclarations(r'D:\Programming\Libraries\boost-cvs\boost\libs\python\pyste\example\test.xml')
diff --git a/libs/python/pyste/src/Pyste/HeaderExporter.py b/libs/python/pyste/src/Pyste/HeaderExporter.py
new file mode 100644
index 000000000..47651ba70
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/HeaderExporter.py
@@ -0,0 +1,81 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from Exporter import Exporter
+from ClassExporter import ClassExporter
+from FunctionExporter import FunctionExporter
+from EnumExporter import EnumExporter
+from VarExporter import VarExporter
+from infos import *
+from declarations import *
+import os.path
+import exporters
+import MultipleCodeUnit
+
+#==============================================================================
+# HeaderExporter
+#==============================================================================
+class HeaderExporter(Exporter):
+ 'Exports all declarations found in the given header'
+
+ def __init__(self, info, parser_tail=None):
+ Exporter.__init__(self, info, parser_tail)
+
+
+ def WriteInclude(self, codeunit):
+ pass
+
+
+ def IsInternalName(self, name):
+ '''Returns true if the given name looks like a internal compiler
+ structure'''
+ return name.startswith('_')
+
+
+ def Export(self, codeunit, exported_names):
+ header = os.path.normpath(self.parser_header)
+ for decl in self.declarations:
+ # check if this declaration is in the header
+ location = os.path.abspath(decl.location[0])
+ if location == header and not self.IsInternalName(decl.name):
+ # ok, check the type of the declaration and export it accordingly
+ self.HandleDeclaration(decl, codeunit, exported_names)
+
+
+ def HandleDeclaration(self, decl, codeunit, exported_names):
+ '''Dispatch the declaration to the appropriate method, that must create
+ a suitable info object for a Exporter, create a Exporter, set its
+ declarations and append it to the list of exporters.
+ '''
+ dispatch_table = {
+ Class : ClassExporter,
+ Enumeration : EnumExporter,
+ Function : FunctionExporter,
+ Variable : VarExporter,
+ }
+
+ exporter_class = dispatch_table.get(type(decl))
+ if exporter_class is not None:
+ self.HandleExporter(decl, exporter_class, codeunit, exported_names)
+
+
+ def HandleExporter(self, decl, exporter_type, codeunit, exported_names):
+ # only export complete declarations
+ if not decl.incomplete:
+ info = self.info[decl.name]
+ info.name = decl.FullName()
+ info.include = self.info.include
+ exporter = exporter_type(info)
+ exporter.SetDeclarations(self.declarations)
+ exporter.SetParsedHeader(self.parser_header)
+ if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit):
+ codeunit.SetCurrent(self.interface_file, exporter.Name())
+ else:
+ codeunit.SetCurrent(exporter.Name())
+ exporter.GenerateCode(codeunit, exported_names)
+
+
+ def Name(self):
+ return self.info.include
diff --git a/libs/python/pyste/src/Pyste/MultipleCodeUnit.py b/libs/python/pyste/src/Pyste/MultipleCodeUnit.py
new file mode 100644
index 000000000..65faad45d
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/MultipleCodeUnit.py
@@ -0,0 +1,135 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from SingleCodeUnit import SingleCodeUnit
+import os
+import utils
+from SmartFile import SmartFile
+
+
+#==============================================================================
+# MultipleCodeUnit
+#==============================================================================
+class MultipleCodeUnit(object):
+ '''
+ Represents a bunch of cpp files, where each cpp file represents a header
+ to be exported by pyste. Another cpp, named <module>.cpp is created too.
+ '''
+
+ def __init__(self, modulename, outdir):
+ self.modulename = modulename
+ self.outdir = outdir
+ self.codeunits = {} # maps from a (filename, function) to a SingleCodeUnit
+ self.functions = []
+ self._current = None
+ self.all = SingleCodeUnit(None, None)
+
+
+ def _FunctionName(self, interface_file):
+ name = os.path.splitext(interface_file)[0]
+ return 'Export_%s' % utils.makeid(name)
+
+
+ def _FileName(self, interface_file):
+ filename = os.path.basename(interface_file)
+ filename = '_%s.cpp' % os.path.splitext(filename)[0]
+ return os.path.join(self.outdir, filename)
+
+
+ def SetCurrent(self, interface_file, export_name):
+ 'Changes the current code unit'
+ if export_name is None:
+ self._current = None
+ elif export_name is '__all__':
+ self._current = self.all
+ else:
+ filename = self._FileName(interface_file)
+ function = self._FunctionName(interface_file)
+ try:
+ codeunit = self.codeunits[filename]
+ except KeyError:
+ codeunit = SingleCodeUnit(None, filename)
+ codeunit.module_definition = 'void %s()' % function
+ self.codeunits[filename] = codeunit
+ if function not in self.functions:
+ self.functions.append(function)
+ self._current = codeunit
+
+
+ def Current(self):
+ return self._current
+
+ current = property(Current, SetCurrent)
+
+
+ def Write(self, section, code):
+ if self._current is not None:
+ self.current.Write(section, code)
+
+
+ def Section(self, section):
+ if self._current is not None:
+ return self.current.Section(section)
+
+
+ def _CreateOutputDir(self):
+ try:
+ os.mkdir(self.outdir)
+ except OSError: pass # already created
+
+
+ def Save(self):
+ # create the directory where all the files will go
+ self._CreateOutputDir();
+ # order all code units by filename, and merge them all
+ codeunits = {} # filename => list of codeunits
+
+ # While ordering all code units by file name, the first code
+ # 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():
+ if filename not in codeunits:
+ # this codeunit is the main codeunit.
+ codeunits[filename] = [codeunit]
+ codeunit.Merge(self.all)
+ else:
+ main_unit = codeunits[filename][0]
+ for section in ('include', 'declaration', 'declaration-outside'):
+ main_unit.code[section] = main_unit.code[section] + codeunit.code[section]
+ codeunit.code[section] = ''
+ codeunits[filename].append(codeunit)
+
+ # Now write all the codeunits appending them correctly.
+ for file_units in codeunits.values():
+ append = False
+ for codeunit in file_units:
+ 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/module.hpp>\n\n')
+ fout.write(utils.left_equals('Exports'))
+ 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 functions:
+ fout.write(indent)
+ fout.write('%s();\n' % function)
+ fout.write('}\n')
+
+
+
diff --git a/libs/python/pyste/src/Pyste/SingleCodeUnit.py b/libs/python/pyste/src/Pyste/SingleCodeUnit.py
new file mode 100644
index 000000000..2e59dbb80
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/SingleCodeUnit.py
@@ -0,0 +1,121 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from settings import namespaces
+import settings
+from utils import remove_duplicated_lines, left_equals
+from SmartFile import SmartFile
+
+
+#==============================================================================
+# SingleCodeUnit
+#==============================================================================
+class SingleCodeUnit:
+ '''
+ Represents a cpp file, where other objects can write in one of the
+ predefined sections.
+ The avaiable sections are:
+ pchinclude - The pre-compiled header area
+ include - The include area of the cpp file
+ declaration - The part before the module definition
+ module - Inside the BOOST_PYTHON_MODULE macro
+ '''
+
+ def __init__(self, modulename, filename):
+ self.modulename = modulename
+ self.filename = filename
+ # define the avaiable sections
+ self.code = {}
+ # include section
+ self.code['pchinclude'] = ''
+ # include section
+ self.code['include'] = ''
+ # declaration section (inside namespace)
+ self.code['declaration'] = ''
+ # declaration (outside namespace)
+ self.code['declaration-outside'] = ''
+ # inside BOOST_PYTHON_MACRO
+ self.code['module'] = ''
+ # create the default module definition
+ self.module_definition = 'BOOST_PYTHON_MODULE(%s)' % modulename
+
+
+ def Write(self, section, code):
+ 'write the given code in the section of the code unit'
+ if section not in self.code:
+ raise RuntimeError, 'Invalid CodeUnit section: %s' % section
+ self.code[section] += code
+
+
+ def Merge(self, other):
+ for section in ('include', 'declaration', 'declaration-outside', 'module'):
+ self.code[section] = self.code[section] + other.code[section]
+
+
+ def Section(self, section):
+ return self.code[section]
+
+
+ def SetCurrent(self, *args):
+ pass
+
+
+ def Current(self):
+ pass
+
+
+ def Save(self, append=False):
+ 'Writes this code unit to the filename'
+ space = '\n\n'
+ if not append:
+ flag = 'w'
+ else:
+ flag = 'a'
+ fout = SmartFile(self.filename, flag)
+ fout.write('\n')
+ # includes
+ # boost.python header
+ if self.code['pchinclude']:
+ fout.write(left_equals('PCH'))
+ fout.write(self.code['pchinclude']+'\n')
+ fout.write('#ifdef _MSC_VER\n')
+ fout.write('#pragma hdrstop\n')
+ fout.write('#endif\n')
+ else:
+ fout.write(left_equals('Boost Includes'))
+ fout.write('#include <boost/python.hpp>\n')
+ # include numerical boost for int64 definitions
+ fout.write('#include <boost/cstdint.hpp>\n')
+ fout.write('\n')
+ # other includes
+ if self.code['include']:
+ fout.write(left_equals('Includes'))
+ includes = remove_duplicated_lines(self.code['include'])
+ fout.write(includes)
+ fout.write(space)
+ # using
+ if settings.USING_BOOST_NS and not append:
+ fout.write(left_equals('Using'))
+ fout.write('using namespace boost::python;\n\n')
+ # declarations
+ declaration = self.code['declaration']
+ declaration_outside = self.code['declaration-outside']
+ if declaration_outside or declaration:
+ fout.write(left_equals('Declarations'))
+ if declaration_outside:
+ fout.write(declaration_outside + '\n\n')
+ if declaration:
+ pyste_namespace = namespaces.pyste[:-2]
+ fout.write('namespace %s {\n\n' % pyste_namespace)
+ fout.write(declaration)
+ 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\n')
+ fout.close()
diff --git a/libs/python/pyste/src/Pyste/SmartFile.py b/libs/python/pyste/src/Pyste/SmartFile.py
new file mode 100644
index 000000000..039579e3b
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/SmartFile.py
@@ -0,0 +1,60 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import os
+import md5
+
+#==============================================================================
+# SmartFile
+#==============================================================================
+class SmartFile(object):
+ '''
+ A file-like object used for writing files. The given file will only be
+ actually written to disk if there's not a file with the same name, or if
+ the existing file is *different* from the file to be written.
+ '''
+
+ def __init__(self, filename, mode='w'):
+ self.filename = filename
+ self.mode = mode
+ self._contents = []
+ self._closed = False
+
+
+ def __del__(self):
+ if not self._closed:
+ self.close()
+
+
+ def write(self, string):
+ self._contents.append(string)
+
+
+ def _dowrite(self, contents):
+ f = file(self.filename, self.mode)
+ f.write(contents)
+ f.close()
+
+
+ def _GetMD5(self, string):
+ return md5.new(string).digest()
+
+
+ def close(self):
+ # if the filename doesn't exist, write the file right away
+ this_contents = ''.join(self._contents)
+ if not os.path.isfile(self.filename):
+ self._dowrite(this_contents)
+ else:
+ # read the contents of the file already in disk
+ f = file(self.filename)
+ other_contents = f.read()
+ f.close()
+ # test the md5 for both files
+ this_md5 = self._GetMD5(this_contents)
+ other_md5 = self._GetMD5(other_contents)
+ if this_md5 != other_md5:
+ self._dowrite(this_contents)
+ self._closed = True
diff --git a/libs/python/pyste/src/Pyste/VarExporter.py b/libs/python/pyste/src/Pyste/VarExporter.py
new file mode 100644
index 000000000..d3571e751
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/VarExporter.py
@@ -0,0 +1,40 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from Exporter import Exporter
+from settings import *
+import utils
+
+#==============================================================================
+# VarExporter
+#==============================================================================
+class VarExporter(Exporter):
+ '''Exports a global variable.
+ '''
+
+ def __init__(self, info):
+ Exporter.__init__(self, info)
+
+
+ def Export(self, codeunit, exported_names):
+ if self.info.exclude: return
+ decl = self.GetDeclaration(self.info.name)
+ if not decl.type.const:
+ msg = '---> Warning: The global variable "%s" is non-const:\n' \
+ ' changes in Python will not reflect in C++.'
+ print msg % self.info.name
+ print
+ rename = self.info.rename or self.info.name
+ code = self.INDENT + namespaces.python
+ code += 'scope().attr("%s") = %s;\n' % (rename, self.info.name)
+ codeunit.Write('module', code)
+
+
+ def Order(self):
+ return 0, self.info.name
+
+
+ def Name(self):
+ return self.info.name
diff --git a/libs/python/pyste/src/Pyste/__init__.py b/libs/python/pyste/src/Pyste/__init__.py
new file mode 100644
index 000000000..02eec64b7
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/__init__.py
@@ -0,0 +1,6 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+
diff --git a/libs/python/pyste/src/Pyste/declarations.py b/libs/python/pyste/src/Pyste/declarations.py
new file mode 100644
index 000000000..6eff97dc5
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/declarations.py
@@ -0,0 +1,653 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+'''
+Defines classes that represent declarations found in C++ header files.
+
+'''
+
+# version indicates the version of the declarations. Whenever a declaration
+# changes, this variable should be updated, so that the caches can be rebuilt
+# automatically
+version = '1.0'
+
+#==============================================================================
+# Declaration
+#==============================================================================
+class Declaration(object):
+ '''Base class for all declarations.
+ @ivar name: The name of the declaration.
+ @ivar namespace: The namespace of the declaration.
+ '''
+
+ def __init__(self, name, namespace):
+ '''
+ @type name: string
+ @param name: The name of this declaration
+ @type namespace: string
+ @param namespace: the full namespace where this declaration resides.
+ '''
+ self.name = name
+ self.namespace = namespace
+ self.location = '', -1 # (filename, line)
+ self.incomplete = False
+ self.is_unique = True
+
+
+ def FullName(self):
+ '''
+ Returns the full qualified name: "boost::inner::Test"
+ @rtype: string
+ @return: The full name of the declaration.
+ '''
+ namespace = self.namespace or ''
+ if namespace and not namespace.endswith('::'):
+ namespace += '::'
+ return namespace + self.name
+
+
+ def __repr__(self):
+ return '<Declaration %s at %s>' % (self.FullName(), id(self))
+
+
+ def __str__(self):
+ return 'Declaration of %s' % self.FullName()
+
+
+#==============================================================================
+# Class
+#==============================================================================
+class Class(Declaration):
+ '''
+ Represents a C++ class or struct. Iteration through it yields its members.
+
+ @type abstract: bool
+ @ivar abstract: if the class has any abstract methods.
+
+ @type bases: tuple
+ @ivar bases: tuple with L{Base} instances, representing the most direct
+ inheritance.
+
+ @type hierarchy: list
+ @ivar hierarchy: a list of tuples of L{Base} instances, representing
+ the entire hierarchy tree of this object. The first tuple is the parent
+ classes, and the other ones go up in the hierarchy.
+ '''
+
+ def __init__(self, name, namespace, members, abstract):
+ Declaration.__init__(self, name, namespace)
+ self.__members = members
+ self.__member_names = {}
+ self.abstract = abstract
+ self.bases = ()
+ self.hierarchy = ()
+ self.operator = {}
+
+
+ def __iter__(self):
+ '''iterates through the class' members.
+ '''
+ return iter(self.__members)
+
+
+ def Constructors(self, publics_only=True):
+ '''Returns a list of the constructors for this class.
+ @rtype: list
+ '''
+ constructors = []
+ for member in self:
+ if isinstance(member, Constructor):
+ if publics_only and member.visibility != Scope.public:
+ continue
+ constructors.append(member)
+ return constructors
+
+
+ def HasCopyConstructor(self):
+ '''Returns true if this class has a public copy constructor.
+ @rtype: bool
+ '''
+ for cons in self.Constructors():
+ if cons.IsCopy():
+ return True
+ return False
+
+
+ def HasDefaultConstructor(self):
+ '''Returns true if this class has a public default constructor.
+ @rtype: bool
+ '''
+ for cons in self.Constructors():
+ if cons.IsDefault():
+ return True
+ return False
+
+
+ def AddMember(self, member):
+ if member.name in self.__member_names:
+ member.is_unique = False
+ for m in self:
+ if m.name == member.name:
+ m.is_unique = False
+ else:
+ member.is_unique = True
+ self.__member_names[member.name] = 1
+ self.__members.append(member)
+ if isinstance(member, ClassOperator):
+ self.operator[member.name] = member
+
+
+ def ValidMemberTypes():
+ return (NestedClass, Method, Constructor, Destructor, ClassVariable,
+ ClassOperator, ConverterOperator, ClassEnumeration)
+ ValidMemberTypes = staticmethod(ValidMemberTypes)
+
+
+#==============================================================================
+# NestedClass
+#==============================================================================
+class NestedClass(Class):
+ '''The declaration of a class/struct inside another class/struct.
+
+ @type class: string
+ @ivar class: fullname of the class where this class is contained.
+
+ @type visibility: L{Scope}
+ @ivar visibility: the visibility of this class.
+ '''
+
+ def __init__(self, name, class_, visib, members, abstract):
+ Class.__init__(self, name, None, members, abstract)
+ self.class_ = class_
+ self.visibility = visib
+
+
+ def FullName(self):
+ '''The full name of this class, like ns::outer::inner.
+ @rtype: string
+ '''
+ return '%s::%s' % (self.class_, self.name)
+
+
+#==============================================================================
+# Scope
+#==============================================================================
+class Scope:
+ '''Used to represent the visibility of various members inside a class.
+ @cvar public: public visibility
+ @cvar private: private visibility
+ @cvar protected: protected visibility
+ '''
+ public = 'public'
+ private = 'private'
+ protected = 'protected'
+
+
+#==============================================================================
+# Base
+#==============================================================================
+class Base:
+ '''Represents a base class of another class.
+ @ivar _name: the full name of the base class.
+ @ivar _visibility: the visibility of the derivation.
+ '''
+
+ def __init__(self, name, visibility=Scope.public):
+ self.name = name
+ self.visibility = visibility
+
+
+#==============================================================================
+# Function
+#==============================================================================
+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, 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 ([x.FullName() for x in self.throws])
+
+
+ def PointerDeclaration(self, force=False):
+ '''Returns a declaration of a pointer to this function.
+ @param force: If True, returns a complete pointer declaration regardless
+ if this function is unique or not.
+ '''
+ if self.is_unique and not force:
+ return '&%s' % self.FullName()
+ else:
+ result = self.result.FullName()
+ params = ', '.join([x.FullName() for x in self.parameters])
+ return '(%s (*)(%s)%s)&%s' % (result, params, self.Exceptions(), self.FullName())
+
+
+ def MinArgs(self):
+ min = 0
+ for arg in self.parameters:
+ if arg.default is None:
+ min += 1
+ return min
+
+ minArgs = property(MinArgs)
+
+
+ def MaxArgs(self):
+ return len(self.parameters)
+
+ maxArgs = property(MaxArgs)
+
+
+
+#==============================================================================
+# Operator
+#==============================================================================
+class Operator(Function):
+ '''The declaration of a custom operator. Its name is the same as the
+ operator name in C++, ie, the name of the declaration "operator+(..)" is
+ "+".
+ '''
+
+ def FullName(self):
+ namespace = self.namespace or ''
+ if not namespace.endswith('::'):
+ namespace += '::'
+ return namespace + 'operator' + self.name
+
+
+#==============================================================================
+# Method
+#==============================================================================
+class Method(Function):
+ '''The declaration of a method.
+
+ @ivar _visibility: the visibility of this method.
+ @ivar _virtual: if this method is declared as virtual.
+ @ivar _abstract: if this method is virtual but has no default implementation.
+ @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, throws=None):
+ Function.__init__(self, name, None, result, params, throws)
+ self.visibility = visib
+ self.virtual = virtual
+ self.abstract = abstract
+ self.static = static
+ self.class_ = class_
+ self.const = const
+
+
+ def FullName(self):
+ return self.class_ + '::' + self.name
+
+
+ def PointerDeclaration(self, force=False):
+ '''Returns a declaration of a pointer to this member function.
+ @param force: If True, returns a complete pointer declaration regardless
+ if this function is unique or not.
+ '''
+ if self.static:
+ # static methods are like normal functions
+ return Function.PointerDeclaration(self, force)
+ if self.is_unique and not force:
+ return '&%s' % self.FullName()
+ else:
+ result = self.result.FullName()
+ params = ', '.join([x.FullName() for x in self.parameters])
+ const = ''
+ if self.const:
+ const = 'const'
+ return '(%s (%s::*)(%s) %s%s)&%s' %\
+ (result, self.class_, params, const, self.Exceptions(), self.FullName())
+
+
+#==============================================================================
+# Constructor
+#==============================================================================
+class Constructor(Method):
+ '''A class' constructor.
+ '''
+
+ def __init__(self, name, class_, params, visib):
+ Method.__init__(self, name, class_, None, params, visib, False, False, False, False)
+
+
+ def IsDefault(self):
+ '''Returns True if this constructor is a default constructor.
+ '''
+ return len(self.parameters) == 0 and self.visibility == Scope.public
+
+
+ def IsCopy(self):
+ '''Returns True if this constructor is a copy constructor.
+ '''
+ if len(self.parameters) != 1:
+ return False
+ param = self.parameters[0]
+ class_as_param = self.parameters[0].name == self.class_
+ param_reference = isinstance(param, ReferenceType)
+ is_public = self.visibility == Scope.public
+ return param_reference and class_as_param and param.const and is_public
+
+
+ def PointerDeclaration(self, force=False):
+ return ''
+
+
+#==============================================================================
+# Destructor
+#==============================================================================
+class Destructor(Method):
+ 'The destructor of a class.'
+
+ def __init__(self, name, class_, visib, virtual):
+ Method.__init__(self, name, class_, None, [], visib, virtual, False, False, False)
+
+ def FullName(self):
+ return self.class_ + '::~' + self.name
+
+
+ def PointerDeclaration(self, force=False):
+ return ''
+
+
+
+#==============================================================================
+# ClassOperator
+#==============================================================================
+class ClassOperator(Method):
+ 'A custom operator in a class.'
+
+ def FullName(self):
+ return self.class_ + '::operator ' + self.name
+
+
+
+#==============================================================================
+# ConverterOperator
+#==============================================================================
+class ConverterOperator(ClassOperator):
+ 'An operator in the form "operator OtherClass()".'
+
+ def FullName(self):
+ return self.class_ + '::operator ' + self.result.FullName()
+
+
+
+#==============================================================================
+# Type
+#==============================================================================
+class Type(Declaration):
+ '''Represents the type of a variable or parameter.
+ @ivar _const: if the type is constant.
+ @ivar _default: if this type has a default value associated with it.
+ @ivar _volatile: if this type was declared with the keyword volatile.
+ @ivar _restricted: if this type was declared with the keyword restricted.
+ @ivar _suffix: Suffix to get the full type name. '*' for pointers, for
+ example.
+ '''
+
+ def __init__(self, name, const=False, default=None, suffix=''):
+ Declaration.__init__(self, name, None)
+ # whatever the type is constant or not
+ self.const = const
+ # used when the Type is a function argument
+ self.default = default
+ self.volatile = False
+ self.restricted = False
+ self.suffix = suffix
+
+ def __repr__(self):
+ if self.const:
+ const = 'const '
+ else:
+ const = ''
+ return '<Type ' + const + self.name + '>'
+
+
+ def FullName(self):
+ if self.const:
+ const = 'const '
+ else:
+ const = ''
+ return const + self.name + self.suffix
+
+
+#==============================================================================
+# ArrayType
+#==============================================================================
+class ArrayType(Type):
+ '''Represents an array.
+ @ivar min: the lower bound of the array, usually 0. Can be None.
+ @ivar max: the upper bound of the array. Can be None.
+ '''
+
+ def __init__(self, name, const, min, max):
+ 'min and max can be None.'
+ Type.__init__(self, name, const)
+ self.min = min
+ self.max = max
+
+
+
+#==============================================================================
+# ReferenceType
+#==============================================================================
+class ReferenceType(Type):
+ '''A reference type.'''
+
+ def __init__(self, name, const=False, default=None, expandRef=True, suffix=''):
+ Type.__init__(self, name, const, default)
+ if expandRef:
+ self.suffix = suffix + '&'
+
+
+#==============================================================================
+# PointerType
+#==============================================================================
+class PointerType(Type):
+ 'A pointer type.'
+
+ def __init__(self, name, const=False, default=None, expandPointer=False, suffix=''):
+ Type.__init__(self, name, const, default)
+ if expandPointer:
+ self.suffix = suffix + '*'
+
+
+#==============================================================================
+# FundamentalType
+#==============================================================================
+class FundamentalType(Type):
+ 'One of the fundamental types, like int, void, etc.'
+
+ def __init__(self, name, const=False, default=None):
+ Type.__init__(self, name, const, default)
+
+
+
+#==============================================================================
+# FunctionType
+#==============================================================================
+class FunctionType(Type):
+ '''A pointer to a function.
+ @ivar _result: the return value
+ @ivar _parameters: a list of Types, indicating the parameters of the function.
+ @ivar _name: the name of the function.
+ '''
+
+ def __init__(self, result, parameters):
+ Type.__init__(self, '', False)
+ self.result = result
+ self.parameters = parameters
+ self.name = self.FullName()
+
+
+ def FullName(self):
+ full = '%s (*)' % self.result.FullName()
+ params = [x.FullName() for x in self.parameters]
+ full += '(%s)' % ', '.join(params)
+ return full
+
+
+#==============================================================================
+# MethodType
+#==============================================================================
+class MethodType(FunctionType):
+ '''A pointer to a member function of a class.
+ @ivar _class: The fullname of the class that the method belongs to.
+ '''
+
+ def __init__(self, result, parameters, class_):
+ self.class_ = class_
+ FunctionType.__init__(self, result, parameters)
+
+
+ def FullName(self):
+ full = '%s (%s::*)' % (self.result.FullName(), self.class_)
+ params = [x.FullName() for x in self.parameters]
+ full += '(%s)' % ', '.join(params)
+ return full
+
+
+#==============================================================================
+# Variable
+#==============================================================================
+class Variable(Declaration):
+ '''Represents a global variable.
+
+ @type _type: L{Type}
+ @ivar _type: The type of the variable.
+ '''
+
+ def __init__(self, type, name, namespace):
+ Declaration.__init__(self, name, namespace)
+ self.type = type
+
+
+#==============================================================================
+# ClassVariable
+#==============================================================================
+class ClassVariable(Variable):
+ '''Represents a class variable.
+
+ @type _visibility: L{Scope}
+ @ivar _visibility: The visibility of this variable within the class.
+
+ @type _static: bool
+ @ivar _static: Indicates if the variable is static.
+
+ @ivar _class: Full name of the class that this variable belongs to.
+ '''
+
+ def __init__(self, type, name, class_, visib, static):
+ Variable.__init__(self, type, name, None)
+ self.visibility = visib
+ self.static = static
+ self.class_ = class_
+
+
+ def FullName(self):
+ return self.class_ + '::' + self.name
+
+
+#==============================================================================
+# Enumeration
+#==============================================================================
+class Enumeration(Declaration):
+ '''Represents an enum.
+
+ @type _values: dict of str => int
+ @ivar _values: holds the values for this enum.
+ '''
+
+ def __init__(self, name, namespace):
+ Declaration.__init__(self, name, namespace)
+ self.values = {} # dict of str => int
+
+
+ def ValueFullName(self, name):
+ '''Returns the full name for a value in the enum.
+ '''
+ assert name in self.values
+ namespace = self.namespace
+ if namespace:
+ namespace += '::'
+ return namespace + name
+
+
+#==============================================================================
+# ClassEnumeration
+#==============================================================================
+class ClassEnumeration(Enumeration):
+ '''Represents an enum inside a class.
+
+ @ivar _class: The full name of the class where this enum belongs.
+ @ivar _visibility: The visibility of this enum inside his class.
+ '''
+
+ def __init__(self, name, class_, visib):
+ Enumeration.__init__(self, name, None)
+ self.class_ = class_
+ self.visibility = visib
+
+
+ def FullName(self):
+ return '%s::%s' % (self.class_, self.name)
+
+
+ def ValueFullName(self, name):
+ assert name in self.values
+ return '%s::%s' % (self.class_, name)
+
+
+#==============================================================================
+# Typedef
+#==============================================================================
+class Typedef(Declaration):
+ '''A Typedef declaration.
+
+ @type _type: L{Type}
+ @ivar _type: The type of the typedef.
+
+ @type _visibility: L{Scope}
+ @ivar _visibility: The visibility of this typedef.
+ '''
+
+ def __init__(self, type, name, namespace):
+ Declaration.__init__(self, name, namespace)
+ self.type = type
+ self.visibility = Scope.public
+
+
+
+
+
+#==============================================================================
+# Unknown
+#==============================================================================
+class Unknown(Declaration):
+ '''A declaration that Pyste does not know how to handle.
+ '''
+
+ def __init__(self, name):
+ Declaration.__init__(self, name, None)
diff --git a/libs/python/pyste/src/Pyste/exporters.py b/libs/python/pyste/src/Pyste/exporters.py
new file mode 100644
index 000000000..f573d01be
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/exporters.py
@@ -0,0 +1,12 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+
+# a list of Exporter instances
+exporters = []
+
+current_interface = None # the current interface file being processed
+importing = False # whetever we are now importing a pyste file.
+ # exporters created here shouldn't export themselves
diff --git a/libs/python/pyste/src/Pyste/exporterutils.py b/libs/python/pyste/src/Pyste/exporterutils.py
new file mode 100644
index 000000000..363700d2b
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/exporterutils.py
@@ -0,0 +1,87 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+'''
+Various helpers for interface files.
+'''
+
+from settings import *
+from policies import *
+from declarations import *
+
+#==============================================================================
+# FunctionWrapper
+#==============================================================================
+class FunctionWrapper(object):
+ '''Holds information about a wrapper for a function or a method. It is
+ divided in 2 parts: the name of the Wrapper, and its code. The code is
+ placed in the declaration section of the module, while the name is used to
+ def' the function or method (with the pyste namespace prepend to it). If
+ code is None, the name is left unchanged.
+ '''
+
+ def __init__(self, name, code=None):
+ self.name = name
+ self.code = code
+
+ def FullName(self):
+ if self.code:
+ return namespaces.pyste + self.name
+ else:
+ return self.name
+
+
+_printed_warnings = {} # used to avoid double-prints of warnings
+
+#==============================================================================
+# HandlePolicy
+#==============================================================================
+def HandlePolicy(function, policy):
+ '''Show a warning to the user if the function needs a policy and doesn't
+ have one. Return a policy to the function, which is the given policy itself
+ if it is not None, or a default policy for this method.
+ '''
+
+ def IsString(type):
+ 'Return True if the Type instance can be considered a string'
+ return type.FullName() == 'const char*'
+
+ def IsPyObject(type):
+ return type.FullName() == '_object *' # internal name of PyObject
+
+ result = function.result
+ # if the function returns const char*, a policy is not needed
+ if IsString(result) or IsPyObject(result):
+ return policy
+ # if returns a const T&, set the default policy
+ if policy is None and result.const and isinstance(result, ReferenceType):
+ policy = return_value_policy(copy_const_reference)
+ # basic test if the result type demands a policy
+ needs_policy = isinstance(result, (ReferenceType, PointerType))
+ # show a warning to the user, if needed
+ if needs_policy and policy is None:
+ global _printed_warnings
+ warning = '---> Error: %s returns a pointer or a reference, ' \
+ 'but no policy was specified.' % function.FullName()
+ if warning not in _printed_warnings:
+ print warning
+ print
+ # avoid double prints of the same warning
+ _printed_warnings[warning] = 1
+ return policy
+
+
+#==============================================================================
+# EspecializeTypeID
+#==============================================================================
+_exported_type_ids = {}
+def EspecializeTypeID(typename):
+ global _exported_type_ids
+ macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)\n' % typename
+ if macro not in _exported_type_ids:
+ _exported_type_ids[macro] = 1
+ return macro
+ else:
+ return None
diff --git a/libs/python/pyste/src/Pyste/infos.py b/libs/python/pyste/src/Pyste/infos.py
new file mode 100644
index 000000000..2a4f01eaf
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/infos.py
@@ -0,0 +1,259 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import os.path
+import copy
+import exporters
+from ClassExporter import ClassExporter
+from FunctionExporter import FunctionExporter
+from EnumExporter import EnumExporter
+from HeaderExporter import HeaderExporter
+from VarExporter import VarExporter
+from CodeExporter import CodeExporter
+from exporterutils import FunctionWrapper
+from utils import makeid
+import warnings
+
+#==============================================================================
+# DeclarationInfo
+#==============================================================================
+class DeclarationInfo:
+
+ def __init__(self, otherInfo=None):
+ self.__infos = {}
+ self.__attributes = {}
+ if otherInfo is not None:
+ self.__infos = copy.deepcopy(otherInfo.__infos)
+ self.__attributes = copy.deepcopy(otherInfo.__attributes)
+
+
+ def __getitem__(self, name):
+ 'Used to access sub-infos'
+ if name.startswith('__'):
+ raise AttributeError
+ default = DeclarationInfo()
+ default._Attribute('name', name)
+ return self.__infos.setdefault(name, default)
+
+
+ def __getattr__(self, name):
+ return self[name]
+
+
+ def _Attribute(self, name, value=None):
+ if value is None:
+ # get value
+ return self.__attributes.get(name)
+ else:
+ # set value
+ self.__attributes[name] = value
+
+
+ def AddExporter(self, exporter):
+ # this was causing a much serious bug, as reported by Niall Douglas:
+ # another solution must be found!
+ #if not exporters.importing:
+ if exporter not in exporters.exporters:
+ exporters.exporters.append(exporter)
+ exporter.interface_file = exporters.current_interface
+
+
+#==============================================================================
+# FunctionInfo
+#==============================================================================
+class FunctionInfo(DeclarationInfo):
+
+ def __init__(self, name, include, tail=None, otherOption=None,
+ exporter_class = FunctionExporter):
+ DeclarationInfo.__init__(self, otherOption)
+ self._Attribute('name', name)
+ self._Attribute('include', include)
+ self._Attribute('exclude', False)
+ # create a FunctionExporter
+ exporter = exporter_class(InfoWrapper(self), tail)
+ self.AddExporter(exporter)
+
+
+#==============================================================================
+# ClassInfo
+#==============================================================================
+class ClassInfo(DeclarationInfo):
+
+ def __init__(self, name, include, tail=None, otherInfo=None,
+ exporter_class = ClassExporter):
+ DeclarationInfo.__init__(self, otherInfo)
+ self._Attribute('name', name)
+ self._Attribute('include', include)
+ self._Attribute('exclude', False)
+ # create a ClassExporter
+ exporter = exporter_class(InfoWrapper(self), tail)
+ self.AddExporter(exporter)
+
+
+#==============================================================================
+# templates
+#==============================================================================
+def GenerateName(name, type_list):
+ name = name.replace('::', '_')
+ names = [name] + type_list
+ return makeid('_'.join(names))
+
+
+class ClassTemplateInfo(DeclarationInfo):
+
+ def __init__(self, name, include,
+ exporter_class = ClassExporter):
+ DeclarationInfo.__init__(self)
+ self._Attribute('name', name)
+ self._Attribute('include', include)
+ self._exporter_class = exporter_class
+
+
+ def Instantiate(self, type_list, rename=None):
+ if not rename:
+ rename = GenerateName(self._Attribute('name'), type_list)
+ # generate code to instantiate the template
+ types = ', '.join(type_list)
+ tail = 'typedef %s< %s > %s;\n' % (self._Attribute('name'), types, rename)
+ tail += 'void __instantiate_%s()\n' % rename
+ tail += '{ sizeof(%s); }\n\n' % rename
+ # create a ClassInfo
+ class_ = ClassInfo(rename, self._Attribute('include'), tail, self,
+ exporter_class = self._exporter_class)
+ return class_
+
+
+ def __call__(self, types, rename=None):
+ if isinstance(types, str):
+ types = types.split()
+ return self.Instantiate(types, rename)
+
+#==============================================================================
+# EnumInfo
+#==============================================================================
+class EnumInfo(DeclarationInfo):
+
+ def __init__(self, name, include, exporter_class = EnumExporter):
+ DeclarationInfo.__init__(self)
+ self._Attribute('name', name)
+ self._Attribute('include', include)
+ self._Attribute('exclude', False)
+ self._Attribute('export_values', False)
+ exporter = exporter_class(InfoWrapper(self))
+ self.AddExporter(exporter)
+
+
+#==============================================================================
+# HeaderInfo
+#==============================================================================
+class HeaderInfo(DeclarationInfo):
+
+ def __init__(self, include, exporter_class = HeaderExporter):
+ warnings.warn('AllFromHeader is not working in all cases in the current version.')
+ DeclarationInfo.__init__(self)
+ self._Attribute('include', include)
+ exporter = exporter_class(InfoWrapper(self))
+ self.AddExporter(exporter)
+
+
+#==============================================================================
+# VarInfo
+#==============================================================================
+class VarInfo(DeclarationInfo):
+
+ def __init__(self, name, include, exporter_class = VarExporter):
+ DeclarationInfo.__init__(self)
+ self._Attribute('name', name)
+ self._Attribute('include', include)
+ exporter = exporter_class(InfoWrapper(self))
+ self.AddExporter(exporter)
+
+
+#==============================================================================
+# CodeInfo
+#==============================================================================
+class CodeInfo(DeclarationInfo):
+
+ def __init__(self, code, section, exporter_class = CodeExporter):
+ DeclarationInfo.__init__(self)
+ self._Attribute('code', code)
+ self._Attribute('section', section)
+ exporter = exporter_class(InfoWrapper(self))
+ self.AddExporter(exporter)
+
+
+#==============================================================================
+# InfoWrapper
+#==============================================================================
+class InfoWrapper:
+ 'Provides a nicer interface for a info'
+
+ def __init__(self, info):
+ self.__dict__['_info'] = info # so __setattr__ is not called
+
+ def __getitem__(self, name):
+ return InfoWrapper(self._info[name])
+
+ def __getattr__(self, name):
+ return self._info._Attribute(name)
+
+ def __setattr__(self, name, value):
+ self._info._Attribute(name, value)
+
+
+#==============================================================================
+# Functions
+#==============================================================================
+def exclude(info):
+ info._Attribute('exclude', True)
+
+def set_policy(info, policy):
+ info._Attribute('policy', policy)
+
+def rename(info, name):
+ info._Attribute('rename', name)
+
+def set_wrapper(info, wrapper):
+ if isinstance(wrapper, str):
+ wrapper = FunctionWrapper(wrapper)
+ info._Attribute('wrapper', wrapper)
+
+def instantiate(template, types, rename=None):
+ if isinstance(types, str):
+ types = types.split()
+ return template.Instantiate(types, rename)
+
+def use_shared_ptr(info):
+ info._Attribute('smart_ptr', 'boost::shared_ptr< %s >')
+
+def use_auto_ptr(info):
+ info._Attribute('smart_ptr', '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__')
+ if added is None:
+ info._Attribute('__added__', [(name, rename)])
+ else:
+ added.append((name, rename))
+
+
+def class_code(info, code):
+ added = info._Attribute('__code__')
+ if added is None:
+ info._Attribute('__code__', [code])
+ else:
+ added.append(code)
+
+def final(info):
+ info._Attribute('no_override', True)
+
+
+def export_values(info):
+ info._Attribute('export_values', True)
diff --git a/libs/python/pyste/src/Pyste/policies.py b/libs/python/pyste/src/Pyste/policies.py
new file mode 100644
index 000000000..57ebd0dea
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/policies.py
@@ -0,0 +1,95 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+
+
+class Policy(object):
+ 'Represents one of the call policies of boost.python.'
+
+ def __init__(self):
+ if type(self) is Policy:
+ raise RuntimeError, "Can't create an instance of the class Policy"
+
+
+ def Code(self):
+ 'Returns the string corresponding to a instancialization of the policy.'
+ pass
+
+
+ def _next(self):
+ if self.next is not None:
+ return ', %s >' % self.next.Code()
+ else:
+ return ' >'
+
+
+ def __eq__(self, other):
+ try:
+ return self.Code() == other.Code()
+ except AttributeError:
+ return False
+
+
+
+class return_internal_reference(Policy):
+ 'Ties the return value to one of the parameters.'
+
+ def __init__(self, param=1, next=None):
+ '''
+ param is the position of the parameter, or None for "self".
+ next indicates the next policy, or None.
+ '''
+ self.param = param
+ self.next=next
+
+
+ def Code(self):
+ c = 'return_internal_reference< %i' % self.param
+ c += self._next()
+ return c
+
+
+
+class with_custodian_and_ward(Policy):
+ 'Ties lifetime of two arguments of a function.'
+
+ def __init__(self, custodian, ward, next=None):
+ self.custodian = custodian
+ self.ward = ward
+ self.next = next
+
+ def Code(self):
+ c = 'with_custodian_and_ward< %i, %i' % (self.custodian, self.ward)
+ c += self._next()
+ return c
+
+
+
+class return_value_policy(Policy):
+ 'Policy to convert return values.'
+
+ def __init__(self, which, next=None):
+ self.which = which
+ self.next = next
+
+
+ def Code(self):
+ c = 'return_value_policy< %s' % self.which
+ c += self._next()
+ return c
+
+class return_self(Policy):
+
+ def Code(self):
+ return 'return_self<>'
+
+
+# values for return_value_policy
+reference_existing_object = 'reference_existing_object'
+copy_const_reference = 'copy_const_reference'
+copy_non_const_reference = 'copy_non_const_reference'
+manage_new_object = 'manage_new_object'
+return_opaque_pointer = 'return_opaque_pointer'
+return_by_value = 'return_by_value'
diff --git a/libs/python/pyste/src/Pyste/pyste.py b/libs/python/pyste/src/Pyste/pyste.py
new file mode 100644
index 000000000..cedffff55
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/pyste.py
@@ -0,0 +1,424 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+"""
+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=<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)
+ --file-list A file with one pyste file per line. Use as a
+ substitute for passing the files in the command
+ line.
+ --gccxml-path=<path> Path to gccxml executable (default: gccxml)
+ --no-default-include Do not use INCLUDE environment variable for include
+ files to pass along gccxml.
+ -h, --help Print this help and exit
+ -v, --version Print version information
+"""
+
+import sys
+import os
+import getopt
+import exporters
+import SingleCodeUnit
+import MultipleCodeUnit
+import infos
+import exporterutils
+import settings
+import gc
+import sys
+from policies import *
+from CppParser import CppParser, CppParserError
+import time
+import declarations
+
+__version__ = '0.9.30'
+
+def RecursiveIncludes(include):
+ 'Return a list containg the include dir and all its subdirectories'
+ dirs = [include]
+ def visit(arg, dir, names):
+ # ignore CVS dirs
+ if os.path.split(dir)[1] != 'CVS':
+ dirs.append(dir)
+ os.path.walk(include, visit, None)
+ return dirs
+
+
+def GetDefaultIncludes():
+ if 'INCLUDE' in os.environ:
+ include = os.environ['INCLUDE']
+ return include.split(os.pathsep)
+ else:
+ return []
+
+
+def ProcessIncludes(includes):
+ if sys.platform == 'win32':
+ index = 0
+ for include in includes:
+ includes[index] = include.replace('\\', '/')
+ index += 1
+
+
+def ReadFileList(filename):
+ f = file(filename)
+ files = []
+ try:
+ for line in f:
+ line = line.strip()
+ if line:
+ files.append(line)
+ finally:
+ f.close()
+ return files
+
+
+def ParseArguments():
+
+ def Usage():
+ 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', 'cache-dir=',
+ 'only-create-cache', 'version', 'generate-main', 'file-list=', 'help',
+ 'gccxml-path=', 'no-default-include'])
+ except getopt.GetoptError, e:
+ print
+ print 'ERROR:', e
+ Usage()
+
+ default_includes = GetDefaultIncludes()
+ includes = []
+ defines = []
+ module = None
+ out = None
+ multiple = False
+ cache_dir = None
+ create_cache = False
+ generate_main = False
+ gccxml_path = 'gccxml'
+
+ for opt, value in options:
+ if opt == '-I':
+ includes.append(value)
+ elif opt == '-D':
+ defines.append(value)
+ elif opt == '-R':
+ includes.extend(RecursiveIncludes(value))
+ elif opt == '--module':
+ module = value
+ elif opt == '--out':
+ out = value
+ elif opt == '--no-using':
+ settings.namespaces.python = 'boost::python::'
+ settings.USING_BOOST_NS = False
+ elif opt == '--pyste-ns':
+ settings.namespaces.pyste = value + '::'
+ elif opt == '--debug':
+ 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 == '--file-list':
+ files += ReadFileList(value)
+ elif opt in ['-h', '--help']:
+ Usage()
+ elif opt in ['-v', '--version']:
+ print 'Pyste version %s' % __version__
+ sys.exit(2)
+ elif opt == '--generate-main':
+ generate_main = True
+ elif opt == '--gccxml-path':
+ gccxml_path = value
+ elif opt == '--no-default-include':
+ default_includes = []
+ else:
+ print 'Unknown option:', opt
+ Usage()
+
+ includes[0:0] = default_includes
+ if not files:
+ Usage()
+ if not module:
+ module = os.path.splitext(os.path.basename(files[0]))[0]
+ if not out:
+ out = module
+ if not multiple:
+ out += '.cpp'
+ for file in files:
+ d = os.path.dirname(os.path.abspath(file))
+ if d not in sys.path:
+ sys.path.append(d)
+
+ 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, gccxml_path
+
+
+def PCHInclude(*headers):
+ code = '\n'.join(['#include <%s>' % x for x in headers])
+ infos.CodeInfo(code, 'pchinclude')
+
+
+def CreateContext():
+ 'create the context where a interface file will be executed'
+ context = {}
+ context['Import'] = Import
+ # infos
+ context['Function'] = infos.FunctionInfo
+ context['Class'] = infos.ClassInfo
+ context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include')
+ context['PCHInclude'] = PCHInclude
+ context['Template'] = infos.ClassTemplateInfo
+ context['Enum'] = infos.EnumInfo
+ context['AllFromHeader'] = infos.HeaderInfo
+ context['Var'] = infos.VarInfo
+ # functions
+ context['rename'] = infos.rename
+ context['set_policy'] = infos.set_policy
+ context['exclude'] = infos.exclude
+ context['set_wrapper'] = infos.set_wrapper
+ context['use_shared_ptr'] = infos.use_shared_ptr
+ context['use_auto_ptr'] = infos.use_auto_ptr
+ context['holder'] = infos.holder
+ context['add_method'] = infos.add_method
+ context['final'] = infos.final
+ context['export_values'] = infos.export_values
+ # policies
+ context['return_internal_reference'] = return_internal_reference
+ context['with_custodian_and_ward'] = with_custodian_and_ward
+ context['return_value_policy'] = return_value_policy
+ context['reference_existing_object'] = reference_existing_object
+ context['copy_const_reference'] = copy_const_reference
+ context['copy_non_const_reference'] = copy_non_const_reference
+ context['return_opaque_pointer'] = return_opaque_pointer
+ context['manage_new_object'] = manage_new_object
+ context['return_by_value'] = return_by_value
+ context['return_self'] = return_self
+ # utils
+ context['Wrapper'] = exporterutils.FunctionWrapper
+ context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside')
+ context['module_code'] = lambda code: infos.CodeInfo(code, 'module')
+ context['class_code'] = infos.class_code
+ return context
+
+
+def Begin():
+ # parse arguments
+ includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main, gccxml_path = ParseArguments()
+ # run pyste scripts
+ for interface in interfaces:
+ ExecuteInterface(interface)
+ # create the parser
+ parser = CppParser(includes, defines, cache_dir, declarations.version, gccxml_path)
+ 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()
+ context['INTERFACE_FILE'] = os.path.abspath(interface)
+ execfile(interface, context)
+ exporters.current_interface = old_interface
+
+
+def Import(interface):
+ exporters.importing = True
+ ExecuteInterface(interface)
+ exporters.importing = False
+
+
+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)
+ # stop referencing the exporters here
+ exports = exporters.exporters
+ exporters.exporters = None
+ exported_names = dict([(x.Name(), None) for x in exports])
+
+ # order the exports
+ order = {}
+ for export in exports:
+ if export.interface_file in order:
+ order[export.interface_file].append(export)
+ else:
+ order[export.interface_file] = [export]
+ exports = []
+ interfaces_order = OrderInterfaces(interfaces)
+ 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:
+ tail = tails[(interface, header)]
+ declarations, parsed_header = parser.Parse(header, interface, tail)
+ else:
+ declarations = []
+ parsed_header = None
+ 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()
+ if not multiple:
+ print 'Module %s generated' % module
+ return 0
+
+
+def ExpandTypedefs(decls, 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 decls:
+ if isinstance(decl, declarations.Typedef):
+ exported_names[decl.type.FullName()] = None
+
+def UsePsyco():
+ 'Tries to use psyco if possible'
+ try:
+ import psyco
+ psyco.profile()
+ except: pass
+
+
+def main():
+ start = time.clock()
+ UsePsyco()
+ status = Begin()
+ print '%0.2f seconds' % (time.clock()-start)
+ sys.exit(status)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libs/python/pyste/src/Pyste/settings.py b/libs/python/pyste/src/Pyste/settings.py
new file mode 100644
index 000000000..ba613b234
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/settings.py
@@ -0,0 +1,21 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+
+#==============================================================================
+# Global information
+#==============================================================================
+
+DEBUG = False
+USING_BOOST_NS = True
+
+class namespaces:
+ boost = 'boost::'
+ pyste = ''
+ python = '' # default is to not use boost::python namespace explicitly, so
+ # use the "using namespace" statement instead
+
+import sys
+msvc = sys.platform == 'win32'
diff --git a/libs/python/pyste/src/Pyste/utils.py b/libs/python/pyste/src/Pyste/utils.py
new file mode 100644
index 000000000..a8843e3f6
--- /dev/null
+++ b/libs/python/pyste/src/Pyste/utils.py
@@ -0,0 +1,78 @@
+# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
+# distribution is subject to the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+from __future__ import generators
+import string
+import sys
+
+#==============================================================================
+# enumerate
+#==============================================================================
+def enumerate(seq):
+ i = 0
+ for x in seq:
+ yield i, x
+ i += 1
+
+
+#==============================================================================
+# makeid
+#==============================================================================
+_valid_chars = string.ascii_letters + string.digits + '_'
+_valid_chars = dict(zip(_valid_chars, _valid_chars))
+
+def makeid(name):
+ 'Returns the name as a valid identifier'
+ if type(name) != str:
+ print type(name), name
+ newname = []
+ for char in name:
+ if char not in _valid_chars:
+ char = '_'
+ newname.append(char)
+ newname = ''.join(newname)
+ # avoid duplications of '_' chars
+ names = [x for x in newname.split('_') if x]
+ return '_'.join(names)
+
+
+#==============================================================================
+# remove_duplicated_lines
+#==============================================================================
+def remove_duplicated_lines(text):
+ includes = text.splitlines()
+ d = dict([(include, 0) for include in includes])
+ includes = d.keys()
+ includes.sort()
+ return '\n'.join(includes)
+
+
+#==============================================================================
+# left_equals
+#==============================================================================
+def left_equals(s):
+ s = '// %s ' % s
+ return s + ('='*(80-len(s))) + '\n'
+
+
+#==============================================================================
+# post_mortem
+#==============================================================================
+def post_mortem():
+
+ def info(type, value, tb):
+ if hasattr(sys, 'ps1') or not sys.stderr.isatty():
+ # we are in interactive mode or we don't have a tty-like
+ # device, so we call the default hook
+ sys.__excepthook__(type, value, tb)
+ else:
+ import traceback, pdb
+ # we are NOT in interactive mode, print the exception...
+ traceback.print_exception(type, value, tb)
+ print
+ # ...then start the debugger in post-mortem mode.
+ pdb.pm()
+
+ sys.excepthook = info