blob: fb3cb036ec1293d1cda1dbf9e3f9106ceb0c178b [file] [log] [blame]
Jeremy Hylton53d527a2002-08-05 18:29:45 +00001"""Provides the Module and Type base classes that user code inherits from."""
2
3__all__ = ["Module", "Type", "member"]
4
5from framer import struct, template
6from framer.function import Function, Method
7from framer.member import member
8from framer.slots import *
9from framer.util import cstring, unindent
10
11from types import FunctionType
12
13def 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
23class 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
42class 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
Tim Peters182b5ac2004-07-18 06:16:08 +000067
Jeremy Hylton53d527a2002-08-05 18:29:45 +000068 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
Tim Peters182b5ac2004-07-18 06:16:08 +000086
Jeremy Hylton53d527a2002-08-05 18:29:45 +000087 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)
Tim Peters182b5ac2004-07-18 06:16:08 +0000101
Jeremy Hylton53d527a2002-08-05 18:29:45 +0000102 p("}")
103
104class Module:
105 __metaclass__ = ModuleMetaclass
106
107class 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)
Tim Peters182b5ac2004-07-18 06:16:08 +0000124
Jeremy Hylton53d527a2002-08-05 18:29:45 +0000125 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:
Tim Peters182b5ac2004-07-18 06:16:08 +0000202 p(template.dealloc_func, {"name" : self.__slots[TP_DEALLOC]})
Jeremy Hylton53d527a2002-08-05 18:29:45 +0000203
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
219class Type:
220 __metaclass__ = TypeMetaclass