Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 53d527a

Browse files
committed
Initial prototype of framer: a tool to build the frame for extension modules.
1 parent f4d32df commit 53d527a

12 files changed

Lines changed: 915 additions & 0 deletions

File tree

Tools/framer/README.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
framer is a tool to generate boilerplate code for C extension types.
2+
3+
The boilerplate is generated from a specification object written in
4+
Python. The specification uses the class statement to describe the
5+
extension module and any extension types it contains. From the
6+
specification, framer can generate all the boilerplate C code,
7+
including function definitions, argument handling code, and type
8+
objects.

Tools/framer/TODO.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Add spec for getsets.
2+
Generate a distutils setup script.
3+
Handle operator overloading.
4+
Generate traverse and clear methods for GC.
5+
Handle mapping, sequence, buffer protocols.
6+
Finish the todo list.

Tools/framer/example.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"""Generate the skeleton for cStringIO as an example of framer."""
2+
3+
from framer.bases import Module, Type
4+
from framer.member import member
5+
6+
class cStringIO(Module):
7+
"""A simple fast partial StringIO replacement.
8+
9+
This module provides a simple useful replacement for the StringIO
10+
module that is written in C. It does not provide the full
11+
generality of StringIO, but it provides enough for most
12+
applications and is especially useful in conjunction with the
13+
pickle module.
14+
15+
Usage:
16+
17+
from cStringIO import StringIO
18+
19+
an_output_stream = StringIO()
20+
an_output_stream.write(some_stuff)
21+
...
22+
value = an_output_stream.getvalue()
23+
24+
an_input_stream = StringIO(a_string)
25+
spam = an_input_stream.readline()
26+
spam = an_input_stream.read(5)
27+
an_input_stream.seek(0) # OK, start over
28+
spam = an_input_stream.read() # and read it all
29+
"""
30+
31+
__file__ = "cStringIO.c"
32+
33+
def StringIO(o):
34+
"""Return a StringIO-like stream for reading or writing"""
35+
StringIO.pyarg = "|O"
36+
37+
class InputType(Type):
38+
"Simple type for treating strings as input file streams"
39+
40+
abbrev = "input"
41+
42+
struct = """\
43+
typedef struct {
44+
PyObject_HEAD
45+
char *buf;
46+
int pos;
47+
int size;
48+
PyObject *pbuf;
49+
} InputObject;
50+
"""
51+
52+
def flush(self):
53+
"""Does nothing"""
54+
55+
def getvalue(self):
56+
"""Get the string value.
57+
58+
If use_pos is specified and is a true value, then the
59+
string returned will include only the text up to the
60+
current file position.
61+
"""
62+
63+
def isatty(self):
64+
"""Always returns False"""
65+
66+
def read(self, s):
67+
"""Return s characters or the rest of the string."""
68+
read.pyarg = "|i"
69+
70+
def readline(self):
71+
"""Read one line."""
72+
73+
def readlines(self, hint):
74+
"""Read all lines."""
75+
readlines.pyarg = "|i"
76+
77+
def reset(self):
78+
"""Reset the file position to the beginning."""
79+
80+
def tell(self):
81+
"""Get the current position."""
82+
83+
def truncate(self, pos):
84+
"""Truncate the file at the current position."""
85+
truncate.pyarg = "|i"
86+
87+
def seek(self, position, mode=0):
88+
"""Set the current position.
89+
90+
The optional mode argument can be 0 for absolute, 1 for relative,
91+
and 2 for relative to EOF. The default is absolute.
92+
"""
93+
seek.pyarg = "i|i"
94+
95+
def close(self):
96+
pass
97+
98+
class OutputType(InputType):
99+
"Simple type for output strings."
100+
101+
abbrev = "output"
102+
103+
struct = """\
104+
typedef struct {
105+
PyObject_HEAD
106+
char *buf;
107+
int pos;
108+
int size;
109+
int softspace;
110+
} OutputObject;
111+
"""
112+
113+
softspace = member()
114+
115+
def close(self):
116+
"""Explicitly release resources."""
117+
118+
def write(self, s):
119+
"""Write a string to the file."""
120+
# XXX Hack: writing None resets the buffer
121+
122+
def writelines(self, lines):
123+
"""Write each string in lines."""
124+
125+
126+
cStringIO.gen()
127+

Tools/framer/framer/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""A tool to generate basic framework for C extension types.
2+
3+
The basic ideas is the same as modulator, but the code generates code
4+
using many of the new features introduced in Python 2.2. It also
5+
takes a more declarative approach to generating code.
6+
"""
7+
8+

Tools/framer/framer/bases.py

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
"""Provides the Module and Type base classes that user code inherits from."""
2+
3+
__all__ = ["Module", "Type", "member"]
4+
5+
from framer import struct, template
6+
from framer.function import Function, Method
7+
from framer.member import member
8+
from framer.slots import *
9+
from framer.util import cstring, unindent
10+
11+
from types import FunctionType
12+
13+
def sortitems(dict):
14+
L = dict.items()
15+
L.sort()
16+
return L
17+
18+
# The Module and Type classes are implemented using metaclasses,
19+
# because most of the methods are class methods. It is easier to use
20+
# metaclasses than the cumbersome classmethod() builtin. They have
21+
# class methods because they are exposed to user code as base classes.
22+
23+
class BaseMetaclass(type):
24+
"""Shared infrastructure for generating modules and types."""
25+
26+
# just methoddef so far
27+
28+
def dump_methoddef(self, f, functions, vars):
29+
def p(templ, vars=vars): # helper function to generate output
30+
print >> f, templ % vars
31+
32+
if not functions:
33+
return
34+
p(template.methoddef_start)
35+
for name, func in sortitems(functions):
36+
if func.__doc__:
37+
p(template.methoddef_def_doc, func.vars)
38+
else:
39+
p(template.methoddef_def, func.vars)
40+
p(template.methoddef_end)
41+
42+
class ModuleMetaclass(BaseMetaclass):
43+
"""Provides methods for Module class."""
44+
45+
def gen(self):
46+
self.analyze()
47+
self.initvars()
48+
f = open(self.__filename, "w")
49+
self.dump(f)
50+
f.close()
51+
52+
def analyze(self):
53+
self.name = getattr(self, "abbrev", self.__name__)
54+
self.__functions = {}
55+
self.__types = {}
56+
self.__members = False
57+
58+
for name, obj in self.__dict__.iteritems():
59+
if isinstance(obj, FunctionType):
60+
self.__functions[name] = Function(obj, self)
61+
elif isinstance(obj, TypeMetaclass):
62+
obj._TypeMetaclass__module = self.name
63+
obj.analyze()
64+
self.__types[name] = obj
65+
if obj.has_members():
66+
self.__members = True
67+
68+
def initvars(self):
69+
v = self.__vars = {}
70+
filename = getattr(self, "__file__", None)
71+
if filename is None:
72+
filename = self.__name__ + "module.c"
73+
self.__filename = v["FileName"] = filename
74+
name = v["ModuleName"] = self.__name__
75+
v["MethodDefName"] = "%s_methods" % name
76+
v["ModuleDocstring"] = cstring(unindent(self.__doc__))
77+
78+
def dump(self, f):
79+
def p(templ, vars=self.__vars): # helper function to generate output
80+
print >> f, templ % vars
81+
82+
p(template.module_start)
83+
if self.__members:
84+
p(template.member_include)
85+
print >> f
86+
87+
if self.__doc__:
88+
p(template.module_doc)
89+
90+
for name, type in sortitems(self.__types):
91+
type.dump(f)
92+
93+
for name, func in sortitems(self.__functions):
94+
func.dump(f)
95+
96+
self.dump_methoddef(f, self.__functions, self.__vars)
97+
98+
p(template.module_init_start)
99+
for name, type in sortitems(self.__types):
100+
type.dump_init(f)
101+
102+
p("}")
103+
104+
class Module:
105+
__metaclass__ = ModuleMetaclass
106+
107+
class TypeMetaclass(BaseMetaclass):
108+
109+
def dump(self, f):
110+
self.initvars()
111+
112+
# defined after initvars() so that __vars is defined
113+
def p(templ, vars=self.__vars):
114+
print >> f, templ % vars
115+
116+
if self.struct is not None:
117+
print >> f, unindent(self.struct, False)
118+
119+
if self.__doc__:
120+
p(template.docstring)
121+
122+
for name, func in sortitems(self.__methods):
123+
func.dump(f)
124+
125+
self.dump_methoddef(f, self.__methods, self.__vars)
126+
self.dump_memberdef(f)
127+
self.dump_slots(f)
128+
129+
def has_members(self):
130+
if self.__members:
131+
return True
132+
else:
133+
return False
134+
135+
def analyze(self):
136+
# called by ModuleMetaclass analyze()
137+
self.name = getattr(self, "abbrev", self.__name__)
138+
src = getattr(self, "struct", None)
139+
if src is not None:
140+
self.__struct = struct.parse(src)
141+
else:
142+
self.__struct = None
143+
self.__methods = {}
144+
self.__members = {}
145+
for cls in self.__mro__:
146+
for k, v in cls.__dict__.iteritems():
147+
if isinstance(v, FunctionType):
148+
self.__methods[k] = Method(v, self)
149+
if isinstance(v, member):
150+
self.__members[k] = v
151+
assert self.__struct is not None
152+
v.register(k, self.__struct)
153+
self.analyze_slots()
154+
155+
def analyze_slots(self):
156+
self.__slots = {}
157+
for s in Slots:
158+
if s.special is not None:
159+
meth = self.__methods.get(s.special)
160+
if meth is not None:
161+
self.__slots[s] = meth
162+
self.__slots[TP_NAME] = '"%s.%s"' % (self.__module, self.__name__)
163+
if self.__doc__:
164+
self.__slots[TP_DOC] = "%s_doc" % self.name
165+
if self.__struct is not None:
166+
self.__slots[TP_BASICSIZE] = "sizeof(%s)" % self.__struct.name
167+
self.__slots[TP_DEALLOC] = "%s_dealloc" % self.name
168+
if self.__methods:
169+
self.__slots[TP_METHODS] = "%s_methods" % self.name
170+
if self.__members:
171+
self.__slots[TP_MEMBERS] = "%s_members" % self.name
172+
173+
def initvars(self):
174+
v = self.__vars = {}
175+
v["TypeName"] = self.__name__
176+
v["CTypeName"] = "Py%s_Type" % self.__name__
177+
v["MethodDefName"] = self.__slots[TP_METHODS]
178+
if self.__doc__:
179+
v["DocstringVar"] = self.__slots[TP_DOC]
180+
v["Docstring"] = cstring(unindent(self.__doc__))
181+
if self.__struct is not None:
182+
v["StructName"] = self.__struct.name
183+
if self.__members:
184+
v["MemberDefName"] = self.__slots[TP_MEMBERS]
185+
186+
def dump_memberdef(self, f):
187+
def p(templ, vars=self.__vars):
188+
print >> f, templ % vars
189+
190+
if not self.__members:
191+
return
192+
p(template.memberdef_start)
193+
for name, slot in sortitems(self.__members):
194+
slot.dump(f)
195+
p(template.memberdef_end)
196+
197+
def dump_slots(self, f):
198+
def p(templ, vars=self.__vars):
199+
print >> f, templ % vars
200+
201+
if self.struct:
202+
p(template.dealloc_func, {"name" : self.__slots[TP_DEALLOC]})
203+
204+
p(template.type_struct_start)
205+
for s in Slots[:-5]: # XXX
206+
val = self.__slots.get(s, s.default)
207+
ntabs = 4 - (4 + len(val)) / 8
208+
line = " %s,%s/* %s */" % (val, "\t" * ntabs, s.name)
209+
print >> f, line
210+
p(template.type_struct_end)
211+
212+
def dump_init(self, f):
213+
def p(templ):
214+
print >> f, templ % self.__vars
215+
216+
p(template.type_init_type)
217+
p(template.module_add_type)
218+
219+
class Type:
220+
__metaclass__ = TypeMetaclass
221+

0 commit comments

Comments
 (0)