]> git.cworth.org Git - apitrace/blob - helpers/spec.py
c4f2df5faf074207a038f76133a88d00ea39a703
[apitrace] / helpers / spec.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2010 VMware, Inc.
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 # THE SOFTWARE.
24 #
25 ##########################################################################/
26
27
28 import sys
29 import re
30 import optparse
31
32
33 class Parser:
34
35     def __init__(self, stream):
36         pass
37
38
39 class LineParser:
40     """Base class for parsers that read line-based formats."""
41
42     def __init__(self, stream):
43         self._stream = stream
44         self._line = None
45         self._eof = False
46         # read lookahead
47         self.readline()
48     
49     def parse(self):
50         raise NotImplementedError
51
52     def readline(self):
53         line = self._stream.readline()
54         if not line:
55             self._line = ''
56             self._eof = True
57         self._line = line.rstrip('\r\n')
58
59     def lookahead(self):
60         assert self._line is not None
61         return self._line
62
63     def consume(self):
64         assert self._line is not None
65         line = self._line
66         self.readline()
67         return line
68
69     def eof(self):
70         assert self._line is not None
71         return self._eof
72     
73     def skip_whitespace(self):
74         while not self.eof() and self.match_whitespace() or self.match_comment():
75             self.consume()
76
77     def match_whitespace(self):
78         line = self.lookahead()
79         return not line.strip()
80
81     def match_comment(self):
82         return False
83
84
85 class TypemapParser(LineParser):
86
87     def parse(self):
88         typemap = {}
89         self.skip_whitespace()
90         while not self.eof():
91             line = self.consume()
92             fields = [field.strip() for field in line.split(',')]
93             src = fields[0]
94             dst = fields[3]
95             self.skip_whitespace()
96             typemap[src] = dst
97         return typemap
98     
99     def match_comment(self):
100         line = self.lookahead()
101         return line.startswith('#')
102
103
104 class SpecParser(LineParser):
105
106     property_re = re.compile(r'^\w+:')
107     prototype_re = re.compile(r'^(\w+)\((.*)\)$')
108
109     def __init__(self, stream, prefix='', typemap = None):
110         LineParser.__init__(self, stream)
111         if typemap is None:
112             self.typemap = {}
113         else:
114             self.typemap = typemap
115         self.prefix = prefix
116         self.category = None
117
118     def parse(self):
119         self.skip_whitespace()
120         while not self.eof():
121             line = self.lookahead()
122             if self.property_re.match(line):
123                 self.parse_property()
124             elif self.prototype_re.match(line):
125                 self.parse_prototype()
126             else:
127                 self.consume()
128             self.skip_whitespace()
129
130     def parse_property(self):
131         line = self.consume()
132         name, value = line.split(':', 1)
133         if name == 'category':
134             values = value.split()
135             #self.prefix = values[0]
136
137     get_function_re = re.compile(r'^Get[A-Z]\w+')
138
139     def parse_prototype(self):
140         line = self.consume()
141         mo = self.prototype_re.match(line)
142         function_name, arg_names = mo.groups()
143         arg_names = [arg_name.strip() for arg_name in arg_names.split(',') if arg_name.strip()]
144         
145         ret_type = 'Void'
146         arg_types = {}
147         category = None
148         line = self.lookahead()
149         while line.startswith('\t'):
150             fields = line.split(None, 2)
151             if fields[0] == 'return':
152                 ret_type = self.parse_type(fields[1])
153             elif fields[0] == 'param':
154                 arg_name, arg_type = fields[1:3]
155                 arg_types[fields[1]] = self.parse_arg(arg_name, arg_type)
156             elif fields[0] == 'category':
157                 category = fields[1]
158             else:
159                 pass
160             self.consume()
161             line = self.lookahead()
162         self.consume()
163         args = [arg_types[arg_name] for arg_name in arg_names]
164
165         if category is not None:
166             if category == self.prefix:
167                 category = self.prefix.upper()
168             else:
169                 category = self.prefix.upper() + '_' + category
170             if category != self.category:
171                 if self.category is not None:
172                     print
173                 print '    # %s' % category
174                 self.category = category
175
176         if self.prefix == 'wgl':
177             constructor = 'StdFunction'
178         else:
179             constructor = 'glFunction'
180         extra = ''
181         if self.get_function_re.match(function_name):
182             extra += ', sideeffects=False'
183         print '    %s(%s, "%s%s", [%s]%s),' % (constructor, ret_type, self.prefix, function_name, ', '.join(args), extra)
184
185     array_re = re.compile(r'^array\s+\[(.*)\]$')
186
187     def parse_arg(self, arg_name, arg_type):
188         base_type, inout, kind = arg_type.split(' ', 2)
189         base_type = self.parse_type(base_type)
190
191         if kind == 'value':
192             arg_type = base_type
193         elif kind == 'reference':
194             arg_type = 'Pointer(%s)' % base_type
195             if inout == 'in':
196                 arg_type = 'Const(%s)' % arg_type
197         elif kind.startswith("array"):
198             mo = self.array_re.match(kind)
199             if mo:
200                 length = mo.group(1)
201                 arg_type = 'Array(%s, "%s")' % (base_type, length)
202             else:
203                 arg_type = 'OpaquePointer(%s)' % base_type
204             if inout == 'in':
205                 arg_type = 'Const(%s)' % arg_type
206         else:
207             assert False
208         
209         arg = '(%s, "%s")' % (arg_type, arg_name)
210         if inout == 'out':
211             arg = 'Out' + arg
212         return arg
213
214     _typemap = {
215         'void': 'Void',
216         'int': 'Int',
217         'float': 'Float',
218     }
219
220     def parse_type(self, type):
221         type = self.typemap.get(type, type)
222         type = self._typemap.get(type, type)
223         return type
224
225     def match_comment(self):
226         line = self.lookahead()
227         return line.startswith('#')
228
229
230 def main():
231     prefix = sys.argv[1]
232
233     parser = TypemapParser(open(sys.argv[2], 'rt'))
234     typemap = parser.parse()
235
236     for arg in sys.argv[3:]:
237         parser = SpecParser(open(arg, 'rt'), prefix=prefix, typemap=typemap)
238         parser.parse()
239     
240
241 if __name__ == '__main__':
242     main()