]> git.cworth.org Git - apitrace/blob - specs/scripts/gltxt.py
Update downloads link.
[apitrace] / specs / scripts / gltxt.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 """Parser for OpenGL .txt extensions specification."""
29
30
31 import sys
32 import re
33 import optparse
34 from urllib2 import urlopen
35
36
37 def stderr(x):
38     sys.stderr.write(str(x) + '\n')
39
40
41 class Parser:
42
43     def __init__(self, stream):
44         pass
45
46
47 class LineParser:
48     """Base class for parsers that read line-based formats."""
49
50     def __init__(self, stream):
51         self._stream = stream
52         self._line = None
53         self._eof = False
54         # read lookahead
55         self.readline()
56     
57     def parse(self):
58         raise NotImplementedError
59
60     def readline(self):
61         line = self._stream.readline()
62         if not line:
63             self._line = ''
64             self._eof = True
65         self._line = line.rstrip('\r\n')
66
67     def lookahead(self):
68         assert self._line is not None
69         return self._line
70
71     def consume(self):
72         assert self._line is not None
73         line = self._line
74         self.readline()
75         return line
76
77     def eof(self):
78         assert self._line is not None
79         return self._eof
80     
81     def skip_whitespace(self):
82         while not self.eof() and self.match_whitespace() or self.match_comment():
83             self.consume()
84
85     def match_whitespace(self):
86         line = self.lookahead()
87         return not line.strip()
88
89     def match_comment(self):
90         return False
91
92
93 class TxtParser(LineParser):
94
95     section_re = re.compile(r'^([A-Z]\w+)( \w+)*$')
96
97     property_re = re.compile(r'^\w+:')
98     prototype_re = re.compile(r'^(\w+)\((.*)\)$')
99
100     comment_start_re = re.compile(r'^/\*')
101     comment_end_re = re.compile(r'.*\*/$')
102
103     def __init__(self, stream, prefix=''):
104         LineParser.__init__(self, stream)
105         self.prefix = prefix
106
107     def parse(self):
108         while  not self.eof():
109             while not self.eof():
110                 line = self.lookahead()
111                 if self.eof():
112                     return
113                 mo = self.section_re.match(line)
114                 if mo:
115                     break
116                 self.consume()
117             line = self.consume()
118             self.parse_section(line)
119         print
120
121     def parse_section(self, name):
122         if name == 'Name Strings':
123             self.parse_strings()
124         if name == 'New Procedures and Functions':
125             self.parse_procs()
126
127     def parse_strings(self):
128         while not self.eof():
129             line = self.lookahead()
130             if not line.strip():
131                 self.consume()
132                 continue
133             if not line.startswith(' '):
134                 break
135             self.consume()
136             name = line.strip()
137             print '    # %s' % name
138
139     def skip_c_comments(self):
140         while not self.eof():
141             line = self.lookahead().strip()
142             mo = self.comment_start_re.match(line)
143             if not mo:
144                 return
145             while not self.eof():
146                 self.consume()
147                 mo = self.comment_end_re.match(line)
148                 if mo:
149                     return
150                 line = self.lookahead().strip()
151
152     def parse_procs(self):
153         lines = []
154         while not self.eof():
155             self.skip_c_comments()
156             line = self.lookahead()
157             if not line.strip():
158                 self.consume()
159                 continue
160             if not line.startswith(' '):
161                 break
162             self.consume()
163             lines.append(line.strip())
164             if line[-1] in (';', ')'):
165                 prototype = ' '.join(lines)
166                 self.parse_proc(prototype)
167                 lines = []
168
169     token_re = re.compile(r'(\w+|\s+|.)')
170     get_function_re = re.compile(r'^Get[A-Z]\w+')
171
172     def parse_proc(self, prototype):
173         #print prototype
174         tokens = self.token_re.split(prototype)
175         self.tokens = [token for token in tokens if token.strip()]
176         #print self.tokens
177
178         ret = self.parse_type()
179
180         name = self.tokens.pop(0)
181         extra = ''
182         if self.get_function_re.match(name):
183             extra += ', sideeffects=False'
184         name = self.prefix + name
185
186         assert self.tokens.pop(0) == '('
187         args = []
188         while self.tokens[0] != ')':
189             arg = self.parse_arg()
190             args.append(arg)
191             if self.tokens[0] == ',':
192                 self.tokens.pop(0)
193         print '    GlFunction(%s, "%s", [%s]%s),' % (ret, name, ', '.join(args), extra)
194
195     def parse_arg(self):
196         type = self.parse_type()
197         if self.tokens[0] == ')':
198             assert type == 'Void'
199             return ''
200         name = self.tokens.pop(0)
201         if self.tokens[0] == '[':
202             self.tokens.pop(0)
203             n = int(self.tokens.pop(0))
204             assert self.tokens.pop(0) == ']'
205             type = 'Array(%s, %d)' % (type, n)
206         return '(%s, "%s")' % (type, name)
207
208     def parse_type(self):
209         token = self.tokens.pop(0)
210         if token == 'const':
211             return 'Const(%s)' % self.parse_type()
212         if token == 'void':
213             type = 'Void'
214         else:
215             type = self.prefix.upper() + token
216         while self.tokens[0] == '*':
217             type = 'OpaquePointer(%s)' % type
218             self.tokens.pop(0)
219         return type
220
221
222 def main():
223     optparser = optparse.OptionParser(
224         usage="\n\t%prog [options] [SPEC] ")
225     optparser.add_option(
226         '-p', '--prefix', metavar='STRING',
227         type="string", dest="prefix", default='gl',
228         help="function prefix [default: %default]")
229
230     (options, args) = optparser.parse_args(sys.argv[1:])
231
232     for arg in args:
233         if arg.startswith('http://'):
234             stream = urlopen(arg, 'rt')
235         else:
236             stream = open(arg, 'rt')
237         parser = TxtParser(stream, prefix = options.prefix)
238         parser.parse()
239     
240
241 if __name__ == '__main__':
242     main()