]> git.cworth.org Git - apitrace/blob - specs/scripts/gltxt.py
Minor cleanups and better documentation for the spec generation scripts.
[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     def __init__(self, stream, prefix=''):
101         LineParser.__init__(self, stream)
102         self.prefix = prefix
103
104     def parse(self):
105         while  not self.eof():
106             while not self.eof():
107                 line = self.lookahead()
108                 if self.eof():
109                     return
110                 mo = self.section_re.match(line)
111                 if mo:
112                     break
113                 self.consume()
114             line = self.consume()
115             self.parse_section(line)
116         print
117
118     def parse_section(self, name):
119         if name == 'Name Strings':
120             self.parse_strings()
121         if name == 'New Procedures and Functions':
122             self.parse_procs()
123
124     def parse_strings(self):
125         while not self.eof():
126             line = self.lookahead()
127             if not line.strip():
128                 self.consume()
129                 continue
130             if not line.startswith(' '):
131                 break
132             self.consume()
133             name = line.strip()
134             print '    # %s' % name
135
136     def parse_procs(self):
137         lines = []
138         while not self.eof():
139             line = self.lookahead()
140             if not line.strip():
141                 self.consume()
142                 continue
143             if not line.startswith(' '):
144                 break
145             self.consume()
146             lines.append(line.strip())
147             if line[-1] in (';', ')'):
148                 prototype = ' '.join(lines)
149                 self.parse_proc(prototype)
150                 lines = []
151
152     token_re = re.compile(r'(\w+|\s+|.)')
153     get_function_re = re.compile(r'^Get[A-Z]\w+')
154
155     def parse_proc(self, prototype):
156         #print prototype
157         tokens = self.token_re.split(prototype)
158         self.tokens = [token for token in tokens if token.strip()]
159         #print self.tokens
160
161         ret = self.parse_type()
162
163         name = self.tokens.pop(0)
164         extra = ''
165         if self.get_function_re.match(name):
166             extra += ', sideeffects=False'
167         name = self.prefix + name
168
169         assert self.tokens.pop(0) == '('
170         args = []
171         while self.tokens[0] != ')':
172             arg = self.parse_arg()
173             args.append(arg)
174             if self.tokens[0] == ',':
175                 self.tokens.pop(0)
176         print '    GlFunction(%s, "%s", [%s]%s),' % (ret, name, ', '.join(args), extra)
177
178     def parse_arg(self):
179         type = self.parse_type()
180         name = self.tokens.pop(0)
181         return '(%s, "%s")' % (type, name)
182
183     def parse_type(self):
184         token = self.tokens.pop(0)
185         if token == 'const':
186             return 'Const(%s)' % self.parse_type()
187         if token == 'void':
188             type = 'Void'
189         else:
190             type = 'GL' + token
191         while self.tokens[0] == '*':
192             type = 'OpaquePointer(%s)' % type
193             self.tokens.pop(0)
194         return type
195
196
197 def main():
198     optparser = optparse.OptionParser(
199         usage="\n\t%prog [options] [SPEC] ")
200     optparser.add_option(
201         '-p', '--prefix', metavar='STRING',
202         type="string", dest="prefix", default='gl',
203         help="function prefix [default: %default]")
204
205     (options, args) = optparser.parse_args(sys.argv[1:])
206
207     for arg in args:
208         if arg.startswith('http://'):
209             stream = urlopen(arg, 'rt')
210         else:
211             stream = open(arg, 'rt')
212         parser = TxtParser(stream, prefix = options.prefix)
213         parser.parse()
214     
215
216 if __name__ == '__main__':
217     main()