diff options
Diffstat (limited to 'ppapi/generators/idl_c_proto.py')
-rw-r--r-- | ppapi/generators/idl_c_proto.py | 794 |
1 files changed, 550 insertions, 244 deletions
diff --git a/ppapi/generators/idl_c_proto.py b/ppapi/generators/idl_c_proto.py index 145eff1..3809795 100644 --- a/ppapi/generators/idl_c_proto.py +++ b/ppapi/generators/idl_c_proto.py @@ -11,243 +11,537 @@ import os import sys from idl_log import ErrOut, InfoOut, WarnOut -from idl_node import IDLAttribute, IDLAst, IDLNode +from idl_node import IDLNode +from idl_ast import IDLAst from idl_option import GetOption, Option, ParseOptions -from idl_outfile import IDLOutFile -from idl_parser import IDLParser, ParseFiles - - -# -# 'C' style parameter and return styles -# - -# Normal parameters (int8_t, etc...) -NormalType = { - 'in': '$TYPEREF$', - 'inout': '$TYPEREF$*', - 'out': '$TYPEREF$*', - 'store': '$TYPEREF$', - 'return': '$TYPEREF$' -} - -# Enum uses the enum's name, except when storing. -EnumType = { - 'in': '$TYPEREF$', - 'inout': '$TYPEREF$*', - 'out': '$TYPEREF$*', - 'store': 'int', - 'return': '$TYPEREF$' -} - -# A mem_t is a 'void *' to memory. -MemPtrType = { - 'in': 'const void*', - 'inout': 'void*', - 'out': 'void*', - 'store': 'void*', - 'return': 'void*' -} - -# A str_t is a string pointer 'char *'. -CharPtrType = { - 'in': 'const char*', - 'inout': 'char*', - 'out': 'char*', - 'return': 'char*', - 'store': 'char*' -} - -# A function pointer type -FuncType = { - 'in': '$TYPEREF$', - 'inout': '$TYPEREF$', - 'out': '$TYPEREF$', - 'return': '$TYPEREF$', - 'store': '$TYPEREF$' -} - -# A 'struct' is passed by pointer. -StructType = { - 'in': 'const $TYPEREF$*', - 'inout': '$TYPEREF$*', - 'out': '$TYPEREF$*', - 'return': '$TYPEREF$*', - 'store': '$TYPEREF$' -} - -# A 'void' does not have a parameter or storage type. -VoidType = { - 'in': None, - 'inout': None, - 'out': None, - 'return': 'void', - 'store': None -} - -TypeMap = { - 'func': FuncType, - 'enum': EnumType, - 'mem_t': MemPtrType, - 'str_t': CharPtrType, - 'struct': StructType, - 'void': VoidType -} - - -# Place the individual 'normal' types in the type map. -for name in ['int8_t', 'int16_t' ,'int32_t', 'int64_t', 'uint8_t', 'uint16_t', - 'uint32_t', 'uint64_t', 'double_t', 'float_t', 'handle_t', 'bool']: - TypeMap[name] = NormalType - - - -# Return the name of the node with suffix/prefix if availible. -def GetName(node, **keyargs): - prefix = keyargs.get('prefix','') - suffix = keyargs.get('suffix', '') - named = keyargs.get('named', True) - name = node.name - if not named: name = '' - return '%s%s%s' % (prefix, name, suffix) - - -# Return the array specification of the object. -def GetArrayspec(node, name): - assert(node.cls == 'Array') - out = '' - fixed = node.GetProperty('FIXED') - if fixed: - out = '%s[%s]' % (name, fixed) - else: - out = '*%s' % name - # Add children - for child in node.GetListOf('Array'): - out += GetArrayspec(child, name) - return out - - -# Return the <name>[<size>] form of the node. -def GetNameArray(node, **keyargs): - name = GetName(node, **keyargs) - for child in node.GetListOf('Array'): - name = GetArrayspec(child, name) - return name - - -def GetRootType(node): - root = node - while root.typeinfo: - typeinfo = root.typeinfo - if root.GetOneOf('Callspec'): - return TypeMap['func'] - root = root.typeinfo - return TypeMap[root.name] - - -# Get the passing form of the parameter. -def GetParamType(node, **keyargs): - typedata = GetRootType(node) - if node.GetProperty('in'): - return node.Replace(typedata['in']) - if node.GetProperty('out'): - return node.Replace(typedata['out']) - if node.GetProperty('inout'): - return node.Replace(typedata['inout']) - return node.GetProperty('TYPEREF') - - -# GetParam -# -# A Param signature is different than that of a Member because a Member is -# stored in the structure as declared, but the Param's signature is affected -# by how it gets passed and it's extended attributes like IN, OUT, and INOUT. -# -def GetParam(node, **keyargs): - # This may be a function. - callnode = node.GetOneOf('Callspec') - - typeref = GetParamType(node, **keyargs) - name = GetNameArray(node, **keyargs) - if callnode: - arglist = GetParamList(callnode, **keyargs) - return '%s (*%s)(%s)' % (typeref, name, ', '.join(arglist)) - return '%s %s' % (typeref, name) - - -# GetParamList -def GetParamList(node, **keyargs): - assert(node.cls == 'Callspec') - out = [] - for child in node.GetListOf('Param'): - out.append(GetParam(child, **keyargs)) - return out - - -# DefineSignature -def DefineSignature(node, **keyargs): - # This may be a function. - callnode = node.GetOneOf('Callspec') - - typeref = node.GetProperty('TYPEREF') - name = GetNameArray(node, **keyargs) - if callnode: - arglist = GetParamList(callnode, **keyargs) - return '%s (*%s)(%s)' % (typeref, name, ', '.join(arglist)) - return '%s %s' % (typeref, name) - -# Define a Member (or Function) in an interface. -def DefineMember(node, **keyargs): - return '%s;\n' % DefineSignature(node, **keyargs) - -# Define an Typedef. -def DefineTypedef(node, **keyargs): - return 'typedef %s;\n' % DefineSignature(node, **keyargs) - -# Define an Enum. -def DefineEnum(node, **keyargs): - out = 'enum %s {' % GetName(node, **keyargs) - - enumlist = [] - for child in node.GetListOf('EnumItem'): - value = child.GetProperty('VALUE') - enumlist.append(' %s = %s' % (GetName(child), value)) - return '%s\n%s\n};\n' % (out, ',\n'.join(enumlist)) - -# Define a Struct. -def DefineStruct(node, **keyargs): - out = 'struct %s {\n' % (GetName(node, **keyargs)) - - # Generate Member Functions - for child in node.GetListOf('Function'): - out += ' %s' % DefineMember(child, **keyargs) - - # Generate Member Variables - for child in node.GetListOf('Member'): - out += ' %s' % DefineMember(child, **keyargs) - out += '};' - return out - - -# Define a top level object. -def Define(node, **keyargs): - declmap = { - 'Enum' : DefineEnum, - 'Interface' : DefineStruct, - 'Struct' : DefineStruct, - 'Typedef' : DefineTypedef, +from idl_parser import ParseFiles + +Option('cgen_debug', 'Debug generate.') + +class CGenError(Exception): + def __init__(self, msg): + self.value = value + + def __str__(self): + return repr(self.value) + + +class CGen(object): + # TypeMap + # + # TypeMap modifies how an object is stored or passed, for example pointers + # are passed as 'const' if they are 'in' parameters, and structures are + # preceeded by the keyword 'struct' as well as using a pointer. + # + TypeMap = { + 'Array': { + 'in': 'const %s', + 'inout': '%s*', + 'out': '%s*', + 'store': '%s', + 'return': '%s' + }, + 'Callspec': { + 'in': '%s', + 'inout': '%s', + 'out': '%s', + 'store': '%s', + 'return': '%s' + }, + 'Enum': { + 'in': '%s', + 'inout': '%s*', + 'out': '%s*', + 'store': '%s', + 'return': '%s' + }, + 'Struct': { + 'in': 'const %s*', + 'inout': '%s*', + 'out': '%s*', + 'return': ' %s*', + 'store': '%s' + }, + 'mem_t': { + 'in': 'const %s', + 'inout': '%s', + 'out': '%s', + 'return': '%s', + 'store': '%s' + }, + 'str_t': { + 'in': 'const %s', + 'inout': '%s', + 'out': '%s', + 'return': 'const %s', + 'store': '%s' + }, + 'TypeValue': { + 'in': '%s', + 'inout': '%s*', + 'out': '%s*', + 'return': '%s', + 'store': '%s' + }, } - func = declmap.get(node.cls) - if not func: - ErrLog.Log('Failed to define %s named %s' % (node.cls, node.name)) - out = func(node, **keyargs) - - tab = '' - for i in range(keyargs.get('tabs', 0)): - tab += ' ' - return ('%s\n' % tab).join(out.split('\n')) + '\n' + # + # RemapName + # + # A diction array of PPAPI types that are converted to language specific + # types before being returned by by the C generator + # + RemapName = { + 'float_t': 'float', + 'double_t': 'double', + 'handle_t': 'int', + 'mem_t': 'void*', + 'str_t': 'char*', + 'interface_t' : 'const void*' + } + def __init__(self): + self.dbg_depth = 0 + self.vmin = 0.0 + self.vmax = 1e100 + self.release = 'M14' + + def SetVersionMap(self, node): + self.vmin = 0.0 + self.vmax = 1e100 + for version in node.GetListOf('LabelItem'): + if version.GetName() == GetOption('version'): + self.vmin = float(version.GetProperty('VALUE')) + self.vmax = float(version.GetProperty('VALUE')) + + # + # Debug Logging functions + # + def Log(self, txt): + if not GetOption('cgen_debug'): return + tabs = '' + for tab in range(self.dbg_depth): tabs += ' ' + print '%s%s' % (tabs, txt) + + def LogEnter(self, txt): + if txt: self.Log(txt) + self.dbg_depth += 1 + + def LogExit(self, txt): + self.dbg_depth -= 1 + if txt: self.Log(txt) + + # + # Return the array specification of the object. + # + def GetArraySpec(self, node): + assert(node.cls == 'Array') + out = '' + fixed = node.GetProperty('FIXED') + if fixed: + return '[%s]' % fixed + else: + return '[]' + + # + # GetTypeName + # + # For any valid 'typed' object such as Member or Typedef + # the typenode object contains the typename + # + # For a given node return the type name by passing mode. + # + def GetTypeName(self, node, prefix=''): + self.LogEnter('GetTypeName of %s' % node) + + # For Members, Params, and Typedef's your want type it refers to + if node.IsA('Member', 'Param', 'Typedef'): + typeref = node.GetType(self.release) + else: + typeref = node + + if typeref is None: + raise CGenError('No type for %s' % node) + + # If the type is a (BuiltIn) Type then return it's name + # remapping as needed + if typeref.IsA('Type'): + name = CGen.RemapName.get(typeref.GetName(), None) + if name is None: name = typeref.GetName() + name = '%s%s' % (prefix, name) + + # For structures, preceed with 'struct' or 'union' as appropriate + elif typeref.IsA('Interface', 'Struct'): + if typeref.GetProperty('union'): + name = 'union %s%s' % (prefix, typeref.GetName()) + else: + name = 'struct %s%s' % (prefix, typeref.GetName()) + + # If it's an enum, or typedef then return the Enum's name + elif typeref.IsA('Enum', 'Typedef'): + name = '%s%s' % (prefix, typeref.GetName()) + + else: + raise RuntimeError('Getting name of non-type %s.' % node) + self.LogExit('GetTypeName %s is %s' % (node, name)) + return name + + + # + # GetRootType + # + # For a given node return basic type of that object. This is + # either a 'Type', 'Callspec', or 'Array' + # + def GetRootTypeMode(self, node, mode): + self.LogEnter('GetRootType of %s' % node) + # If it has an array spec, then treat it as an array regardless of type + if node.GetOneOf('Array'): + rootType = 'Array' + # Or if it has a callspec, treat it as a function + elif node.GetOneOf('Callspec'): + rootType, mode = self.GetRootTypeMode(node.GetType(self.release), + 'return') + + # If it's a plain typedef, try that object's root type + elif node.IsA('Member', 'Param', 'Typedef'): + rootType, mode = self.GetRootTypeMode(node.GetType(self.release), mode) + + # If it's an Enum, then it's normal passing rules + elif node.IsA('Enum'): + rootType = node.cls + + # If it's an Interface or Struct, we may be passing by value + elif node.IsA('Interface', 'Struct'): + if mode == 'return': + if node.GetProperty('returnByValue'): + rootType = 'TypeValue' + else: + rootType = node.cls + else: + if node.GetProperty('passByValue'): + rootType = 'TypeValue' + else: + rootType = node.cls + + # If it's an Basic Type, check if it's a special type + elif node.IsA('Type'): + if node.GetName() in CGen.TypeMap: + rootType = node.GetName() + else: + rootType = 'TypeValue' + else: + raise RuntimeError('Getting root type of non-type %s.' % node) + self.LogExit('RootType is "%s"' % rootType) + return rootType, mode + + + def GetTypeByMode(self, node, mode): + self.LogEnter('GetTypeByMode of %s mode=%s' % (node, mode)) + name = self.GetTypeName(node) + type, mode = self.GetRootTypeMode(node, mode) + out = CGen.TypeMap[type][mode] % name + self.LogExit('GetTypeByMode %s = %s' % (node, out)) + return out + + + # Get the passing mode of the object (in, out, inout). + def GetParamMode(self, node): + self.Log('GetParamMode for %s' % node) + if node.GetProperty('in'): return 'in' + if node.GetProperty('out'): return 'out' + if node.GetProperty('inout'): return 'inout' + return 'return' + + # + # GetComponents + # + # Returns the signature components of an object as a tuple of + # (rtype, name, arrays, callspec) where: + # rtype - The store or return type of the object. + # name - The name of the object. + # arrays - A list of array dimensions as [] or [<fixed_num>]. + # args - None of not a function, otherwise a list of parameters. + # + def GetComponents(self, node, mode): + self.LogEnter('GetComponents mode %s for %s' % (mode, node)) + + # Generate passing type by modifying root type + rtype = self.GetTypeByMode(node, mode) + if node.IsA('Enum', 'Interface', 'Struct'): + rname = node.GetName() + else: + rname = node.GetType(self.release).GetName() + + if rname in CGen.RemapName: + rname = CGen.RemapName[rname] + if '%' in rtype: + rtype = rtype % rname + name = node.GetName() + arrayspec = [self.GetArraySpec(array) for array in node.GetListOf('Array')] + callnode = node.GetOneOf('Callspec') + if callnode: + callspec = [] + for param in callnode.GetListOf('Param'): + mode = self.GetParamMode(param) + ptype, pname, parray, pspec = self.GetComponents(param, mode) + callspec.append((ptype, pname, parray, pspec)) + else: + callspec = None + + self.LogExit('GetComponents: %s, %s, %s, %s' % + (rtype, name, arrayspec, callspec)) + return (rtype, name, arrayspec, callspec) + + + def Compose(self, rtype, name, arrayspec, callspec, prefix, func_as_ptr): + self.LogEnter('Compose: %s %s' % (rtype, name)) + arrayspec = ''.join(arrayspec) + name = '%s%s%s' % (prefix, name, arrayspec) + if callspec is None: + out = '%s %s' % (rtype, name) + else: + params = [] + for ptype, pname, parray, pspec in callspec: + params.append(self.Compose(ptype, pname, parray, pspec, '', True)) + if func_as_ptr: name = '(*%s)' % name + out = '%s %s(%s)' % (rtype, name, ', '.join(params)) + self.LogExit('Exit Compose: %s' % out) + return out + + # + # GetSignature + # + # Returns the 'C' style signature of the object + # prefix - A prefix for the object's name + # func_as_ptr - Formats a function as a function pointer + # + def GetSignature(self, node, mode, prefix='', func_as_ptr=True): + self.LogEnter('GetSignature %s %s as func=%s' % (node, mode, func_as_ptr)) + rtype, name, arrayspec, callspec = self.GetComponents(node, mode) + out = self.Compose(rtype, name, arrayspec, callspec, prefix, func_as_ptr) + self.LogExit('Exit GetSignature: %s' % out) + return out + + def GetMacro(self, node): + name = node.GetName() + name = name.upper() + return "%s_INTERFACE" % name + + def GetDefine(self, name, value): + out = '#define %s %s' % (name, value) + if len(out) > 80: + out = '#define %s \\\n %s' % (name, value) + return '%s\n' % out + + # Define an Typedef. + def DefineTypedef(self, node, prefix='', comment=False): + out = 'typedef %s;\n' % self.GetSignature(node, 'return', prefix, True) + self.Log('DefineTypedef: %s' % out) + return out + + # Define an Enum. + def DefineEnum(self, node, prefix='', comment=False): + self.LogEnter('DefineEnum %s' % node) + unnamed = node.GetProperty('unnamed') + if unnamed: + out = 'enum {' + else: + out = 'typedef enum {' + name = '%s%s' % (prefix, node.GetName()) + enumlist = [] + for child in node.GetListOf('EnumItem'): + value = child.GetProperty('VALUE') + comment_txt = '' + if comment: + for comment_node in child.GetListOf('Comment'): + comment_txt += self.Comment(comment_node, tabs=1) + if comment_txt: + comment_txt = '%s' % comment_txt + if value: + item_txt = '%s%s = %s' % (prefix, child.GetName(), value) + else: + item_txt = '%s%s' % (prefix, child.GetName()) + enumlist.append('%s %s' % (comment_txt, item_txt)) + self.LogExit('Exit DefineEnum') + + if unnamed: + out = '%s\n%s\n};\n' % (out, ',\n'.join(enumlist)) + else: + out = '%s\n%s\n} %s;\n' % (out, ',\n'.join(enumlist), name) + return out + + def DefineMember(self, node, prefix='', comment=False): + self.LogEnter('DefineMember %s' % node) + +# out = '' +# if comment: +# for doc in node.GetListOf('Comment'): +# out += self.Comment(doc) + out = '%s;' % self.GetSignature(node, 'store', '', True) + self.LogExit('Exit DefineMember') + return out + + # Define a Struct. + def DefineStruct(self, node, prefix='', comment=False): + out = '' + if node.IsA('Interface'): + release = 'M14' + name = node.GetName() + macro = node.GetProperty('macro') + if not macro: + macro = self.GetMacro(node) + label = node.GetLabel() + if label: + for vers in label.versions: + strver = str(vers).replace('.', '_') + out += self.GetDefine('%s_%s' % (macro, strver), + '"%s;%s"' % (name, vers)) + if label.GetRelease(vers) == release: + out += self.GetDefine(macro, '%s_%s' % (macro, strver)) + out += '\n' + + self.LogEnter('DefineStruct %s' % node) + if node.GetProperty('union'): + out += 'union %s%s {\n' % (prefix, node.GetName()) + else: + out += 'struct %s%s {\n' % (prefix, node.GetName()) + + # Generate Member Functions + members = [] + for child in node.GetListOf('Member'): + member = self.Define(child, tabs=1, comment=comment) + if not member: + continue + members.append(member) + out += '%s\n};\n' % '\n'.join(members) + self.LogExit('Exit DefineStruct') + return out + + # + # Copyright and Comment + # + # Generate a comment or copyright block + # + def Copyright(self, node, tabs=0): + lines = node.GetName().split('\n') + return self.CommentLines(lines, tabs) + + def Comment(self, node, prefix=None, tabs=0): + comment = node.GetName() + + # Ignore comments that do not have a '*' marker +# if comment[0] != '*' and not prefix: return '' + + lines = comment.split('\n') + if prefix: + prefix = prefix.split('\n') + if prefix[0] == '*' and lines[0] == '*': + lines = prefix + lines[1:] + else: + lines = prefix + lines; + return self.CommentLines(lines, tabs) + + def CommentLines(self, lines, tabs=0): + tab = ''.join([' ' for i in range(tabs)]) + if lines[-1] == '': + return '%s/*' % tab + ('\n%s *' % tab).join(lines) + '/\n' + else: + return '%s/*' % tab + ('\n%s *' % tab).join(lines) + ' */\n' + + + # Define a top level object. + def Define(self, node, tabs=0, prefix='', comment=False): + if True: +# try: + self.LogEnter('Define %s tab=%d prefix="%s"' % (node,tabs,prefix)) + + min = node.GetProperty('version') + max = node.GetProperty('deprecate') + + if min is not None: + min = float(min) + else: + min = 0.0 + + if max is not None: + max = float(max) + else: + max = 1.0e100 + + label = node.GetLabel() + if label: + lver = label.GetVersion('M14') + + # Verify that we are in a valid version. + if max <= lver: return '' + if min > lver: return '' + + declmap = { + 'Enum' : CGen.DefineEnum, + 'Function' : CGen.DefineMember, + 'Interface' : CGen.DefineStruct, + 'Member' : CGen.DefineMember, + 'Struct' : CGen.DefineStruct, + 'Typedef' : CGen.DefineTypedef, + } + + if node.cls == 'Inline': + return node.GetProperty('VALUE') + + if node.cls == 'Label': + return '' + + out = '' + comment_txt = '' + if comment: + for doc in node.GetListOf('Comment'): + comment_txt += self.Comment(doc) + + func = declmap.get(node.cls) + if not func: + ErrOut.Log('Failed to define %s named %s' % (node.cls, node.GetName())) + + define_txt = func(self, node, prefix=prefix, comment=comment) + if comment_txt: + out += '%s%s' % (comment_txt, define_txt) + else: + out += define_txt + + tab = '' + for i in range(tabs): + tab += ' ' + + lines = [] + for line in out.split('\n'): + # Add indentation + line = '%s%s' % (tab, line) + if len(line) > 80: + left = line.rfind('(') + 1 + args = line[left:].split(',') + max = 0 + for arg in args: + if len(arg) > max: max = len(arg) + + if left + max >= 80: + space = '%s ' % tab + args = (',\n%s' % space).join([arg.strip() for arg in args]) + lines.append('%s\n%s%s' % (line[:left], space, args)) + else: + space = ' '.join(['' for i in range(left)]) + args = (',\n%s' % space).join(args) + lines.append('%s%s' % (line[:left], args)) + else: + lines.append(line.rstrip()) + + # out = tab + ('\n%s' % tab).join(out.split('\n')) + '\n' + self.LogExit('Exit Define') + return '\n'.join(lines) +# except: + if False: + node.Error('Failed to resolve.') + return '' # Clean a string representing an object definition and return then string # as a single space delimited set of tokens. @@ -259,15 +553,18 @@ def CleanString(instr): # Test a file, by comparing all it's objects, with their comments. def TestFile(filenode): - errors = 0 - for node in filenode.Children()[2:]: - if GetOption('verbose'): - node.Dump(0, comments=True) + cgen = CGen() + errors = 0 + for node in filenode.GetChildren()[2:]: instr = node.GetOneOf('Comment') - instr = CleanString(instr.name)[3:-3] + if not instr: continue + instr.Dump() + instr = CleanString(instr.GetName()) - outstr = Define(node) + outstr = cgen.Define(node) + if GetOption('verbose'): + print outstr + '\n' outstr = CleanString(outstr) if instr != outstr: @@ -277,7 +574,6 @@ def TestFile(filenode): return errors - # Build and resolve the AST and compare each file individual. def TestFiles(filenames): if not filenames: @@ -286,13 +582,14 @@ def TestFiles(filenames): filenames = glob.glob(idldir) filenames = sorted(filenames) - ast_result = ParseFiles(filenames) + ast = ParseFiles(filenames) total_errs = 0 - for filenode in ast_result.out.GetListOf('File'): + for filenode in ast.GetListOf('File'): errs = TestFile(filenode) if errs: - ErrOut.Log('%s test failed with %d error(s).' % (filenode.name, errs)) + ErrOut.Log('%s test failed with %d error(s).' % + (filenode.GetName(), errs)) total_errs += errs if total_errs: @@ -301,10 +598,19 @@ def TestFiles(filenames): InfoOut.Log('Passed generator test.') return total_errs - def Main(args): filenames = ParseOptions(args) - return TestFiles(filenames) + if GetOption('test'): + return TestFiles(filenames) + ast = ParseFiles(filenames) + for f in ast.GetListOf('File'): + if f.GetProperty('ERRORS') > 0: + print 'Skipping %s' % f.GetName() + continue + print DefineDepends(node) + for node in f.GetChildren()[2:]: + print Define(node, comment=True, prefix='tst_') + if __name__ == '__main__': sys.exit(Main(sys.argv[1:])) |