Skip to content

Commit 1684763

Browse files
author
Bruno da Silva de Oliveira
committed
- incremental code and some fixes
[SVN r19499]
1 parent 7fa6a29 commit 1684763

13 files changed

Lines changed: 416 additions & 199 deletions

pyste/src/Pyste/ClassExporter.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,23 @@ def ScopeName(self):
4848
return makeid(self.class_.FullName()) + '_scope'
4949

5050

51-
def Unit(self):
52-
return makeid(self.class_.name)
53-
54-
5551
def Name(self):
56-
return self.class_.FullName()
52+
return self.info.name
5753

5854

5955
def SetDeclarations(self, declarations):
6056
Exporter.SetDeclarations(self, declarations)
61-
decl = self.GetDeclaration(self.info.name)
62-
if isinstance(decl, Typedef):
63-
self.class_ = self.GetDeclaration(decl.type.name)
64-
if not self.info.rename:
65-
self.info.rename = decl.name
57+
if self.declarations:
58+
decl = self.GetDeclaration(self.info.name)
59+
if isinstance(decl, Typedef):
60+
self.class_ = self.GetDeclaration(decl.type.name)
61+
if not self.info.rename:
62+
self.info.rename = decl.name
63+
else:
64+
self.class_ = decl
65+
self.class_ = copy.deepcopy(self.class_)
6666
else:
67-
self.class_ = decl
68-
self.class_ = copy.deepcopy(self.class_)
69-
67+
self.class_ = None
7068

7169

7270
def ClassBases(self):
@@ -82,7 +80,8 @@ def Order(self):
8280
bases' bases. Do this because base classes must be instantialized
8381
before the derived classes in the module definition.
8482
'''
85-
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
83+
num_bases = len(self.ClassBases())
84+
return num_bases, self.class_.FullName()
8685

8786

8887
def Export(self, codeunit, exported_names):
@@ -101,7 +100,7 @@ def Export(self, codeunit, exported_names):
101100
self.ExportSmartPointer()
102101
self.ExportOpaquePointerPolicies()
103102
self.Write(codeunit)
104-
exported_names[self.class_.FullName()] = 1
103+
exported_names[self.Name()] = 1
105104

106105

107106
def InheritMethods(self, exported_names):
@@ -131,7 +130,7 @@ def InheritMethods(self, exported_names):
131130
break
132131
def IsValid(member):
133132
return isinstance(member, valid_members) and member.visibility == Scope.public
134-
self.public_members = [x for x in self.class_ if IsValid(x)]
133+
self.public_members = [x for x in self.class_ if IsValid(x)]
135134

136135

137136
def Write(self, codeunit):
@@ -196,29 +195,24 @@ def Add(self, section, item):
196195

197196

198197
def ExportBasics(self):
199-
'''Export the name of the class and its class_ statement.
200-
Also export the held_type if specified.'''
198+
'''Export the name of the class and its class_ statement.'''
201199
class_name = self.class_.FullName()
202200
self.Add('template', class_name)
203-
held_type = self.info.held_type
204-
if held_type:
205-
held_type = held_type % class_name
206-
self.Add('template', held_type)
207201
name = self.info.rename or self.class_.name
208202
self.Add('constructor', '"%s"' % name)
209203

210204

211205
def ExportBases(self, exported_names):
212206
'Expose the bases of the class into the template section'
213207
hierarchy = self.class_.hierarchy
208+
exported = []
214209
for level in hierarchy:
215-
exported = []
216210
for base in level:
217211
if base.visibility == Scope.public and base.name in exported_names:
218212
exported.append(base.name)
219-
if exported:
220-
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
221-
self.Add('template', code)
213+
if exported:
214+
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
215+
self.Add('template', code)
222216

223217

224218
def ExportConstructors(self):
@@ -408,13 +402,19 @@ def ExportVirtualMethods(self):
408402
has_virtual_methods = True
409403
break
410404

405+
holder = self.info.holder
411406
if has_virtual_methods:
412407
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info)
413-
self.Add('template', generator.FullName())
408+
if holder:
409+
self.Add('template', holder(generator.FullName()))
410+
else:
411+
self.Add('template', generator.FullName())
414412
for definition in generator.GenerateDefinitions():
415413
self.Add('inside', definition)
416414
self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT))
417-
415+
else:
416+
if holder:
417+
self.Add('template', holder(self.class_.FullName()))
418418

419419
# operators natively supported by boost
420420
BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -='\
@@ -610,7 +610,7 @@ def ExportSmartPointer(self):
610610
if smart_ptr:
611611
class_name = self.class_.FullName()
612612
smart_ptr = smart_ptr % class_name
613-
self.Add('scope', '%s::register_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
613+
self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
614614

615615

616616
def ExportOpaquePointerPolicies(self):

pyste/src/Pyste/CppParser.py

Lines changed: 153 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,52 @@
22
import tempfile
33
import shutil
44
import os
5+
import sys
56
import os.path
67
import settings
8+
import shutil
9+
import shelve
10+
from cPickle import dump, load
711

12+
#==============================================================================
13+
# exceptions
14+
#==============================================================================
815
class CppParserError(Exception): pass
916

10-
17+
#==============================================================================
18+
# CppParser
19+
#==============================================================================
1120
class CppParser:
1221
'Parses a header file and returns a list of declarations'
1322

14-
def __init__(self, includes=None, defines=None):
23+
def __init__(self, includes=None, defines=None, cache_dir=None):
1524
'includes and defines ar the directives given to gcc'
1625
if includes is None:
1726
includes = []
1827
if defines is None:
1928
defines = []
2029
self.includes = includes
2130
self.defines = defines
31+
#if cache_dir is None:
32+
# cache_dir = tempfile.mktemp()
33+
# self.delete_cache = True
34+
#else:
35+
# self.delete_cache = False
36+
self.delete_cache = False
37+
self.cache_dir = cache_dir
38+
self.cache_files = []
39+
# create the cache dir
40+
if cache_dir:
41+
try:
42+
os.makedirs(cache_dir)
43+
except OSError: pass
44+
2245

46+
def __del__(self):
47+
self.Close()
2348

24-
def _includeparams(self, filename):
49+
50+
def _IncludeParams(self, filename):
2551
includes = self.includes[:]
2652
filedir = os.path.dirname(filename)
2753
if not filedir:
@@ -31,64 +57,153 @@ def _includeparams(self, filename):
3157
return ' '.join(includes)
3258

3359

34-
def _defineparams(self):
60+
def _DefineParams(self):
3561
defines = ['-D "%s"' % x for x in self.defines]
3662
return ' '.join(defines)
3763

3864

39-
def FindFileName(self, include):
40-
if os.path.isfile(include):
41-
return include
65+
def FindHeader(self, header):
66+
if os.path.isfile(header):
67+
return header
4268
for path in self.includes:
43-
filename = os.path.join(path, include)
69+
filename = os.path.join(path, header)
4470
if os.path.isfile(filename):
4571
return filename
46-
name = os.path.basename(include)
47-
raise RuntimeError, 'Header file "%s" not found!' % name
72+
else:
73+
name = os.path.basename(header)
74+
raise RuntimeError, 'Header file "%s" not found!' % name
4875

4976

50-
def parse(self, include, tail=None, decl_name=None):
51-
'''Parses the given filename, and returns (declaration, header). The
52-
header returned is normally the same as the given to this method,
53-
except if tail is not None: in this case, the header is copied to a temp
54-
filename and the tail code is appended to it before being passed on to gcc.
55-
This temp filename is then returned.
56-
'''
57-
filename = self.FindFileName(include)
58-
# copy file to temp folder, if needed
77+
def AppendTail(self, filename, tail):
78+
'''Creates a temporary file, appends the text tail to it, and returns
79+
the filename of the file.
80+
'''
81+
temp = tempfile.mktemp('.h')
82+
shutil.copyfile(filename, temp)
83+
f = file(temp, 'a')
84+
f.write('\n\n'+tail)
85+
f.close()
86+
return temp
87+
88+
89+
def ParseWithGCCXML(self, header, tail):
90+
'''Parses the given header using gccxml and GCCXMLParser.
91+
'''
92+
header = self.FindHeader(header)
5993
if tail:
60-
tempfilename = tempfile.mktemp('.h')
61-
infilename = tempfilename
62-
shutil.copyfile(filename, infilename)
63-
f = file(infilename, 'a')
64-
f.write('\n\n'+tail)
65-
f.close()
94+
filename = self.AppendTail(header, tail)
6695
else:
67-
infilename = filename
96+
filename = header
6897
xmlfile = tempfile.mktemp('.xml')
6998
try:
7099
# get the params
71-
includes = self._includeparams(filename)
72-
defines = self._defineparams()
100+
includes = self._IncludeParams(filename)
101+
defines = self._DefineParams()
73102
# call gccxml
74-
cmd = 'gccxml %s %s %s -fxml=%s' \
75-
% (includes, defines, infilename, xmlfile)
76-
if decl_name is not None:
77-
cmd += ' "-fxml-start=%s"' % decl_name
78-
status = os.system(cmd)
103+
cmd = 'gccxml %s %s %s -fxml=%s'
104+
status = os.system(cmd % (includes, defines, filename, xmlfile))
79105
if status != 0 or not os.path.isfile(xmlfile):
80106
raise CppParserError, 'Error executing gccxml'
81107
# parse the resulting xml
82108
declarations = ParseDeclarations(xmlfile)
109+
# make the declarations' location to point to the original file
110+
if tail:
111+
for decl in declarations:
112+
decl_filename = os.path.normpath(os.path.normcase(decl.location[0]))
113+
filename = os.path.normpath(os.path.normcase(filename))
114+
if decl_filename == filename:
115+
decl.location = header, decl.location[1]
83116
# return the declarations
84-
return declarations, infilename
117+
return declarations
85118
finally:
86119
if settings.DEBUG and os.path.isfile(xmlfile):
87-
filename = os.path.basename(include)
88-
shutil.copy(xmlfile, os.path.splitext(filename)[0] + '.xml')
120+
filename = os.path.basename(header)
121+
filename = os.path.splitext(filename)[0] + '.xml'
122+
shutil.copy(xmlfile, filename)
89123
# delete the temporary files
90124
try:
91125
os.remove(xmlfile)
92126
if tail:
93-
os.remove(tempfilename)
94-
except OSError: pass
127+
os.remove(filename)
128+
except OSError: pass
129+
130+
131+
def Parse(self, header, interface, tail=None):
132+
'''Parses the given filename related to the given interface and returns
133+
the (declarations, headerfile). The header returned is normally the
134+
same as the given to this method (except that it is the full path),
135+
except if tail is not None: in this case, the header is copied to a temp
136+
filename and the tail code is appended to it before being passed on to
137+
gccxml. This temp filename is then returned.
138+
'''
139+
if tail is None:
140+
tail = ''
141+
tail.strip()
142+
declarations = self.GetCache(header, interface, tail)
143+
if declarations is None:
144+
declarations = self.ParseWithGCCXML(header, tail)
145+
if self.cache_dir is not None:
146+
self.CreateCache(header, interface, tail, declarations)
147+
return declarations, header
148+
149+
150+
def CacheFileName(self, interface):
151+
interface_name = os.path.basename(interface)
152+
cache_file = os.path.splitext(interface_name)[0] + '.pystec'
153+
cache_file = os.path.join(self.cache_dir, cache_file)
154+
return cache_file
155+
156+
157+
158+
def GetCache(self, header, interface, tail):
159+
if self.cache_dir is None:
160+
return None
161+
header = self.FindHeader(header)
162+
cache_file = self.CacheFileName(interface)
163+
if os.path.isfile(cache_file):
164+
f = file(cache_file, 'rb')
165+
try:
166+
cache = load(f)
167+
key = (header, interface, tail)
168+
if cache.has_key(key):
169+
self.cache_files.append(cache_file)
170+
return cache[key]
171+
else:
172+
return None
173+
finally:
174+
f.close()
175+
else:
176+
return None
177+
178+
179+
def CreateCache(self, header, interface, tail, declarations):
180+
header = self.FindHeader(header)
181+
cache_file = self.CacheFileName(interface)
182+
if os.path.isfile(cache_file):
183+
f = file(cache_file, 'rb')
184+
try:
185+
cache = load(f)
186+
finally:
187+
f.close()
188+
else:
189+
cache = {}
190+
key = (header, interface, tail)
191+
cache[key] = declarations
192+
self.cache_files.append(cache_file)
193+
f = file(cache_file, 'wb')
194+
try:
195+
dump(cache, f, 1)
196+
finally:
197+
f.close()
198+
return cache_file
199+
200+
201+
def Close(self):
202+
if self.delete_cache and self.cache_files:
203+
for filename in self.cache_files:
204+
try:
205+
os.remove(filename)
206+
except OSError:
207+
pass
208+
self.cache_files = []
209+
shutil.rmtree(self.cache_dir)

0 commit comments

Comments
 (0)