2 ##########################################################################
4 # Copyright 2010 VMware, Inc.
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:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
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
25 ##########################################################################/
27 """Parser for OpenGL .spec files in http://www.opengl.org/registry/."""
36 sys.stderr.write(str(x) + '\n')
41 def __init__(self, stream):
46 """Base class for parsers that read line-based formats."""
48 def __init__(self, stream):
56 raise NotImplementedError
59 line = self._stream.readline()
63 self._line = line.rstrip('\r\n')
66 assert self._line is not None
70 assert self._line is not None
76 assert self._line is not None
79 def skip_whitespace(self):
80 while not self.eof() and self.match_whitespace() or self.match_comment():
83 def match_whitespace(self):
84 line = self.lookahead()
85 return not line.strip()
87 def match_comment(self):
91 class TypemapParser(LineParser):
95 self.skip_whitespace()
98 fields = [field.strip() for field in line.split(',')]
103 self.skip_whitespace()
106 def match_comment(self):
107 line = self.lookahead()
108 return line.startswith('#')
111 class SpecParser(LineParser):
113 property_re = re.compile(r'^\w+:')
114 prototype_re = re.compile(r'^(\w+)\((.*)\)$')
116 def __init__(self, stream, prefix='', typemap = None):
117 LineParser.__init__(self, stream)
121 self.typemap = typemap
126 self.skip_whitespace()
127 while not self.eof():
128 line = self.lookahead()
129 if self.property_re.match(line):
130 self.parse_property()
131 elif self.prototype_re.match(line):
132 self.parse_prototype()
135 self.skip_whitespace()
137 def parse_property(self):
138 line = self.consume()
139 name, value = line.split(':', 1)
140 if name == 'category':
141 values = value.split()
142 #self.prefix = values[0]
144 get_function_re = re.compile(r'^(Get|Is|Are)[A-Z]\w+')
146 def parse_prototype(self):
147 line = self.consume()
148 mo = self.prototype_re.match(line)
149 function_name, arg_names = mo.groups()
150 arg_names = [arg_name.strip() for arg_name in arg_names.split(',') if arg_name.strip()]
153 if self.get_function_re.match(function_name):
154 extra += ', sideeffects=False'
155 function_name = self.prefix + function_name
160 line = self.lookahead()
161 while line.startswith('\t'):
162 fields = line.split(None, 2)
163 if fields[0] == 'return':
164 ret_type = self.parse_type(fields[1])
165 elif fields[0] == 'param':
166 arg_name, arg_type = fields[1:3]
167 arg_types[fields[1]] = self.parse_arg(function_name, arg_name, arg_type)
168 elif fields[0] == 'category':
173 line = self.lookahead()
175 args = [arg_types[arg_name] for arg_name in arg_names]
177 if category is not None:
178 if category == self.prefix:
179 category = self.prefix.upper()
181 category = self.prefix.upper() + '_' + category
182 if category != self.category:
183 if self.category is not None:
185 print ' # %s' % category
186 self.category = category
188 if self.prefix == 'wgl':
189 constructor = 'StdFunction'
191 constructor = 'GlFunction'
193 print ' %s(%s, "%s", [%s]%s),' % (constructor, ret_type, function_name, ', '.join(args), extra)
195 array_re = re.compile(r'^array\s+\[(.*)\]$')
198 'GLchar': 'GLstring',
199 'GLcharARB': 'GLstringARB',
202 def parse_arg(self, function_name, arg_name, arg_type):
203 orig_type, inout, kind = arg_type.split(' ', 2)
205 base_type = self.parse_type(orig_type)
209 elif kind == 'reference':
211 base_type = 'Const(%s)' % base_type
212 arg_type = 'Pointer(%s)' % base_type
213 elif kind.startswith("array"):
215 base_type = 'Const(%s)' % base_type
217 arg_type = 'OpaquePointer(%s)' % base_type
219 if base_type in ('Void', 'void', 'GLvoid'):
222 constructor = 'Array'
224 mo = self.array_re.match(kind)
226 length = mo.group(1).strip()
229 arg_type = self.string_typemap[base_type]
233 arg_type = 'Pointer(%s)' % base_type
234 elif length.find("COMPSIZE") == -1:
238 length = '"%s"' % length
239 arg_type = '%s(%s, %s)' % (constructor, base_type, length)
241 if length == "COMPSIZE(pname)":
242 length = "_gl_param_size(pname)"
243 arg_type = '%s(%s, "%s")' % (constructor, base_type, length)
245 length = length.replace("COMPSIZE", "_%s_size" % function_name)
246 length = length.replace("/", ", ")
247 arg_type = 'Opaque%s(%s, "%s")' % (constructor, base_type, length)
251 arg = '(%s, "%s")' % (arg_type, arg_name)
258 'Texture': 'GLtexture',
267 def parse_type(self, type):
269 return self.semantic_typemap[type]
272 type = self.typemap.get(type, type)
273 type = self.post_typemap.get(type, type)
276 def match_comment(self):
277 line = self.lookahead()
278 return line.startswith('#')
284 parser = TypemapParser(open(sys.argv[2], 'rt'))
285 typemap = parser.parse()
287 for arg in sys.argv[3:]:
288 parser = SpecParser(open(arg, 'rt'), prefix=prefix, typemap=typemap)
292 if __name__ == '__main__':