]> git.tdb.fi Git - gldbg.git/blob - genwrap.py
Enhance the object-orientedness of genwrap.py
[gldbg.git] / genwrap.py
1 #!/usr/bin/python
2 # $Id$
3
4 import sys
5 import os
6
7 class InputFile:
8         def __init__(self, fn):
9                 self.file = open(fn)
10
11         def __iter__(self):
12                 for l in self.file:
13                         h = l.find("#")
14                         if h==0 or (h>0 and l[h-1].isspace()):
15                                 l = l[:h]
16
17                         l = l.rstrip()
18                         if not l:
19                                 continue
20
21                         yield l
22                 
23
24 def strip_name(name):
25         """Strips any vendor suffix and GL prefix from a name (but not GLX prefix)"""
26
27         suffix = ""
28         if name.endswith(" *"):
29                 suffix = " *"
30                 name = name[:-2]
31         elif name.endswith("Pointer"):
32                 suffix = "Pointer"
33                 name = name[:-7]
34
35         prefix = ""
36         if name.startswith("const "):
37                 prefix = "const "
38                 name = name[6:]
39
40         if name.startswith("GL") and not name.startswith("GLX"):
41                 name = name[2:]
42         if name.endswith(("EXT", "ARB", "SGI", "IBM", "ATI")):
43                 return prefix+name[:-3]+suffix
44         elif name.endswith("SGIX"):
45                 return prefix+name[:-4]+suffix
46         elif name.endswith(("NV", "HP")):
47                 return prefix+name[:-2]+suffix
48         else:
49                 return prefix+name+suffix
50
51
52 class Typemap:
53         def __init__(self, fn):
54                 self.map = {}
55                 for line in InputFile(fn):
56                         parts = [p.strip() for p in line.split(',')]
57                         if parts[3]=="*":
58                                 parts[3] = parts[0]
59                         elif parts[3][-1]=='*' and parts[3][-2]!=' ':
60                                 parts[3] = parts[3][:-1]+" *"
61                         self.map[tuple(parts[0:3])] = tuple(parts[3:6])
62
63         def wildcard_match(self, a, b):
64                 if a=="*" or b=="*":
65                         return True
66                 return a==b
67
68         def __getitem__(self, key):
69                 return self.map[(key[0], "*", "*")]
70                 for k, v in self.map.iteritems():
71                         if strip_name(k[0])==strip_name(key[0]) and self.wildcard_match(k[1], key[1]) and self.wildcard_match(k[2], key[2]):
72                                 return v
73                 raise KeyError, key
74
75         def update(self, other):
76                 self.map.update(other.map)
77
78
79 class IOmap:
80         def __init__(self, fn):
81                 self.map = {}
82                 self.map["void"] = None
83                 for line in InputFile(fn):
84                         parts = [p.strip() for p in line.split(',')]
85                         self.map[parts[0]] = tuple(parts[1:])
86
87         def __getitem__(self, key):
88                 return self.map[strip_name(key)]
89
90
91 class Function:
92         class Parameter:
93                 def __init__(self, func, name):
94                         self.func = func
95                         self.name = name
96                         self.type = None
97                         self.direction = "in"
98                         self.kind = "value"
99                         self.size = None
100                         self.ctype = None
101                         self.csize = None
102                         self.io = None
103
104                 def set_type(self, type, dir, kind):
105                         self.type = type
106                         self.direction = dir
107                         self.kind = kind
108
109                 def set_size(self, size):
110                         if type(size)==str and size.isdigit():
111                                 self.size = int(size)
112                         else:
113                                 self.size = size
114
115                 def derive_ctype(self):
116                         self.ctype = typemap[(self.type, self.direction, self.kind)][0]
117                         self.base_ctype = self.ctype
118                         if self.kind=="value":
119                                 if self.base_ctype.startswith("const "):
120                                         self.base_ctype = self.base_ctype[6:]
121                                 self.io = iomap[self.base_ctype]
122                         else:
123                                 if self.direction=="in":
124                                         self.ctype = "const "+self.ctype
125                                 self.ctype = self.ctype+" *"
126
127                 def derive_csize(self):
128                         if self.kind=="array" and self.size is not None:
129                                 self.csize = None
130                                 if type(self.size)==int:
131                                         self.csize = "%d*sizeof(%s)"%(self.size, self.base_ctype)
132                                 elif self.size.startswith("COMPSIZE("):
133                                         self.csize = self.func.compsize(self.size[9:-1], self.base_ctype)
134                                 elif self.size=="" and (self.type=="charARB" or self.type=="Char"):
135                                         self.csize = "strlen"
136                                 else:
137                                         s = self.func.get_param(self.size.split('*')[0])
138                                         if (s.type=="SizeI" or s.type.endswith("Int32") or s.type.startswith("BufferSize")) and s.kind=="value":
139                                                 self.csize = "%s*sizeof(%s)"%(self.size, self.base_ctype)
140                                                 if self.func.name.startswith("Uniform") and self.func.name[7].isdigit():
141                                                         self.csize += "*%s"%func.name[7]
142                                         if not self.csize:
143                                                 sys.stderr.write("Could not determine size for array parameter '%s[%s]' of function '%s'\n"%(self.name, self.size, self.func.name))
144                         elif self.kind=="reference":
145                                 self.csize = "sizeof(%s)"%self.base_ctype
146
147         def __init__(self, name, pnames):
148                 self.name = name
149                 self.ret = Function.Parameter(self, "ret")
150                 self.params = [Function.Parameter(self, n) for n in pnames]
151                 self.category = None
152
153         def get_param(self, pname):
154                 for p in self.params:
155                         if p.name==pname:
156                                 return p
157                 raise KeyError, pname
158
159         def set_category(self, cat):
160                 self.category = cat
161
162         def compsize(self, size, btype):
163                 if not size:
164                         return
165
166                 res = ""
167                 have_type = False
168                 for c in size.replace(',', '/').split('/'):
169                         param = self.get_param(c)
170                         if not param:
171                                 sys.stderr.write("Compsize '%s' for function '%s' failed: No parameter '%s'\n"%(size, self.name, c))
172                                 return
173
174                         if res:
175                                 res += "*"
176
177                         cn = strip_name(param.type)
178                         if cn.endswith("Type"):
179                                 res += "typesize(%s)"%param.name
180                                 have_type = True
181                         elif cn.endswith("Format"):
182                                 res += "formatsize(%s)"%param.name
183                         elif cn.endswith(("Parameter", "ParameterPName", "ParameterName")) or cn=="GetPName":
184                                 res += "paramsize(%s)"%param.name
185                         elif cn=="MapTarget":
186                                 res += "mapsize(%s)"%param.name
187                         elif (cn=="SizeI" or cn.endswith("Int32")) and not param.size:
188                                 res += param.name
189                         else:
190                                 sys.stderr.write("Compsize '%s' for function '%s' failed: Parameter '%s' has unknown type '%s'\n"%(size, self.name, param.name, param.type))
191                                 return
192                 if not have_type:
193                         res += "*sizeof(%s)"%param.ctype
194                 return res
195
196         def finalize(self):
197                 self.ret.derive_ctype()
198                 for p in self.params:
199                         p.derive_ctype()
200                 for p in self.params:
201                         p.derive_csize()
202
203
204 class Template:
205         def __init__(self, fn):
206                 self.sections = []
207
208                 literal = True
209                 text = ""
210                 for line in InputFile(fn):
211                         if line[0]==':':
212                                 if not literal and text:
213                                         self.add_section(text, literal)
214                                         text = ""
215                                 text += line[1:]+"\n"
216                                 literal = True
217                         else:
218                                 if literal and text:
219                                         self.add_section(text, literal)
220                                         text = ""
221                                 text += line+"\n"
222                                 literal = False
223                 if text:
224                         self.add_section(text, literal)
225
226         def add_section(self, text, literal):
227                 if literal:
228                         self.sections.append(text)
229                 else:
230                         self.sections.append(compile(text, "-", "exec"))
231
232         def write(self, str, *args):
233                 sys.stdout.write(str%args)
234
235         def writeln(self, str, *args):
236                 sys.stdout.write(str%args+"\n")
237
238         def process(self, functions):
239                 for sect in self.sections:
240                         if type(sect)==str:
241                                 print sect
242                         else:
243                                 for func in functions:
244                                         globals = {
245                                                 "w": self.write,
246                                                 "wl": self.writeln,
247                                                 "func": func,
248                                                 "ret": func.ret,
249                                                 "params": func.params
250                                         }
251                                         eval(sect, globals)
252
253
254 class Files:
255         def __init__(self, fn):
256                 self.typemap = None
257                 self.iomap = None
258                 self.spec = None
259                 self.prefix = None
260                 self.ignore_categs = []
261                 self.ignore_funcs = []
262
263                 for line in InputFile(fn):
264                         parts = line.split()
265                         if parts[0]=="typemap":
266                                 self.typemap = parts[1]
267                         elif parts[0]=="iomap":
268                                 self.iomap = parts[1]
269                         elif parts[0]=="spec":
270                                 self.spec = parts[1]
271                         elif parts[0]=="prefix":
272                                 self.prefix = parts[1]
273                         elif parts[0]=="ignore":
274                                 if parts[1]=="category":
275                                         self.ignore_categs.append(parts[2])
276                                 elif parts[1]=="function":
277                                         self.ignore_funcs.append(parts[2])
278                         else:
279                                 sys.stderr.write("Unknown keyword '%s'\n", parts[0])
280
281
282 def read_spec(fn, prefix):
283         funcs = []
284         cur_func = None
285         for line in InputFile(fn):
286                 if line.find(':')>=0:
287                         continue
288                 elif line[0]=='\t' and cur_func:
289                         parts = line.split()
290                         if parts[0]=="return":
291                                 cur_func.ret.set_type(parts[1], "out", "value")
292                         elif parts[0]=="param":
293                                 bracket = parts[4].find('[')
294                                 if bracket>=0:
295                                         parts.insert(5, parts[4][bracket:])
296                                         parts[4] = parts[4][:bracket]
297
298                                 param = cur_func.get_param(parts[1])
299                                 param.set_type(parts[2], parts[3], parts[4])
300                                 if len(parts)==6 or (len(parts)>6 and parts[6]!="retained"):
301                                         param.set_size(parts[5][1:-1])
302                         elif parts[0]=="category":
303                                 cur_func.set_category(parts[1])
304                         elif parts[0]=="glxvendorglx" and cur_func.category=="glx":
305                                 cur_func.set_category("glxext")
306                 else:
307                         paren = line.find('(')
308                         if paren>0:
309                                 cparen = line.rfind(')')
310                                 if cparen>paren+1:
311                                         pnames = [n.strip() for n in line[paren+1:cparen].split(",")]
312                                 else:
313                                         pnames = []
314                                 cur_func = Function(prefix+line[:paren], pnames)
315                                 funcs.append(cur_func)
316         return funcs
317
318 template = Template(sys.argv[1])
319 for i in sys.argv[2:]:
320         files = Files(i)
321
322         typemap = Typemap(files.typemap)
323         iomap = IOmap(files.iomap)
324         functions = read_spec(files.spec, files.prefix)
325         functions = [f for f in functions if f.name not in files.ignore_funcs and f.category not in files.ignore_categs]
326         for f in functions:
327                 f.finalize()
328
329         template.process(functions)