From: José Fonseca Date: Thu, 25 Nov 2010 11:35:16 +0000 (+0000) Subject: Rename GL spec parser. X-Git-Url: https://git.cworth.org/git?p=apitrace;a=commitdiff_plain;h=367ed6280873657dcde3e9d5cda31c43b3b36538 Rename GL spec parser. --- diff --git a/helpers/Makefile b/helpers/Makefile index d332cac..c12939a 100644 --- a/helpers/Makefile +++ b/helpers/Makefile @@ -20,13 +20,13 @@ download: \ %.spec %.tm: wget -N http://www.opengl.org/registry/api/$@ -glapi.py: spec.py gl.tm gl.spec - python spec.py gl gl.tm gl.spec > $@ +glapi.py: glspec.py gl.tm gl.spec + python glspec.py gl gl.tm gl.spec > $@ -glxapi.py: spec.py glx.tm glx.spec glxext.spec - python spec.py glX glx.tm glx.spec glxext.spec > $@ +glxapi.py: glspec.py glx.tm glx.spec glxext.spec + python glspec.py glX glx.tm glx.spec glxext.spec > $@ -wglapi.py: spec.py wgl.tm wgl.spec wglext.spec - python spec.py wgl wgl.tm wgl.spec wglext.spec > $@ +wglapi.py: glspec.py wgl.tm wgl.spec wglext.spec + python glspec.py wgl wgl.tm wgl.spec wglext.spec > $@ .PRECIOUS: %.spec %.tm diff --git a/helpers/glspec.py b/helpers/glspec.py new file mode 100755 index 0000000..401c317 --- /dev/null +++ b/helpers/glspec.py @@ -0,0 +1,278 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2010 VMware, Inc. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +##########################################################################/ + + +import sys +import re +import optparse + + +def stderr(x): + sys.stderr.write(str(x) + '\n') + + +class Parser: + + def __init__(self, stream): + pass + + +class LineParser: + """Base class for parsers that read line-based formats.""" + + def __init__(self, stream): + self._stream = stream + self._line = None + self._eof = False + # read lookahead + self.readline() + + def parse(self): + raise NotImplementedError + + def readline(self): + line = self._stream.readline() + if not line: + self._line = '' + self._eof = True + self._line = line.rstrip('\r\n') + + def lookahead(self): + assert self._line is not None + return self._line + + def consume(self): + assert self._line is not None + line = self._line + self.readline() + return line + + def eof(self): + assert self._line is not None + return self._eof + + def skip_whitespace(self): + while not self.eof() and self.match_whitespace() or self.match_comment(): + self.consume() + + def match_whitespace(self): + line = self.lookahead() + return not line.strip() + + def match_comment(self): + return False + + +class TypemapParser(LineParser): + + def parse(self): + typemap = {} + self.skip_whitespace() + while not self.eof(): + line = self.consume() + fields = [field.strip() for field in line.split(',')] + src = fields[0] + dst = fields[3] + if dst != '*': + typemap[src] = dst + self.skip_whitespace() + return typemap + + def match_comment(self): + line = self.lookahead() + return line.startswith('#') + + +class SpecParser(LineParser): + + property_re = re.compile(r'^\w+:') + prototype_re = re.compile(r'^(\w+)\((.*)\)$') + + def __init__(self, stream, prefix='', typemap = None): + LineParser.__init__(self, stream) + if typemap is None: + self.typemap = {} + else: + self.typemap = typemap + self.prefix = prefix + self.category = None + + def parse(self): + self.skip_whitespace() + while not self.eof(): + line = self.lookahead() + if self.property_re.match(line): + self.parse_property() + elif self.prototype_re.match(line): + self.parse_prototype() + else: + self.consume() + self.skip_whitespace() + + def parse_property(self): + line = self.consume() + name, value = line.split(':', 1) + if name == 'category': + values = value.split() + #self.prefix = values[0] + + get_function_re = re.compile(r'^Get[A-Z]\w+') + + def parse_prototype(self): + line = self.consume() + mo = self.prototype_re.match(line) + function_name, arg_names = mo.groups() + arg_names = [arg_name.strip() for arg_name in arg_names.split(',') if arg_name.strip()] + + extra = '' + if self.get_function_re.match(function_name): + extra += ', sideeffects=False' + function_name = self.prefix + function_name + + ret_type = 'Void' + arg_types = {} + category = None + line = self.lookahead() + while line.startswith('\t'): + fields = line.split(None, 2) + if fields[0] == 'return': + ret_type = self.parse_type(fields[1]) + elif fields[0] == 'param': + arg_name, arg_type = fields[1:3] + arg_types[fields[1]] = self.parse_arg(function_name, arg_name, arg_type) + elif fields[0] == 'category': + category = fields[1] + else: + pass + self.consume() + line = self.lookahead() + self.consume() + args = [arg_types[arg_name] for arg_name in arg_names] + + if category is not None: + if category == self.prefix: + category = self.prefix.upper() + else: + category = self.prefix.upper() + '_' + category + if category != self.category: + if self.category is not None: + print + print ' # %s' % category + self.category = category + + if self.prefix == 'wgl': + constructor = 'StdFunction' + else: + constructor = 'GlFunction' + + print ' %s(%s, "%s", [%s]%s),' % (constructor, ret_type, function_name, ', '.join(args), extra) + + array_re = re.compile(r'^array\s+\[(.*)\]$') + + string_typemap = { + 'GLchar': 'GLstring', + 'GLcharARB': 'GLstringARB', + } + + def parse_arg(self, function_name, arg_name, arg_type): + orig_type, inout, kind = arg_type.split(' ', 2) + + base_type = self.parse_type(orig_type) + + if kind == 'value': + arg_type = base_type + elif kind == 'reference': + arg_type = 'Pointer(%s)' % base_type + if inout == 'in': + arg_type = 'Const(%s)' % arg_type + elif kind.startswith("array"): + arg_type = 'OpaquePointer(%s)' % base_type + + mo = self.array_re.match(kind) + if mo: + length = mo.group(1).strip() + if length == '': + try: + arg_type = self.string_typemap[base_type] + except KeyError: + pass + elif length == '1': + arg_type = 'Pointer(%s)' % base_type + elif length.find("COMPSIZE") == -1: + arg_type = 'Array(%s, "%s")' % (base_type, length) + else: + # XXX: Handle COMPSIZE better + length = length.replace("COMPSIZE", "__%s_size" % function_name) + length = length.replace("/", ",") + arg_type = 'Array(%s, "%s")' % (base_type, length) + if inout == 'in': + arg_type = 'Const(%s)' % arg_type + else: + assert False + + arg = '(%s, "%s")' % (arg_type, arg_name) + if inout == 'out': + arg = 'Out' + arg + return arg + + semantic_typemap = { + 'String': 'CString', + 'Texture': 'GLtexture', + } + + post_typemap = { + 'void': 'Void', + 'int': 'Int', + 'float': 'Float', + } + + def parse_type(self, type): + try: + return self.semantic_typemap[type] + except KeyError: + pass + type = self.typemap.get(type, type) + type = self.post_typemap.get(type, type) + return type + + def match_comment(self): + line = self.lookahead() + return line.startswith('#') + + +def main(): + prefix = sys.argv[1] + + parser = TypemapParser(open(sys.argv[2], 'rt')) + typemap = parser.parse() + + for arg in sys.argv[3:]: + parser = SpecParser(open(arg, 'rt'), prefix=prefix, typemap=typemap) + parser.parse() + + +if __name__ == '__main__': + main() diff --git a/helpers/spec.py b/helpers/spec.py deleted file mode 100755 index 401c317..0000000 --- a/helpers/spec.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python -########################################################################## -# -# Copyright 2010 VMware, Inc. -# All Rights Reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -##########################################################################/ - - -import sys -import re -import optparse - - -def stderr(x): - sys.stderr.write(str(x) + '\n') - - -class Parser: - - def __init__(self, stream): - pass - - -class LineParser: - """Base class for parsers that read line-based formats.""" - - def __init__(self, stream): - self._stream = stream - self._line = None - self._eof = False - # read lookahead - self.readline() - - def parse(self): - raise NotImplementedError - - def readline(self): - line = self._stream.readline() - if not line: - self._line = '' - self._eof = True - self._line = line.rstrip('\r\n') - - def lookahead(self): - assert self._line is not None - return self._line - - def consume(self): - assert self._line is not None - line = self._line - self.readline() - return line - - def eof(self): - assert self._line is not None - return self._eof - - def skip_whitespace(self): - while not self.eof() and self.match_whitespace() or self.match_comment(): - self.consume() - - def match_whitespace(self): - line = self.lookahead() - return not line.strip() - - def match_comment(self): - return False - - -class TypemapParser(LineParser): - - def parse(self): - typemap = {} - self.skip_whitespace() - while not self.eof(): - line = self.consume() - fields = [field.strip() for field in line.split(',')] - src = fields[0] - dst = fields[3] - if dst != '*': - typemap[src] = dst - self.skip_whitespace() - return typemap - - def match_comment(self): - line = self.lookahead() - return line.startswith('#') - - -class SpecParser(LineParser): - - property_re = re.compile(r'^\w+:') - prototype_re = re.compile(r'^(\w+)\((.*)\)$') - - def __init__(self, stream, prefix='', typemap = None): - LineParser.__init__(self, stream) - if typemap is None: - self.typemap = {} - else: - self.typemap = typemap - self.prefix = prefix - self.category = None - - def parse(self): - self.skip_whitespace() - while not self.eof(): - line = self.lookahead() - if self.property_re.match(line): - self.parse_property() - elif self.prototype_re.match(line): - self.parse_prototype() - else: - self.consume() - self.skip_whitespace() - - def parse_property(self): - line = self.consume() - name, value = line.split(':', 1) - if name == 'category': - values = value.split() - #self.prefix = values[0] - - get_function_re = re.compile(r'^Get[A-Z]\w+') - - def parse_prototype(self): - line = self.consume() - mo = self.prototype_re.match(line) - function_name, arg_names = mo.groups() - arg_names = [arg_name.strip() for arg_name in arg_names.split(',') if arg_name.strip()] - - extra = '' - if self.get_function_re.match(function_name): - extra += ', sideeffects=False' - function_name = self.prefix + function_name - - ret_type = 'Void' - arg_types = {} - category = None - line = self.lookahead() - while line.startswith('\t'): - fields = line.split(None, 2) - if fields[0] == 'return': - ret_type = self.parse_type(fields[1]) - elif fields[0] == 'param': - arg_name, arg_type = fields[1:3] - arg_types[fields[1]] = self.parse_arg(function_name, arg_name, arg_type) - elif fields[0] == 'category': - category = fields[1] - else: - pass - self.consume() - line = self.lookahead() - self.consume() - args = [arg_types[arg_name] for arg_name in arg_names] - - if category is not None: - if category == self.prefix: - category = self.prefix.upper() - else: - category = self.prefix.upper() + '_' + category - if category != self.category: - if self.category is not None: - print - print ' # %s' % category - self.category = category - - if self.prefix == 'wgl': - constructor = 'StdFunction' - else: - constructor = 'GlFunction' - - print ' %s(%s, "%s", [%s]%s),' % (constructor, ret_type, function_name, ', '.join(args), extra) - - array_re = re.compile(r'^array\s+\[(.*)\]$') - - string_typemap = { - 'GLchar': 'GLstring', - 'GLcharARB': 'GLstringARB', - } - - def parse_arg(self, function_name, arg_name, arg_type): - orig_type, inout, kind = arg_type.split(' ', 2) - - base_type = self.parse_type(orig_type) - - if kind == 'value': - arg_type = base_type - elif kind == 'reference': - arg_type = 'Pointer(%s)' % base_type - if inout == 'in': - arg_type = 'Const(%s)' % arg_type - elif kind.startswith("array"): - arg_type = 'OpaquePointer(%s)' % base_type - - mo = self.array_re.match(kind) - if mo: - length = mo.group(1).strip() - if length == '': - try: - arg_type = self.string_typemap[base_type] - except KeyError: - pass - elif length == '1': - arg_type = 'Pointer(%s)' % base_type - elif length.find("COMPSIZE") == -1: - arg_type = 'Array(%s, "%s")' % (base_type, length) - else: - # XXX: Handle COMPSIZE better - length = length.replace("COMPSIZE", "__%s_size" % function_name) - length = length.replace("/", ",") - arg_type = 'Array(%s, "%s")' % (base_type, length) - if inout == 'in': - arg_type = 'Const(%s)' % arg_type - else: - assert False - - arg = '(%s, "%s")' % (arg_type, arg_name) - if inout == 'out': - arg = 'Out' + arg - return arg - - semantic_typemap = { - 'String': 'CString', - 'Texture': 'GLtexture', - } - - post_typemap = { - 'void': 'Void', - 'int': 'Int', - 'float': 'Float', - } - - def parse_type(self, type): - try: - return self.semantic_typemap[type] - except KeyError: - pass - type = self.typemap.get(type, type) - type = self.post_typemap.get(type, type) - return type - - def match_comment(self): - line = self.lookahead() - return line.startswith('#') - - -def main(): - prefix = sys.argv[1] - - parser = TypemapParser(open(sys.argv[2], 'rt')) - typemap = parser.parse() - - for arg in sys.argv[3:]: - parser = SpecParser(open(arg, 'rt'), prefix=prefix, typemap=typemap) - parser.parse() - - -if __name__ == '__main__': - main()