summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authornoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-19 00:08:54 +0000
committernoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-19 00:08:54 +0000
commit5eef288b86b805e5d0d18d9a83a1d5416655a330 (patch)
tree916643383d9e92abcd256d8d69f75efb4449d3a0 /ppapi
parentd33b2379837d0688b8011e7d48455bd9d2253fe4 (diff)
downloadchromium_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.py17
-rw-r--r--ppapi/generators/idl_c_header.py268
-rw-r--r--ppapi/generators/idl_c_proto.py794
-rw-r--r--ppapi/generators/idl_diff.py238
-rw-r--r--ppapi/generators/idl_namespace.py29
-rw-r--r--ppapi/generators/idl_node.py7
-rw-r--r--ppapi/generators/idl_option.py3
-rw-r--r--ppapi/generators/idl_outfile.py4
-rw-r--r--ppapi/generators/idl_parser.py17
-rw-r--r--ppapi/generators/test_cgen/enum_typedef.idl10
-rw-r--r--ppapi/generators/test_cgen/interface.idl13
-rw-r--r--ppapi/generators/test_cgen/structs.idl14
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;