diff options
author | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 00:08:54 +0000 |
---|---|---|
committer | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 00:08:54 +0000 |
commit | 5eef288b86b805e5d0d18d9a83a1d5416655a330 (patch) | |
tree | 916643383d9e92abcd256d8d69f75efb4449d3a0 /ppapi | |
parent | d33b2379837d0688b8011e7d48455bd9d2253fe4 (diff) | |
download | chromium_src-5eef288b86b805e5d0d18d9a83a1d5416655a330.zip chromium_src-5eef288b86b805e5d0d18d9a83a1d5416655a330.tar.gz chromium_src-5eef288b86b805e5d0d18d9a83a1d5416655a330.tar.bz2 |
Update the generator
Outstanding changes to the generator to:
Support hashing
Support versions
Clean up 'C' header generation
Update of 'C' header generation tests
Fix line wrapping
Pass error counts through to File objects
BUG= http://code.google.com/p/chromium/issues/detail?id=84272
TEST= python idl_c_header.py & gcl try
Generate the new headers, add them to a CL, and try
TBR= sehr@google.com
Review URL: http://codereview.chromium.org/7408002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92930 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/generators/idl_ast.py | 17 | ||||
-rw-r--r-- | ppapi/generators/idl_c_header.py | 268 | ||||
-rw-r--r-- | ppapi/generators/idl_c_proto.py | 794 | ||||
-rw-r--r-- | ppapi/generators/idl_diff.py | 238 | ||||
-rw-r--r-- | ppapi/generators/idl_namespace.py | 29 | ||||
-rw-r--r-- | ppapi/generators/idl_node.py | 7 | ||||
-rw-r--r-- | ppapi/generators/idl_option.py | 3 | ||||
-rw-r--r-- | ppapi/generators/idl_outfile.py | 4 | ||||
-rw-r--r-- | ppapi/generators/idl_parser.py | 17 | ||||
-rw-r--r-- | ppapi/generators/test_cgen/enum_typedef.idl | 10 | ||||
-rw-r--r-- | ppapi/generators/test_cgen/interface.idl | 13 | ||||
-rw-r--r-- | ppapi/generators/test_cgen/structs.idl | 14 |
12 files changed, 1069 insertions, 345 deletions
diff --git a/ppapi/generators/idl_ast.py b/ppapi/generators/idl_ast.py index 71aaf93..af06de3 100644 --- a/ppapi/generators/idl_ast.py +++ b/ppapi/generators/idl_ast.py @@ -109,12 +109,23 @@ class IDLAst(IDLNode): def __init__(self, children): objs = [] + builtin = None + extranodes = [] + for filenode in children: + if filenode.GetProperty('NAME') == 'pp_stdint.idl': + builtin = filenode + break + + if not builtin: + builtin = IDLFile('pp_stdint.idl', []) + extranodes = [builtin] + for name in BuiltIn: nameattr = IDLAttribute('NAME', name) - objs.append(IDLNode('Type', 'BuiltIn', 1, 0, [nameattr])) + typenode = IDLNode('Type', 'BuiltIn', 1, 0, [nameattr]) + builtin.AddChild(typenode) - builtin = IDLFile('pp_stdint.idl', objs) - IDLNode.__init__(self, 'AST', 'BuiltIn', 1, 0, [builtin] + children) + IDLNode.__init__(self, 'AST', 'BuiltIn', 1, 0, extranodes + children) self.SetProperty('LABEL', IDLVersionMapDefault()) self.Resolve() diff --git a/ppapi/generators/idl_c_header.py b/ppapi/generators/idl_c_header.py index 39ced4a..feef088 100644 --- a/ppapi/generators/idl_c_header.py +++ b/ppapi/generators/idl_c_header.py @@ -9,41 +9,261 @@ import glob import os import sys +import subprocess from idl_log import ErrOut, InfoOut, WarnOut -from idl_node import IDLAttribute, IDLAst, IDLNode +from idl_node import IDLAttribute, IDLNode +from idl_ast import IDLAst from idl_option import GetOption, Option, ParseOptions from idl_outfile import IDLOutFile from idl_parser import ParseFiles -from idl_c_proto import * +from idl_c_proto import CGen + +Option('dstroot', 'Base directory of output', default='../c') +Option('guard', 'Include guard prefix', default='ppapi/c') +Option('out', 'List of output files', default='') + +cgen = CGen() + +def IDLToHeader(filenode, relpath=None, prefix=None): + path, name = os.path.split(filenode.GetProperty('NAME')) + name = os.path.splitext(name)[0] + '.h' + if prefix: name = '%s%s' % (prefix, name) + if path: name = os.path.join(path, name) + if relpath: name = os.path.join(relpath, name) + return name + + +def GenerateHeader(filenode, pref, inline=True): + name = filenode.GetProperty('NAME') + if name == 'pp_stdint.idl': return + + # If we have an 'out' filter list, then check if we should output this file. + outlist = GetOption('out') + if outlist: + outlist = outlist.split(',') + if name not in outlist: + return + + savename = IDLToHeader(filenode, relpath=GetOption('dstroot'), prefix=pref) + out = IDLOutFile(savename) + + gpath = GetOption('guard') + def_guard = IDLToHeader(filenode, relpath=gpath, prefix=pref) + def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' + copyright = filenode.GetChildren()[0] + assert(copyright.IsA('Copyright')) + + fileinfo = filenode.GetChildren()[1] + assert(fileinfo.IsA('Comment')) + + out.Write('%s\n' % cgen.Copyright(copyright)) + out.Write('/* From %s modified %s. */\n\n'% ( + filenode.GetProperty('NAME'), filenode.GetProperty('DATETIME'))) + out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) + + for label in filenode.GetListOf('Label'): + if label.GetName() == GetOption('label'): + cgen.SetVersionMap(label) + + deps = filenode.GetDeps('M14') + # Generate set of includes + includes = set([]) + for dep in deps: + depfile = dep.GetProperty('FILE') + if depfile: + includes.add(depfile) + includes = [IDLToHeader(include, relpath=gpath) for include in includes] + includes.append('ppapi/c/pp_macros.h') + + # Assume we need stdint if we "include" C or C++ code + if filenode.GetListOf('Include'): + includes.append('ppapi/c/pp_stdint.h') + + includes = sorted(set(includes)) + cur_include = IDLToHeader(filenode, relpath=gpath) + for include in includes: + if include == cur_include: continue + out.Write('#include "%s"\n' % include) + + # Generate the @file comment + out.Write('\n%s\n' % cgen.Comment(fileinfo, prefix='*\n @file')) + + # Generate definitions. + last_group = None + for node in filenode.GetChildren()[2:]: + # If we are part of a group comment marker... + if last_group and last_group != node.cls: + pre = cgen.CommentLines(['*',' @}', '']) + '\n' + else: + pre = '\n' + + if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']: + if last_group != node.cls: + pre += cgen.CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', '']) + last_group = node.cls + else: + last_group = None + + if node.IsA('Comment'): + item = '%s\n\n' % cgen.Comment(node) + elif node.IsA('Inline'): + if not inline: continue + if node.GetName() == 'cc': + item = cgen.Define(node, prefix=pref, comment=True) + item = '#ifdef __cplusplus\n%s\n#endif // __cplusplus\n\n' % item + elif node.GetName() == 'c': + item = cgen.Define(node, prefix=pref, comment=True) + else: + continue + if not item: continue + else: + # + # Otherwise we are defining a file level object, so generate the + # correct document notation. + # + item = cgen.Define(node, prefix=pref, comment=True) + if not item: continue + asize = node.GetProperty('assert_size()') + if asize: + name = '%s%s' % (pref, node.GetName()) + if node.IsA('Struct'): + form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n' + else: + form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n' + item += form % (name, asize[0]) + + if item: out.Write('%s%s' % (pre, item)) + if last_group: + out.Write(cgen.CommentLines(['*',' @}', '']) + '\n') + + out.Write('#endif /* %s */\n\n' % def_guard) + out.Close() + + +def GenerateFileTest(cfile, filenode, pref): + tests = [] + original = IDLToHeader(filenode, relpath='') + savename = IDLToHeader(filenode, relpath='', prefix=pref) + cfile.Write('/* Test %s */\n' % filenode.GetProperty('NAME')) + cfile.Write('#include "%s"\n' % original) + cfile.Write('#include "%s"\n' % savename) + + # For all children (excluding copyright notice) + for node in filenode.children[1:]: + # Test enums by assigning all enum items to themselves. Unfortunately this + # will not catch cases where the '.h' has enums that the IDL does not. + if node.IsA('Enum'): + tests.append('test_%s' % node.GetProperty('NAME')) + cfile.Write('int test_%s() {\n' % node.GetProperty('NAME')) + cfile.Write(' int errors = 0;\n') + for enum in node.GetListOf('EnumItem'): + cfile.Write(' errors += VERIFY_ENUM(%s, %s%s);\n' % + (enum.GetProperty('NAME'), pref, enum.GetProperty('NAME'))) + cfile.Write(' if (errors) printf("Failure in %s:%s.\\n");\n' % + (filenode.GetName(), node.GetName())) + cfile.Write(' return errors;\n}\n\n') + continue + + # Use a structure asignment to verify equivilency + if node.IsA('Interface', 'Struct'): + tests.append('test_%s' % node.GetName()) + rtype1 = cgen.GetTypeName(node) + rtype2 = cgen.GetTypeName(node, prefix='tst_') + cfile.Write('int test_%s() {\n' % node.GetName()) + cfile.Write(' int errors = 0;\n'); + cmp_structs = ' %s A;\n %s B;\n' % (rtype1, rtype2) + cfile.Write(cmp_structs) + cfile.Write(' memset(&A, 0, sizeof(A));\n') + cfile.Write(' memset(&B, 1, sizeof(B));\n') + for member in node.GetListOf('Member', 'Function'): + if member.GetOneOf('Array'): + cfile.Write(' memcpy(A.%s, B.%s, sizeof(A.%s));\n' % + (member.GetName(), member.GetName(), member.GetName())) + else: + cfile.Write(' A.%s = B.%s;\n' % (member.GetName(), member.GetName())) + cfile.Write(' errors += (sizeof(A) != sizeof(B)) ? 1 : 0;\n') + cfile.Write(' errors += (memcmp(&A, &B, sizeof(A))) ? 1 : 0;\n') + cfile.Write(' return (sizeof(A) == sizeof(B));\n}\n') + continue + + cfile.Write('\n\n') + return tests + +def GenerateBaseTest(cfile): + for inc in ['<stdio.h>','<string.h>','"pp_stdint.h"']: + cfile.Write('#include %s\n' % inc) + cfile.Write('\n') + cfile.Write('#define VERIFY_ENUM(orig, idl) Check(#orig, orig, idl)\n\n') + cfile.Write('int Check(const char *name, int v1, int v2) {\n') + cfile.Write(' if (v1 == v2) return 0;\n') + cfile.Write(' printf("Mismatch enum %s : %d vs %d\\n", name, v1, v2);\n') + cfile.Write(' return 1;\n}\n\n') -Option('hdir', 'Output directory', default='hdir') def Main(args): filenames = ParseOptions(args) - ast_result = ParseFiles(filenames) - ast = ast_result.out + ast = ParseFiles(filenames) + testFuncs = [] + skipList = [] + + outdir = GetOption('dstroot') + + if GetOption('test'): + prefix = 'tst_' + cfile = IDLOutFile(os.path.join(outdir, 'test.c')) + GenerateBaseTest(cfile) + else: + prefix = '' + cfile = None - ast.Dump() for filenode in ast.GetListOf('File'): - savename = os.path.join(GetOption('hdir'), filenode.name) - out = IDLOutFile(savename) - - # Write the include guard, copyright, and file comment. - def_guard = filenode.name.replace('/','_').replace('.','_').upper() - out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard)) - out.Write('%s\n' % filenode.GetOneOf('Copyright').name) - for comment in filenode.GetListOf('Comment'): - out.Write('\n%s\n' % comment.name) - - # Generate definitions. - for node in filenode.childlist[2:]: - item = Define(node, prefix='tst_') - print '>>%s<<' % item - out.Write(item) - - out.Write('\n#endif /* %s */\n\n' % def_guard) - out.Close() + if GetOption('verbose'): + print "Working on %s" % filenode + + # If this file has errors, skip it + if filenode.GetProperty('ERRORS') > 0: + skipList.append(filenode) + continue + + GenerateHeader(filenode, prefix, inline=not cfile) + if cfile: GenerateFileTest(cfile, filenode, prefix) + + if cfile: + cfile.Write('int main(int argc, const char *args[]) {\n') + cfile.Write(' int errors = 0;\n'); + for testname in testFuncs: + cfile.Write(' errors += %s();\n' % testname) + + cfile.Write(' printf("Found %d error(s) in the IDL.\\n", errors);\n') + cfile.Write(' return errors;\n}\n\n') + cfile.Close() + + # TODO(noelallen) Add a standard test + if not skipList: + args = ['gcc', '-o', 'tester', '%s/test.c' % outdir, '-I%s' % outdir, + '-I../c', '-I../..', '-DPPAPI_INSTANCE_REMOVE_SCRIPTING'] + InfoOut.Log('Running: %s' % ' '.join(args)) + ret = subprocess.call(args) + if ret: + ErrOut.Log('Failed to compile.') + return -1 + InfoOut.Log('Running: ./tester') + ret = subprocess.call('./tester') + if ret > 0: + ErrOut.Log('Found %d errors.' % ret) + return ret + InfoOut.Log('Success!') + return 0 + + for filenode in skipList: + errcnt = filenode.GetProperty('ERRORS') + ErrOut.Log('%s : Skipped because of %d errors.' % ( + filenode.GetName(), errcnt)) + + if not skipList: + InfoOut.Log('Processed %d files.' % len(ast.GetListOf('File'))) + return len(skipList) if __name__ == '__main__': sys.exit(Main(sys.argv[1:])) 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:])) diff --git a/ppapi/generators/idl_diff.py b/ppapi/generators/idl_diff.py index d005a20..9d1abbb 100644 --- a/ppapi/generators/idl_diff.py +++ b/ppapi/generators/idl_diff.py @@ -10,7 +10,7 @@ import subprocess import sys from idl_option import GetOption, Option, ParseOptions - +from idl_outfile import IDLOutFile # # IDLDiff # @@ -23,16 +23,18 @@ from idl_option import GetOption, Option, ParseOptions Option('gen', 'IDL generated files', default='hdir') Option('src', 'Original ".h" files', default='../c') - +Option('halt', 'Stop if a difference is found') +Option('diff', 'Directory holding acceptable diffs', default='diff') +Option('ok', 'Write out the diff file.') # Change # # A Change object contains the previous lines, new news and change type. # class Change(object): - def __init__(self, change): - self.mode = str(change['mode']) - self.was = list(change['was']) - self.now = list(change['now']) + def __init__(self, mode, was, now): + self.mode = mode + self.was = was + self.now = now def Dump(self): if not self.was: @@ -43,9 +45,9 @@ class Change(object): print 'Modifying %s' % self.mode for line in self.was: - print 'src: %s' % line + print 'src: >>%s<<' % line for line in self.now: - print 'gen: %s' % line + print 'gen: >>%s<<' % line print # @@ -55,9 +57,20 @@ class Change(object): # such as non-matching years. # def IsCopyright(change): - if len(change['now']) != 1 or len(change['was']) != 1: return False - if 'Copyright (c)' not in change['now'][0]: return False - if 'Copyright (c)' not in change['was'][0]: return False + if len(change.now) != 1 or len(change.was) != 1: return False + if 'Copyright (c)' not in change.now[0]: return False + if 'Copyright (c)' not in change.was[0]: return False + return True + +# +# IsBlankComment +# +# Return True if this change only removes a blank line from a comment +# +def IsBlankComment(change): + if change.now: return False + if len(change.was) != 1: return False + if change.was[0].strip() != '*': return False return True # @@ -66,14 +79,46 @@ def IsCopyright(change): # Return True if this change only adds or removes blank lines # def IsBlank(change): - for line in change['now']: + for line in change.now: if line: return False - for line in change['was']: + for line in change.was: if line: return False return True # +# IsCppComment +# +# Return True if this change only going from C++ to C style +# +def IsToCppComment(change): + if not len(change.now) or len(change.now) != len(change.was): + return False + for index in range(len(change.now)): + was = change.was[index].strip() + if was[:2] != '//': + return False + was = was[2:].strip() + now = change.now[index].strip() + if now[:2] != '/*': + return False + now = now[2:-2].strip() + if now != was: + return False + return True + + + return True + +def IsMergeComment(change): + if len(change.was) != 1: return False + if change.was[0].strip() != '*': return False + for line in change.now: + stripped = line.strip() + if stripped != '*' and stripped[:2] != '/*' and stripped[-2:] != '*/': + return False + return True +# # IsSpacing # # Return True if this change is only different in the way 'words' are spaced @@ -85,17 +130,17 @@ def IsBlank(change): # ENUM_XYY_Y = 2, # def IsSpacing(change): - if len(change['now']) != len(change['was']): return False - for i in range(len(change['now'])): + if len(change.now) != len(change.was): return False + for i in range(len(change.now)): # Also ignore right side comments - line = change['was'][i] + line = change.was[i] offs = line.find('//') if offs == -1: offs = line.find('/*') if offs >-1: line = line[:offs-1] - words1 = change['now'][i].split() + words1 = change.now[i].split() words2 = line.split() if words1 != words2: return False return True @@ -106,8 +151,9 @@ def IsSpacing(change): # Return True if change has extra includes # def IsInclude(change): - if len(change['was']): return False - for line in change['now']: + for line in change.was: + if line.strip().find('struct'): return False + for line in change.now: if line and '#include' not in line: return False return True @@ -117,8 +163,8 @@ def IsInclude(change): # Return True if the change is only missing C++ comments # def IsCppComment(change): - if len(change['now']): return False - for line in change['was']: + if len(change.now): return False + for line in change.was: line = line.strip() if line[:2] != '//': return False return True @@ -128,7 +174,10 @@ def IsCppComment(change): # Return True if none of the changes does not patch an above "bogus" change. # def ValidChange(change): + if IsToCppComment(change): return False if IsCopyright(change): return False + if IsBlankComment(change): return False + if IsMergeComment(change): return False if IsBlank(change): return False if IsSpacing(change): return False if IsInclude(change): return False @@ -136,55 +185,170 @@ def ValidChange(change): return True +# +# Swapped +# +# Check if the combination of last + next change signals they are both +# invalid such as swap of line around an invalid block. +# +def Swapped(last, next): + if not last.now and not next.was and len(last.was) == len(next.now): + cnt = len(last.was) + for i in range(cnt): + match = True + for j in range(cnt): + if last.was[j] != next.now[(i + j) % cnt]: + match = False + break; + if match: return True + if not last.was and not next.now and len(last.now) == len(next.was): + cnt = len(last.now) + for i in range(cnt): + match = True + for j in range(cnt): + if last.now[i] != next.was[(i + j) % cnt]: + match = False + break; + if match: return True + return False + + +def FilterLinesIn(output): + was = [] + now = [] + filter = [] + for index in range(len(output)): + filter.append(False) + line = output[index] + if len(line) < 2: continue + if line[0] == '<': + if line[2:].strip() == '': continue + was.append((index, line[2:])) + elif line[0] == '>': + if line[2:].strip() == '': continue + now.append((index, line[2:])) + for windex, wline in was: + for nindex, nline in now: + if filter[nindex]: continue + if filter[windex]: continue + if wline == nline: + filter[nindex] = True + filter[windex] = True + if GetOption('verbose'): + print "Found %d, %d >>%s<<" % (windex + 1, nindex + 1, wline) + out = [] + for index in range(len(output)): + if not filter[index]: + out.append(output[index]) + return out # # GetChanges # # Parse the output into discrete change blocks. # def GetChanges(output): + # Split on lines, adding an END marker to simply add logic lines = output.split('\n') + lines = FilterLinesIn(lines) + lines.append('END') + changes = [] - change = { 'mode' : None, - 'was': [], - 'now': [] - } + was = [] + now = [] + mode = '' + last = None + for line in lines: +# print "LINE=%s" % line if not line: continue + elif line[0] == '<': - change['was'].append(line[2:]) + if line[2:].strip() == '': continue + # Ignore prototypes + if len(line) > 10: + words = line[2:].split() + if len(words) == 2 and words[1][-1] == ';': + if words[0] == 'struct' or words[0] == 'union': + continue + was.append(line[2:]) elif line[0] == '>': - change['now'].append(line[2:]) + if line[2:].strip() == '': continue + if line[2:10] == '#include': continue + now.append(line[2:]) elif line[0] == '-': continue else: - if ValidChange(change): changes.append(Change(change)) - change['mode'] = line - change['now'] = [] - change['was'] = [] - if ValidChange(change): changes.append(Change(change)) - return changes + change = Change(line, was, now) + was = [] + now = [] + if ValidChange(change): + changes.append(change) + if line == 'END': + break + + return FilterChanges(changes) + +def FilterChanges(changes): + if len(changes) < 2: return changes + out = [] + filter = [False for change in changes] + for cur in range(len(changes)): + for cmp in range(cur+1, len(changes)): + if filter[cmp]: + continue + if Swapped(changes[cur], changes[cmp]): + filter[cur] = True + filter[cmp] = True + for cur in range(len(changes)): + if filter[cur]: continue + out.append(changes[cur]) + return out def Main(args): filenames = ParseOptions(args) if not filenames: gendir = os.path.join(GetOption('gen'), '*.h') - filenames = glob.glob(gendir) + filenames = sorted(glob.glob(gendir)) + srcdir = os.path.join(GetOption('src'), '*.h') + srcs = sorted(glob.glob(srcdir)) + for name in srcs: + name = os.path.split(name)[1] + name = os.path.join(GetOption('gen'), name) + if name not in filenames: + print 'Missing: %s' % name for filename in filenames: gen = filename filename = filename[len(GetOption('gen')) + 1:] src = os.path.join(GetOption('src'), filename) + diff = os.path.join(GetOption('diff'), filename) p = subprocess.Popen(['diff', src, gen], stdout=subprocess.PIPE) output, errors = p.communicate() - changes = GetChanges(output) + try: + input = open(diff, 'rt').read() + except: + input = '' + + if input != output: + changes = GetChanges(output) + else: + changes = [] + if changes: print "\n\nDelta between:\n src=%s\n gen=%s\n" % (src, gen) - for change in GetChanges(output): + for change in changes: change.Dump() + print 'Done with %s\n\n' % src + if GetOption('ok'): + open(diff, 'wt').write(output) + if GetOption('halt'): + return 1 else: - print "\nSAME:\n src=%s\n gen=%s\n" % (src, gen) + print "\nSAME:\n src=%s\n gen=%s" % (src, gen) + if input: print ' ** Matched expected diff. **' + print '\n' if __name__ == '__main__': sys.exit(Main(sys.argv[1:])) diff --git a/ppapi/generators/idl_namespace.py b/ppapi/generators/idl_namespace.py index dbe6d11..b20e4f2 100644 --- a/ppapi/generators/idl_namespace.py +++ b/ppapi/generators/idl_namespace.py @@ -63,9 +63,9 @@ class IDLVersionList(object): # We should only be missing a 'version' tag for the first item. if not node.vmin: + raise RuntimeError('Missing version') node.Error('Missing version on overload of previous %s.' % cver.Location()) - raise RuntimeError('DSFSD') return False # If the node has no max, then set it to this one @@ -142,36 +142,36 @@ class IDLNamespace(object): InfoOut.Log('') def FindVersion(self, name, version): - list = self.namespace.get(name, None) - if list == None: + verlist = self.namespace.get(name, None) + if verlist == None: if self.parent: return self.parent.FindVersion(name, version) else: return None - return list.FindVersion(version) + return verlist.FindVersion(version) def FindRange(self, name, vmin, vmax): - list = self.namespace.get(name, None) - if list == None: + verlist = self.namespace.get(name, None) + if verlist == None: if self.parent: return self.parent.FindRange(name, vmin, vmax) else: return [] - return list.FindRange(vmin, vmax) + return verlist.FindRange(vmin, vmax) def FindList(self, name): - list = self.namespace.get(name, None) - if list == None: + verlist = self.namespace.get(name, None) + if verlist == None: if self.parent: return self.parent.FindList(name) - return list + return verlist def AddNode(self, node): name = node.GetName() - list = self.namespace.setdefault(name,IDLVersionList()) + verlist = self.namespace.setdefault(name,IDLVersionList()) if GetOption('namespace_debug'): print "Adding to namespace: %s" % node - return list.AddNode(node) + return verlist.AddNode(node) @@ -303,6 +303,7 @@ def Main(args): Bar23 = MockNode('bar', 2.0, 3.0) Bar34 = MockNode('bar', 3.0, 4.0) + # Verify we succeed with fully qualified versions namespace = IDLNamespace(namespace) AddOkay(namespace, BarXX) @@ -333,7 +334,9 @@ def Main(args): VerifyFindAll(namespace, 'foo', 0.0, 3.0, [FooXX, Foo1X]) VerifyFindAll(namespace, 'foo', 3.0, 100.0, [Foo3X]) - + FooBar = MockNode('foobar', 1.0, 2.0) + namespace = IDLNamespace(namespace) + AddOkay(namespace, FooBar) if errors: print 'Test failed with %d errors.' % errors diff --git a/ppapi/generators/idl_node.py b/ppapi/generators/idl_node.py index 285307a..0c8c180 100644 --- a/ppapi/generators/idl_node.py +++ b/ppapi/generators/idl_node.py @@ -81,8 +81,7 @@ class IDLNode(IDLVersion): if child.cls == 'ExtAttribute': self.SetProperty(child.name, child.value) else: - child.SetParent(self) - self.children.append(child) + self.AddChild(child) # # String related functions @@ -171,6 +170,10 @@ class IDLNode(IDLVersion): self.property_node.AddParent(parent) self.parent = parent + def AddChild(self, node): + node.SetParent(self) + self.children.append(node) + # Get a list of all children def GetChildren(self): return self.children diff --git a/ppapi/generators/idl_option.py b/ppapi/generators/idl_option.py index 9b87d42..5d75c28 100644 --- a/ppapi/generators/idl_option.py +++ b/ppapi/generators/idl_option.py @@ -55,7 +55,7 @@ def DumpOption(option): else: out = ' -%-15.15s\t%s' % (option.name, option.desc) if option.default: - out = ' %-15.15s\t%s\n\t\tDefault: %s\n' % (' ', out, option.default) + out = '%s\n\t\t\t(Default: %s)\n' % (out, option.default) InfoOut.Log(out) def DumpHelp(option=None): @@ -107,3 +107,4 @@ def ParseOptions(args): sys.exit(-1) return filenames + diff --git a/ppapi/generators/idl_outfile.py b/ppapi/generators/idl_outfile.py index e25c3ca..fd00c18 100644 --- a/ppapi/generators/idl_outfile.py +++ b/ppapi/generators/idl_outfile.py @@ -11,6 +11,7 @@ import time import sys from idl_log import ErrOut, InfoOut, WarnOut +from idl_option import GetOption, Option, ParseOptions from stat import * # @@ -51,7 +52,8 @@ class IDLOutFile(object): intext = None if intext == outtext: - InfoOut.Log('Output %s unchanged.' % self.filename) + if GetOption('verbose'): + InfoOut.Log('Output %s unchanged.' % self.filename) return False try: diff --git a/ppapi/generators/idl_parser.py b/ppapi/generators/idl_parser.py index 0ee2200..a8a8ef2 100644 --- a/ppapi/generators/idl_parser.py +++ b/ppapi/generators/idl_parser.py @@ -28,6 +28,7 @@ import glob import os.path import re import sys +import time from idl_ast import IDLAst from idl_log import ErrOut, InfoOut, WarnOut @@ -42,7 +43,7 @@ Option('build_debug', 'Debug tree building.') Option('parse_debug', 'Debug parse reduction steps.') Option('token_debug', 'Debug token generation.') Option('dump_tree', 'Dump the tree.') -Option('srcroot', 'Working directory.', default='') +Option('srcroot', 'Working directory.', default='../api') Option('wcomment', 'Disable warning for missing comment.') Option('wenum', 'Disable warning for missing enum value.') @@ -814,6 +815,7 @@ class IDLParser(IDLLexer): # Loads a new file into the lexer and attemps to parse it. # def ParseFile(self, filename): + date = time.ctime(os.path.getmtime(filename)) data = open(filename).read() if self.verbose: InfoOut.Log("Parsing %s" % filename) @@ -824,7 +826,9 @@ class IDLParser(IDLLexer): srcroot = GetOption('srcroot') if srcroot and filename.find(srcroot) == 0: filename = filename[len(srcroot) + 1:] - return IDLFile(filename, out, self.parse_errors + self.lex_errors) + filenode = IDLFile(filename, out, self.parse_errors + self.lex_errors) + filenode.SetProperty('DATETIME', date) + return filenode except Exception as e: ErrOut.LogLine(filename, self.last.lineno, self.last.lexpos, @@ -986,12 +990,19 @@ def TestNamespaceFiles(filter): InfoOut.Log("Passed namespace test.") return errs - +default_dirs = ['.', 'trusted'] def ParseFiles(filenames): parser = IDLParser() filenodes = [] errors = 0 + if not filenames: + filenames = [] + srcroot = GetOption('srcroot') + for dir in default_dirs: + srcdir = os.path.join(srcroot, dir, '*.idl') + filenames += sorted(glob.glob(gendir)) + for filename in filenames: filenode = parser.ParseFile(filename) filenodes.append(filenode) diff --git a/ppapi/generators/test_cgen/enum_typedef.idl b/ppapi/generators/test_cgen/enum_typedef.idl index cb47402..45f1472 100644 --- a/ppapi/generators/test_cgen/enum_typedef.idl +++ b/ppapi/generators/test_cgen/enum_typedef.idl @@ -6,7 +6,7 @@ /* This file will test that the IDL snippet matches the comment */ -/* enum et1 { A = 1, B = 2, C = 3 }; */ +/* typedef enum { A = 1, B = 2, C = 3 } et1; */ enum et1 { A=1, B=2, C=3 }; /* typedef int32_t i; */ @@ -25,10 +25,10 @@ typedef int32_t i_func_i([in] int32_t i); typedef et1[4] et4; /* -typedef int8_t (*PPB_Audio_Callback)(const void* sample_buffer, - uint32_t buffer_size_in_bytes, - const void* user_data); -*/ + * typedef int8_t (*PPB_Audio_Callback)(const void* sample_buffer, + * uint32_t buffer_size_in_bytes, + * const void* user_data); + */ typedef int8_t PPB_Audio_Callback([in] mem_t sample_buffer, [in] uint32_t buffer_size_in_bytes, [in] mem_t user_data); diff --git a/ppapi/generators/test_cgen/interface.idl b/ppapi/generators/test_cgen/interface.idl index 5eec136..0992614 100644 --- a/ppapi/generators/test_cgen/interface.idl +++ b/ppapi/generators/test_cgen/interface.idl @@ -11,12 +11,13 @@ struct ist { mem_t X; }; -/* struct iface1 { - int8_t (*mem1)(int16_t x, int32_t y); - int32_t (*mem2)(const struct ist* a); - int32_t (*mem3)(struct ist* b); - -}; */ +/* + * struct iface1 { + * int8_t (*mem1)(int16_t x, int32_t y); + * int32_t (*mem2)(const struct ist* a); + * int32_t (*mem3)(struct ist* b); + * }; + */ interface iface1 { int8_t mem1([in] int16_t x, [in] int32_t y); int32_t mem2([in] ist a); diff --git a/ppapi/generators/test_cgen/structs.idl b/ppapi/generators/test_cgen/structs.idl index 486473c..e942f05 100644 --- a/ppapi/generators/test_cgen/structs.idl +++ b/ppapi/generators/test_cgen/structs.idl @@ -9,7 +9,7 @@ /* typedef uint8_t s_array[3]; */ typedef uint8_t[3] s_array; -/* enum senum { esv1 = 1, esv2 = 2 }; */ +/* typedef enum { esv1 = 1, esv2 = 2 } senum; */ enum senum { esv1=1, esv2=2 @@ -26,16 +26,18 @@ struct st2 { s_array[640][480] pixels; }; -/* typedef float (*func_t)(s_array data); */ +/* typedef float (*func_t)(const s_array data); */ typedef float_t func_t([in] s_array data); /* typedef func_t (*findfunc_t)(const char* x); */ typedef func_t findfunc_t([in] str_t x); -/* struct sfoo { - s_array screen[480][640]; - findfunc_t myfunc; -}; */ +/* + * struct sfoo { + * s_array screen[480][640]; + * findfunc_t myfunc; + * }; + */ struct sfoo { s_array[480][640] screen; findfunc_t myfunc; |