diff options
author | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-24 23:03:06 +0000 |
---|---|---|
committer | noelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-24 23:03:06 +0000 |
commit | f7314730aae52985ecc4a723289b6a7eade82cd1 (patch) | |
tree | 72a6a3c7f155a66527ee8a455b3bae919a384ec1 /ppapi/generators | |
parent | d995780c28c131a0ea30daa4d2e991746312cc19 (diff) | |
download | chromium_src-f7314730aae52985ecc4a723289b6a7eade82cd1.zip chromium_src-f7314730aae52985ecc4a723289b6a7eade82cd1.tar.gz chromium_src-f7314730aae52985ecc4a723289b6a7eade82cd1.tar.bz2 |
More multi-version support
Minor fix to idl_output: switch from None to '' to alow split to work
Add 'InReleases' member to verify node is valid within a list of releases.
Add 'releases' member to IDLVersionMap class for easier search.
Remove stale code and build ordered list of requested releases in AST
Remove release member from CGen object, and pass into functions
Move release tracking from C prototype to C header generator
Update generator tests.
Added golden files to verify the C generator is correct
NOTE: This is work in progress. The header emitted using
--release=X should be correct and has been tested to generate
exactly what we have today, however --range=X,Y does not yet
generate what we need.
BUG= http://code.google.com/p/chromium/issues/detail?id=89969
TEST= python generator.py
Review URL: http://codereview.chromium.org/7715036
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98133 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/generators')
-rw-r--r-- | ppapi/generators/idl_ast.py | 25 | ||||
-rw-r--r-- | ppapi/generators/idl_c_header.py | 300 | ||||
-rw-r--r-- | ppapi/generators/idl_c_proto.py | 314 | ||||
-rw-r--r-- | ppapi/generators/idl_generator.py | 72 | ||||
-rw-r--r-- | ppapi/generators/idl_namespace.py | 2 | ||||
-rw-r--r-- | ppapi/generators/idl_node.py | 5 | ||||
-rw-r--r-- | ppapi/generators/idl_outfile.py | 2 | ||||
-rw-r--r-- | ppapi/generators/test_cgen/enum_typedef.idl | 4 | ||||
-rw-r--r-- | ppapi/generators/test_cgen/interface.idl | 4 | ||||
-rw-r--r-- | ppapi/generators/test_cgen/structs.idl | 4 | ||||
-rw-r--r-- | ppapi/generators/test_cgen_range/versions.h | 42 | ||||
-rw-r--r-- | ppapi/generators/test_cgen_range/versions.idl | 36 |
12 files changed, 460 insertions, 350 deletions
diff --git a/ppapi/generators/idl_ast.py b/ppapi/generators/idl_ast.py index 57105b7..95eae32 100644 --- a/ppapi/generators/idl_ast.py +++ b/ppapi/generators/idl_ast.py @@ -78,7 +78,6 @@ class IDLFileTypeResolver(IDLVisitor): if node.IsA('File'): node.SetProperty('FILE', node) - # If this node has a TYPEREF, resolve it to a version list typeref = node.property_node.GetPropertyLocal('TYPEREF') if typeref: @@ -90,6 +89,14 @@ class IDLFileTypeResolver(IDLVisitor): return filenode +class IDLReleaseResolver(IDLVisitor): + def VisitFilter(self, node, data): + return node.IsA('AST','File', 'Label') + + def Depart(self, node, data, childdata): + if node.IsA('Label'): + return set([child.name for child in GetListOf('LabelItem')]) + return childdata class IDLVersionMapDefault(IDLVersionMap): def GetRelease(self, version): @@ -116,15 +123,6 @@ class IDLAst(IDLNode): builtin = filenode break -# if not builtin: -# builtin = IDLFile('pp_stdint.idl', []) -# extranodes = [builtin] - -# for name in BuiltIn: -# nameattr = IDLAttribute('NAME', name) -# typenode = IDLNode('Type', 'BuiltIn', 1, 0, [nameattr]) -# builtin.AddChild(typenode) - IDLNode.__init__(self, 'AST', 'BuiltIn', 1, 0, extranodes + children) self.SetProperty('LABEL', IDLVersionMapDefault()) self.Resolve() @@ -135,6 +133,13 @@ class IDLAst(IDLNode): IDLNamespaceLabelResolver().Visit(self, self.namespace) IDLFileTypeResolver().Visit(self, None) + # Build an ordered list of all releases + self.releases = set() + for filenode in self.GetListOf('File'): + vmap = filenode.GetProperty('LABEL') + self.releases |= set(vmap.releases) + self.releases = sorted(self.releases) + def SetTypeInfo(self, name, properties): node = self.namespace[name] for prop in properties: diff --git a/ppapi/generators/idl_c_header.py b/ppapi/generators/idl_c_header.py index 46ca82a..edec95f 100644 --- a/ppapi/generators/idl_c_header.py +++ b/ppapi/generators/idl_c_header.py @@ -17,16 +17,14 @@ 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 CGen -from idl_generator import Generator +from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment +from idl_generator import Generator, GeneratorByFile 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): +def GetOutFileName(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) @@ -34,168 +32,198 @@ def IDLToHeader(filenode, relpath=None, prefix=None): if relpath: name = os.path.join(relpath, name) return name +def WriteGroupMarker(out, node, last_group): + # If we are part of a group comment marker... + if last_group and last_group != node.cls: + pre = CommentLines(['*',' @}', '']) + '\n' + else: + pre = '\n' -def GenerateHeader(filenode, release, 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 + if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']: + if last_group != node.cls: + pre += CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', '']) + last_group = node.cls + else: + last_group = None + out.Write(pre) + return last_group - savename = IDLToHeader(filenode, relpath=GetOption('dstroot'), prefix=pref) - out = IDLOutFile(savename) +def GenerateHeader(out, filenode, releases): gpath = GetOption('guard') - def_guard = IDLToHeader(filenode, relpath=gpath, prefix=pref) - def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' - cright_node = filenode.GetChildren()[0] - assert(cright_node.IsA('Copyright')) - - fileinfo = filenode.GetChildren()[1] - assert(fileinfo.IsA('Comment')) - - out.Write('%s\n' % cgen.Copyright(cright_node)) - 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(release) - # 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 all interface defines - out.Write('\n') - for node in filenode.GetListOf('Interface'): - out.Write( cgen.InterfaceDefs(node) ) - - # Generate the @file comment - out.Write('%s\n' % cgen.Comment(fileinfo, prefix='*\n @file')) + cgen = CGen() + pref = '' + do_comments = True # 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 + top_types = ['Typedef', 'Interface', 'Struct', 'Enum', 'Inline'] + for node in filenode.GetListOf(*top_types): + # Skip if this node is not in this release + if not node.InReleases(releases): + print "Skiping %s" % node + continue + + # End/Start group marker + if do_comments: + last_group = WriteGroupMarker(out, node, last_group) + + if node.IsA('Inline'): + item = node.GetProperty('VALUE') + # If 'C++' use __cplusplus wrapper 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: + # If not C++ or C, then skip it + elif not node.GetName() == 'c': 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 item: out.Write(item) + continue + + # + # Otherwise we are defining a file level object, so generate the + # correct document notation. + # + item = cgen.Define(node, releases, 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(item) if last_group: - out.Write(cgen.CommentLines(['*',' @}', '']) + '\n') + out.Write(CommentLines(['*',' @}', '']) + '\n') - out.Write('#endif /* %s */\n\n' % def_guard) - return out.Close() -class HGen(Generator): +class HGen(GeneratorByFile): def __init__(self): Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.') - def GenerateVersion(self, ast, release, options): - outdir = GetOption('dstroot') - skipList= [] - prefix = '' - cfile = None - cnt = 0 - - for filenode in ast.GetListOf('File'): - if GetOption('verbose'): - print "Working on %s" % filenode - - # If this file has errors, skip it - if filenode.GetProperty('ERRORS') > 0: - skipList.append(filenode) - continue - - if GenerateHeader(filenode, release, prefix): - cnt = cnt + 1 - - for filenode in skipList: - errcnt = filenode.GetProperty('ERRORS') - ErrOut.Log('%s : Skipped because of %d errors.' % ( - filenode.GetName(), errcnt)) - - if skipList: - return -len(skipList) - - if GetOption('diff'): - return -cnt - return cnt + 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 + + + def GetOutFile(self, filenode, options): + savename = GetOutFileName(filenode, GetOption('dstroot')) + return IDLOutFile(savename) + + def GenerateHead(self, out, filenode, releases, options): + cgen = CGen() + gpath = GetOption('guard') + release = releases[0] + def_guard = GetOutFileName(filenode, relpath=gpath) + def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' + + cright_node = filenode.GetChildren()[0] + assert(cright_node.IsA('Copyright')) + fileinfo = filenode.GetChildren()[1] + assert(fileinfo.IsA('Comment')) + + out.Write('%s\n' % cgen.Copyright(cright_node)) + 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)) + # Generate set of includes + + deps = set() + for release in releases: + deps |= filenode.GetDeps(release) + + includes = set([]) + for dep in deps: + depfile = dep.GetProperty('FILE') + if depfile: + includes.add(depfile) + includes = [GetOutFileName(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 = GetOutFileName(filenode, relpath=gpath) + for include in includes: + if include == cur_include: continue + out.Write('#include "%s"\n' % include) + + # Generate all interface defines + out.Write('\n') + for node in filenode.GetListOf('Interface'): + idefs = '' + 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('.', '_') + idefs += self.GetDefine('%s_%s' % (macro, strver), + '"%s;%s"' % (name, vers)) + if label.GetRelease(vers) == releases[-1]: + idefs += self.GetDefine(macro, '%s_%s' % (macro, strver)) + idefs += '\n' + out.Write(idefs) + + # Generate the @file comment + out.Write('%s\n' % Comment(fileinfo, prefix='*\n @file')) + + def GenerateBody(self, out, filenode, releases, options): + GenerateHeader(out, filenode, releases) + + def GenerateTail(self, out, filenode, releases, options): + gpath = GetOption('guard') + def_guard = GetOutFileName(filenode, relpath=gpath) + def_guard = def_guard.replace('/','_').replace('.','_').upper() + '_' + out.Write('#endif /* %s */\n\n' % def_guard) hgen = HGen() def Main(args): # Default invocation will verify the golden files are unchanged. + failed = 0 if not args: args = ['--wnone', '--diff', '--test', '--dstroot=.'] ParseOptions(args) + idldir = os.path.split(sys.argv[0])[0] idldir = os.path.join(idldir, 'test_cgen', '*.idl') filenames = glob.glob(idldir) + ast = ParseFiles(filenames) + if hgen.GenerateRelease(ast, 'M14', {}): + print "Golden file for M14 failed." + failed = 1 + else: + print "Golden file for M14 passed." + + + idldir = os.path.split(sys.argv[0])[0] + idldir = os.path.join(idldir, 'test_cgen_range', '*.idl') + filenames = glob.glob(idldir) ast = ParseFiles(filenames) - return hgen.GenerateVersion(ast, 'M14', {}) + if hgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}): + print "Golden file for M13-M15 failed." + failed =1 + else: + print "Golden file for M13-M15 passed." + + return failed if __name__ == '__main__': retval = Main(sys.argv[1:]) diff --git a/ppapi/generators/idl_c_proto.py b/ppapi/generators/idl_c_proto.py index a116e36..05937e4 100644 --- a/ppapi/generators/idl_c_proto.py +++ b/ppapi/generators/idl_c_proto.py @@ -26,6 +26,47 @@ class CGenError(Exception): return repr(self.value) +def CommentLines(lines, tabs=0): + # Generate a C style comment block by prepending the block with '<tab>/*' + # and adding a '<tab> *' per line. + tab = ' ' * tabs + + out = '%s/*' % tab + ('\n%s *' % tab).join(lines) + + # Add a terminating ' */' unless the last line is blank which would mean it + # already has ' *' + if not lines[-1]: + out += '/\n' + else: + out += ' */\n' + return out + +def Comment(node, prefix=None, tabs=0): + # Generate a comment block from the provided Comment node. + comment = node.GetName() + lines = comment.split('\n') + + # If an option prefix is provided, then prepend that to the comment + # for this node. + if prefix: + prefix_lines = prefix.split('\n') + # If both the prefix and comment start with a blank line ('*') remove + # the extra one. + if prefix_lines[0] == '*' and lines[0] == '*': + lines = prefix_lines + lines[1:] + else: + lines = prefix_lines + lines; + return CommentLines(lines, tabs) + +def GetNodeComments(node, prefix=None, tabs=0): + # Generate a comment block joining all comment nodes which are children of + # the provided node. + comment_txt = '' + for doc in node.GetListOf('Comment'): + comment_txt += Comment(doc, tabs=tabs) + return comment_txt + + class CGen(object): # TypeMap # @@ -103,17 +144,6 @@ class CGen(object): def __init__(self): self.dbg_depth = 0 - self.vmin = 0.0 - self.vmax = 1e100 - self.release = GetOption('release') - - def SetVersionMap(self, node): - self.vmin = 0.0 - self.vmax = 1e100 - for version in node.GetListOf('LabelItem'): - if version.GetName() == GetOption('release'): - self.vmin = float(version.GetProperty('VALUE')) - self.vmax = float(version.GetProperty('VALUE')) # # Debug Logging functions @@ -152,12 +182,13 @@ class CGen(object): # # For a given node return the type name by passing mode. # - def GetTypeName(self, node, prefix=''): - self.LogEnter('GetTypeName of %s' % node) + def GetTypeName(self, node, release, prefix=''): + self.LogEnter('GetTypeName of %s rel=%s' % (node, release)) - # For Members, Params, and Typedef's your want type it refers to + # For Members, Params, and Typedefs get the type it refers to otherwise + # the node in question is it's own type (struct, union etc...) if node.IsA('Member', 'Param', 'Typedef'): - typeref = node.GetType(self.release) + typeref = node.GetType(release) else: typeref = node @@ -194,19 +225,20 @@ class CGen(object): # For a given node return basic type of that object. This is # either a 'Type', 'Callspec', or 'Array' # - def GetRootTypeMode(self, node, mode): + def GetRootTypeMode(self, node, release, 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), + rootType, mode = self.GetRootTypeMode(node.GetType(release), 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) + rootType, mode = self.GetRootTypeMode(node.GetType(release), + release, mode) # If it's an Enum, then it's normal passing rules elif node.IsA('Enum'): @@ -237,10 +269,11 @@ class CGen(object): return rootType, mode - def GetTypeByMode(self, node, mode): - self.LogEnter('GetTypeByMode of %s mode=%s' % (node, mode)) - name = self.GetTypeName(node) - ntype, mode = self.GetRootTypeMode(node, mode) + def GetTypeByMode(self, node, release, mode): + self.LogEnter('GetTypeByMode of %s mode=%s release=%s' % + (node, mode, release)) + name = self.GetTypeName(node, release) + ntype, mode = self.GetRootTypeMode(node, release, mode) out = CGen.TypeMap[ntype][mode] % name self.LogExit('GetTypeByMode %s = %s' % (node, out)) return out @@ -264,15 +297,15 @@ class CGen(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)) + def GetComponents(self, node, release, mode): + self.LogEnter('GetComponents mode %s for %s %s' % (mode, node, release)) # Generate passing type by modifying root type - rtype = self.GetTypeByMode(node, mode) + rtype = self.GetTypeByMode(node, release, mode) if node.IsA('Enum', 'Interface', 'Struct'): rname = node.GetName() else: - rname = node.GetType(self.release).GetName() + rname = node.GetType(release).GetName() if rname in CGen.RemapName: rname = CGen.RemapName[rname] @@ -285,7 +318,7 @@ class CGen(object): callspec = [] for param in callnode.GetListOf('Param'): mode = self.GetParamMode(param) - ptype, pname, parray, pspec = self.GetComponents(param, mode) + ptype, pname, parray, pspec = self.GetComponents(param, release, mode) callspec.append((ptype, pname, parray, pspec)) else: callspec = None @@ -317,32 +350,23 @@ class CGen(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): + def GetSignature(self, node, release, 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) + rtype, name, arrayspec, callspec = self.GetComponents(node, release, 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) + # Define a Typedef. + def DefineTypedef(self, node, releases, prefix='', comment=False): + release = releases[0] + out = 'typedef %s;\n' % self.GetSignature(node, release, 'return', + prefix, True) self.Log('DefineTypedef: %s' % out) return out # Define an Enum. - def DefineEnum(self, node, prefix='', comment=False): + def DefineEnum(self, node, releases, prefix='', comment=False): self.LogEnter('DefineEnum %s' % node) unnamed = node.GetProperty('unnamed') if unnamed: @@ -353,12 +377,7 @@ class CGen(object): 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 + comment_txt = GetNodeComments(child, tabs=1) if value: item_txt = '%s%s = %s' % (prefix, child.GetName(), value) else: @@ -372,36 +391,15 @@ class CGen(object): out = '%s\n%s\n} %s;\n' % (out, ',\n'.join(enumlist), name) return out - def DefineMember(self, node, prefix='', comment=False): + def DefineMember(self, node, releases, prefix='', comment=False): + release = releases[0] 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) + out = '%s;' % self.GetSignature(node, release, 'store', '', True) self.LogExit('Exit DefineMember') return out - def InterfaceDefs(self, node): - out = '' - 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) == self.release: - out += self.GetDefine(macro, '%s_%s' % (macro, strver)) - out += '\n' - return out - # Define a Struct. - def DefineStruct(self, node, prefix='', comment=False): + def DefineStruct(self, node, releases, prefix='', comment=False): out = '' self.LogEnter('DefineStruct %s' % node) @@ -413,7 +411,7 @@ class CGen(object): # Generate Member Functions members = [] for child in node.GetListOf('Member'): - member = self.Define(child, tabs=1, comment=comment) + member = self.Define(child, releases, tabs=1, comment=comment) if not member: continue members.append(member) @@ -421,9 +419,6 @@ class CGen(object): self.LogExit('Exit DefineStruct') return out - def DefineType(self, node, prefix='', comment=False): - return '' - # # Copyright and Comment # @@ -431,124 +426,59 @@ class CGen(object): # 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' + return CommentLines(lines, tabs) # 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)) - - node_nim = node.GetProperty('version') - node_max = node.GetProperty('deprecate') + def Define(self, node, releases, tabs=0, prefix='', comment=False): + if not node.InReleases(releases): + return '' - if node_nim is not None: - node_nim = float(node_nim) - else: - node_nim = 0.0 + self.LogEnter('Define %s tab=%d prefix="%s"' % (node,tabs,prefix)) + declmap = { + 'Enum' : CGen.DefineEnum, + 'Function' : CGen.DefineMember, + 'Interface' : CGen.DefineStruct, + 'Member' : CGen.DefineMember, + 'Struct' : CGen.DefineStruct, + 'Typedef' : CGen.DefineTypedef, + } - if node_max is not None: - node_max = float(node_max) - else: - node_max = 1.0e100 - - label = node.GetLabel() - if label: - lver = label.GetVersion(self.release) - - # Verify that we are in a valid version. - if node_max <= lver: return '' - if node_nim > lver: return '' - - declmap = { - 'Describe' : CGen.DefineType, - 'Enum' : CGen.DefineEnum, - 'Function' : CGen.DefineMember, - 'Interface' : CGen.DefineStruct, - 'Member' : CGen.DefineMember, - 'Struct' : CGen.DefineStruct, - 'Type' : CGen.DefineType, - '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(',') - line_max = 0 - for arg in args: - if len(arg) > line_max: line_max = len(arg) - - if left + line_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)) + out = '' + 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, releases, prefix=prefix, comment=comment) + + comment_txt = GetNodeComments(node, tabs=0) + if comment_txt and comment: + out += comment_txt + out += define_txt + + tab = ' ' * tabs + lines = [] + for line in out.split('\n'): + # Add indentation + line = tab + line + if len(line) > 80: + left = line.rfind('(') + 1 + args = line[left:].split(',') + line_max = 0 + for arg in args: + if len(arg) > line_max: line_max = len(arg) + + if left + line_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: - 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 '' + space = ' ' * (left - 1) + args = (',\n%s' % space).join(args) + lines.append('%s%s' % (line[:left], args)) + else: + lines.append(line.rstrip()) + self.LogExit('Exit Define') + return '\n'.join(lines) # Clean a string representing an object definition and return then string # as a single space delimited set of tokens. @@ -569,7 +499,7 @@ def TestFile(filenode): instr.Dump() instr = CleanString(instr.GetName()) - outstr = cgen.Define(node) + outstr = cgen.Define(node, releases=['M14']) if GetOption('verbose'): print outstr + '\n' outstr = CleanString(outstr) diff --git a/ppapi/generators/idl_generator.py b/ppapi/generators/idl_generator.py index 32c943c..123d08a 100644 --- a/ppapi/generators/idl_generator.py +++ b/ppapi/generators/idl_generator.py @@ -20,7 +20,7 @@ Option('range', 'Which release ranges in the form of MIN,MAX.', default='') # # Base class for generators. This class provides a mechanism for # adding new generator objects to the IDL driver. To use this class -# override the GenerateVersion and GenerateRange members, and +# override the GenerateRelease and GenerateRange members, and # instantiate one copy of the class in the same module which defines it to # register the generator. After the AST is generated, call the static Run # member which will check every registered generator to see which ones have @@ -75,13 +75,15 @@ class Generator(object): else: vmin = range_list[0] vmax = range_list[1] - ret = self.GenerateRange(ast, vmin, vmax, options) - if not ret: + vmin = ast.releases.index(vmin) + vmax = ast.releases.index(vmax) + 1 + ret = self.GenerateRange(ast, ast.releases[vmin:vmax], options) + if ret < 0: self.Error('Failed to generate range %s : %s.' %(vmin, vmax)) # Otherwise this should be a single release generation else: if releasestr: - ret = self.GenerateVersion(ast, releasestr, options) + ret = self.GenerateRelease(ast, releasestr, options) if ret < 0: self.Error('Failed to generate release %s.' % releasestr) else: @@ -91,7 +93,7 @@ class Generator(object): self.Error('No range or release specified for %s.' % releasestr) return self.errors - def GenerateVersion(self, ast, release, options): + def GenerateRelease(self, ast, release, options): __pychecker__ = 'unusednames=ast,release,options' self.Error("Undefined release generator.") return 0 @@ -114,11 +116,65 @@ class Generator(object): return fail_count +# +# GeneratorByFile +# +# A subclass of Generator for use of generators which have a one to one +# mapping between IDL sources and output files. To use, derive a new class +# which defines: +# +# GetOutFile - Returns an IDLOutFile based on filenode (name) and options +# GenerateHead - Writes the first part of the file (includes, etc...) +# GenerateBody - Writes the body of the file (definitions) +# GenerateTail - Writes the end of the file (closing include guard, etc...) +# +class GeneratorByFile(Generator): + def GenerateRelease(self, ast, release, options): + return self.GenerateRange(ast, [release], options) + + def GenerateRange(self, ast, releases, options): + # Get list of out files + outlist = GetOption('out') + if outlist: outlist = outlist.split(',') + + skipList = [] + cnt = 0 + for filenode in ast.GetListOf('File'): + # Skip this file if not required + if outlist and name not in outlist: + continue + + # If this file has errors, skip it + if filenode.GetProperty('ERRORS') > 0: + skipList.append(filenode) + continue + + # Create output file + out = self.GetOutFile(filenode, options) + self.GenerateHead(out, filenode, releases, options) + self.GenerateBody(out, filenode, releases, options) + self.GenerateTail(out, filenode, releases, options) + + if out.Close(): cnt = cnt + 1 + + for filenode in skipList: + errcnt = filenode.GetProperty('ERRORS') + ErrOut.Log('%s : Skipped because of %d errors.' % ( + filenode.GetName(), errcnt)) + + if skipList: + return -len(skipList) + + if GetOption('diff'): + return -cnt + return cnt + + check_release = 0 check_range = 0 -class GeneratorVersionTest(Generator): - def GenerateVersion(self, ast, release, options = {}): +class GeneratorReleaseTest(Generator): + def GenerateRelease(self, ast, release, options = {}): __pychecker__ = 'unusednames=ast,release,options' global check_release check_map = { @@ -182,6 +238,6 @@ def Main(args): if __name__ == '__main__': - GeneratorVersionTest('Test Gen', 'testgen', 'Generator Class Test.') + GeneratorReleaseTest('Test Gen', 'testgen', 'Generator Class Test.') sys.exit(Main(sys.argv[1:])) diff --git a/ppapi/generators/idl_namespace.py b/ppapi/generators/idl_namespace.py index 2451168..98e86258 100644 --- a/ppapi/generators/idl_namespace.py +++ b/ppapi/generators/idl_namespace.py @@ -105,11 +105,13 @@ class IDLVersionMap(object): self.version_to_release = {} self.release_to_version = {} self.versions = [] + self.releases = [] def AddReleaseVersionMapping(self, release, version): self.version_to_release[version] = release self.release_to_version[release] = version self.versions = sorted(self.version_to_release.keys()) + self.releases = sorted(self.release_to_version.keys()) def GetRelease(self, version): # Check for exact match diff --git a/ppapi/generators/idl_node.py b/ppapi/generators/idl_node.py index 0c8c180..b8f71eb 100644 --- a/ppapi/generators/idl_node.py +++ b/ppapi/generators/idl_node.py @@ -214,6 +214,11 @@ class IDLNode(IDLVersion): out = self.IsVersion(version) return out + def InReleases(self, releases): + for rel in releases: + if self.IsRelease(rel): return True + return False + def GetLabel(self): label = self.GetProperty('LABEL') if not label: diff --git a/ppapi/generators/idl_outfile.py b/ppapi/generators/idl_outfile.py index d643b2f..ae8da4e 100644 --- a/ppapi/generators/idl_outfile.py +++ b/ppapi/generators/idl_outfile.py @@ -83,7 +83,7 @@ class IDLOutFile(object): if os.path.isfile(filename): intext = open(filename, 'r').read() else: - intext = None + intext = '' if IsEquivelent(intext, outtext): if GetOption('verbose'): diff --git a/ppapi/generators/test_cgen/enum_typedef.idl b/ppapi/generators/test_cgen/enum_typedef.idl index 45f1472..b5d0feb 100644 --- a/ppapi/generators/test_cgen/enum_typedef.idl +++ b/ppapi/generators/test_cgen/enum_typedef.idl @@ -4,7 +4,9 @@ * found in the LICENSE file. */ -/* This file will test that the IDL snippet matches the comment */ +/** + * This file will test that the IDL snippet matches the comment. + */ /* typedef enum { A = 1, B = 2, C = 3 } et1; */ enum et1 { A=1, B=2, C=3 }; diff --git a/ppapi/generators/test_cgen/interface.idl b/ppapi/generators/test_cgen/interface.idl index 0992614..e017daf 100644 --- a/ppapi/generators/test_cgen/interface.idl +++ b/ppapi/generators/test_cgen/interface.idl @@ -4,7 +4,9 @@ * found in the LICENSE file. */ -/* This file will test that the IDL snippet matches the comment */ +/** + * This file will test that the IDL snippet matches the comment. + */ /* struct ist { void* X; }; */ struct ist { diff --git a/ppapi/generators/test_cgen/structs.idl b/ppapi/generators/test_cgen/structs.idl index e942f05..ecf7163 100644 --- a/ppapi/generators/test_cgen/structs.idl +++ b/ppapi/generators/test_cgen/structs.idl @@ -4,7 +4,9 @@ * found in the LICENSE file. */ -/* This file will test that the IDL snippet matches the comment */ +/** + * This file will test that the IDL snippet matches the comment. + */ /* typedef uint8_t s_array[3]; */ typedef uint8_t[3] s_array; diff --git a/ppapi/generators/test_cgen_range/versions.h b/ppapi/generators/test_cgen_range/versions.h new file mode 100644 index 0000000..819ec0c --- /dev/null +++ b/ppapi/generators/test_cgen_range/versions.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2011 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* From test_cgen_range/versions.idl modified Wed Aug 24 10:35:01 2011. */ + +#ifndef PPAPI_C_TEST_CGEN_RANGE_VERSIONS_H_ +#define PPAPI_C_TEST_CGEN_RANGE_VERSIONS_H_ + +#include "ppapi/c/pp_macros.h" + +/** + * @file + * File Comment. */ + + +/** + * @addtogroup Structs + * @{ + */ +/* Bogus Struct */ +struct PP_Size { + /** + * Comment for function + */ + int32_t (*Foo)(int32_t x); + /** + * Comment for function + */ + int32_t (*Foo)(int32_t x, int32_t y); + /** + * Comment for function + */ + int32_t (*Foo)(int32_t x, int32_t y, int32_t z); +}; +/** + * @} + */ + +#endif /* PPAPI_C_TEST_CGEN_RANGE_VERSIONS_H_ */ + diff --git a/ppapi/generators/test_cgen_range/versions.idl b/ppapi/generators/test_cgen_range/versions.idl new file mode 100644 index 0000000..f4fe232 --- /dev/null +++ b/ppapi/generators/test_cgen_range/versions.idl @@ -0,0 +1,36 @@ +/* Copyright (c) 2011 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* File Comment. */ + +label Chrome { + M13 = 0.0, + M14 = 1.0, + M15 = 2.0 +}; + +[version=0.0] +describe { + /** Standard Ints. */ + int32_t; +}; + + +/* Bogus Struct */ +[version=0.0] +struct PP_Size { + /** + * Comment for function + */ + [version=0.0] int32_t Foo(int32_t x); + /** + * Comment for function + */ + [version=1.0] int32_t Foo(int32_t x, int32_t y); + /** + * Comment for function + */ + [version=2.0] int32_t Foo(int32_t x, int32_t y, int32_t z); +}; |