summaryrefslogtreecommitdiff
path: root/libs/python/pyste/src/Pyste/pyste.py
diff options
context:
space:
mode:
Diffstat (limited to 'libs/python/pyste/src/Pyste/pyste.py')
-rw-r--r--libs/python/pyste/src/Pyste/pyste.py424
1 files changed, 424 insertions, 0 deletions
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()