blob: d4561d5ee4b549ee9a3f48f612a81d8ca60741d7 [file] [log] [blame]
[email protected]4a41db52012-01-13 00:02:561#!/usr/bin/env python
[email protected]dbf21cc2012-01-04 21:57:042# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]f0dd202f2011-06-07 01:36:013# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6""" Generator for C style prototypes and definitions """
7
8import glob
9import os
[email protected]532d461a2012-05-11 18:21:2010import re
[email protected]f0dd202f2011-06-07 01:36:0111import sys
12
13from idl_log import ErrOut, InfoOut, WarnOut
[email protected]5eef2882011-07-19 00:08:5414from idl_node import IDLAttribute, IDLNode
15from idl_ast import IDLAst
[email protected]f0dd202f2011-06-07 01:36:0116from idl_option import GetOption, Option, ParseOptions
17from idl_outfile import IDLOutFile
18from idl_parser import ParseFiles
[email protected]f7314732011-08-24 23:03:0619from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment
20from idl_generator import Generator, GeneratorByFile
[email protected]f0dd202f2011-06-07 01:36:0121
[email protected]f93616a2011-10-04 22:54:2222Option('dstroot', 'Base directory of output', default=os.path.join('..', 'c'))
23Option('guard', 'Include guard prefix', default=os.path.join('ppapi', 'c'))
[email protected]5eef2882011-07-19 00:08:5424
[email protected]406793d2011-11-14 22:26:5425
[email protected]6faeb202012-12-06 15:43:0526def GetPathFromNode(filenode, relpath=None, ext=None):
[email protected]5eef2882011-07-19 00:08:5427 path, name = os.path.split(filenode.GetProperty('NAME'))
[email protected]6faeb202012-12-06 15:43:0528 if ext: name = os.path.splitext(name)[0] + ext
[email protected]5eef2882011-07-19 00:08:5429 if path: name = os.path.join(path, name)
30 if relpath: name = os.path.join(relpath, name)
[email protected]6faeb202012-12-06 15:43:0531 name = os.path.normpath(name)
[email protected]5eef2882011-07-19 00:08:5432 return name
33
[email protected]406793d2011-11-14 22:26:5434
[email protected]6faeb202012-12-06 15:43:0535def GetHeaderFromNode(filenode, relpath=None):
36 return GetPathFromNode(filenode, relpath, ext='.h')
37
38
[email protected]f7314732011-08-24 23:03:0639def WriteGroupMarker(out, node, last_group):
40 # If we are part of a group comment marker...
41 if last_group and last_group != node.cls:
42 pre = CommentLines(['*',' @}', '']) + '\n'
43 else:
44 pre = '\n'
[email protected]5eef2882011-07-19 00:08:5445
[email protected]f7314732011-08-24 23:03:0646 if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']:
47 if last_group != node.cls:
48 pre += CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', ''])
49 last_group = node.cls
50 else:
51 last_group = None
52 out.Write(pre)
53 return last_group
[email protected]5eef2882011-07-19 00:08:5454
[email protected]5eef2882011-07-19 00:08:5455
[email protected]f7314732011-08-24 23:03:0656def GenerateHeader(out, filenode, releases):
[email protected]f7314732011-08-24 23:03:0657 cgen = CGen()
58 pref = ''
59 do_comments = True
[email protected]5eef2882011-07-19 00:08:5460
61 # Generate definitions.
62 last_group = None
[email protected]f7314732011-08-24 23:03:0663 top_types = ['Typedef', 'Interface', 'Struct', 'Enum', 'Inline']
64 for node in filenode.GetListOf(*top_types):
65 # Skip if this node is not in this release
66 if not node.InReleases(releases):
67 print "Skiping %s" % node
68 continue
[email protected]5eef2882011-07-19 00:08:5469
[email protected]f7314732011-08-24 23:03:0670 # End/Start group marker
71 if do_comments:
72 last_group = WriteGroupMarker(out, node, last_group)
[email protected]5eef2882011-07-19 00:08:5473
[email protected]f7314732011-08-24 23:03:0674 if node.IsA('Inline'):
75 item = node.GetProperty('VALUE')
76 # If 'C++' use __cplusplus wrapper
[email protected]5eef2882011-07-19 00:08:5477 if node.GetName() == 'cc':
[email protected]8450e432012-11-06 03:33:4678 item = '#ifdef __cplusplus\n%s\n#endif /* __cplusplus */\n\n' % item
[email protected]f7314732011-08-24 23:03:0679 # If not C++ or C, then skip it
80 elif not node.GetName() == 'c':
[email protected]5eef2882011-07-19 00:08:5481 continue
[email protected]f7314732011-08-24 23:03:0682 if item: out.Write(item)
83 continue
[email protected]5eef2882011-07-19 00:08:5484
[email protected]f7314732011-08-24 23:03:0685 #
86 # Otherwise we are defining a file level object, so generate the
87 # correct document notation.
88 #
89 item = cgen.Define(node, releases, prefix=pref, comment=True)
90 if not item: continue
91 asize = node.GetProperty('assert_size()')
92 if asize:
93 name = '%s%s' % (pref, node.GetName())
94 if node.IsA('Struct'):
95 form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n'
[email protected]03f41ec2011-11-18 22:53:0496 elif node.IsA('Enum'):
97 if node.GetProperty('notypedef'):
98 form = 'PP_COMPILE_ASSERT_ENUM_SIZE_IN_BYTES(%s, %s);\n'
99 else:
100 form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n'
[email protected]f7314732011-08-24 23:03:06101 else:
102 form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n'
103 item += form % (name, asize[0])
104
105 if item: out.Write(item)
[email protected]5eef2882011-07-19 00:08:54106 if last_group:
[email protected]f7314732011-08-24 23:03:06107 out.Write(CommentLines(['*',' @}', '']) + '\n')
[email protected]5eef2882011-07-19 00:08:54108
[email protected]5eef2882011-07-19 00:08:54109
[email protected]f7314732011-08-24 23:03:06110class HGen(GeneratorByFile):
[email protected]acc3d8e2011-08-22 22:17:40111 def __init__(self):
112 Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.')
[email protected]5eef2882011-07-19 00:08:54113
[email protected]406793d2011-11-14 22:26:54114 def GenerateFile(self, filenode, releases, options):
[email protected]6faeb202012-12-06 15:43:05115 savename = GetHeaderFromNode(filenode, GetOption('dstroot'))
[email protected]98cfdfc2012-10-23 18:10:02116 my_min, my_max = filenode.GetMinMax(releases)
117 if my_min > releases[-1] or my_max < releases[0]:
[email protected]55e1a702012-01-10 17:55:17118 if os.path.isfile(savename):
119 print "Removing stale %s for this range." % filenode.GetName()
120 os.remove(os.path.realpath(savename))
121 return False
122
[email protected]406793d2011-11-14 22:26:54123 out = IDLOutFile(savename)
124 self.GenerateHead(out, filenode, releases, options)
125 self.GenerateBody(out, filenode, releases, options)
126 self.GenerateTail(out, filenode, releases, options)
127 return out.Close()
[email protected]f0dd202f2011-06-07 01:36:01128
[email protected]f7314732011-08-24 23:03:06129 def GenerateHead(self, out, filenode, releases, options):
[email protected]406793d2011-11-14 22:26:54130 __pychecker__ = 'unusednames=options'
[email protected]f7314732011-08-24 23:03:06131 cgen = CGen()
132 gpath = GetOption('guard')
[email protected]6faeb202012-12-06 15:43:05133 def_guard = GetHeaderFromNode(filenode, relpath=gpath)
[email protected]f93616a2011-10-04 22:54:22134 def_guard = def_guard.replace(os.sep,'_').replace('.','_').upper() + '_'
[email protected]5eef2882011-07-19 00:08:54135
[email protected]f7314732011-08-24 23:03:06136 cright_node = filenode.GetChildren()[0]
137 assert(cright_node.IsA('Copyright'))
138 fileinfo = filenode.GetChildren()[1]
139 assert(fileinfo.IsA('Comment'))
[email protected]5eef2882011-07-19 00:08:54140
[email protected]f7314732011-08-24 23:03:06141 out.Write('%s\n' % cgen.Copyright(cright_node))
[email protected]dbf21cc2012-01-04 21:57:04142
143 # Wrap the From ... modified ... comment if it would be >80 characters.
[email protected]6faeb202012-12-06 15:43:05144 from_text = 'From %s' % GetPathFromNode(filenode)
[email protected]dbf21cc2012-01-04 21:57:04145 modified_text = 'modified %s.' % (
146 filenode.GetProperty('DATETIME'))
147 if len(from_text) + len(modified_text) < 74:
148 out.Write('/* %s %s */\n\n' % (from_text, modified_text))
149 else:
150 out.Write('/* %s,\n * %s\n */\n\n' % (from_text, modified_text))
151
[email protected]f7314732011-08-24 23:03:06152 out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard))
153 # Generate set of includes
154
155 deps = set()
156 for release in releases:
157 deps |= filenode.GetDeps(release)
158
159 includes = set([])
160 for dep in deps:
161 depfile = dep.GetProperty('FILE')
162 if depfile:
163 includes.add(depfile)
[email protected]6faeb202012-12-06 15:43:05164 includes = [GetHeaderFromNode(
[email protected]f93616a2011-10-04 22:54:22165 include, relpath=gpath).replace(os.sep, '/') for include in includes]
[email protected]f7314732011-08-24 23:03:06166 includes.append('ppapi/c/pp_macros.h')
167
168 # Assume we need stdint if we "include" C or C++ code
169 if filenode.GetListOf('Include'):
170 includes.append('ppapi/c/pp_stdint.h')
171
172 includes = sorted(set(includes))
[email protected]6faeb202012-12-06 15:43:05173 cur_include = GetHeaderFromNode(filenode,
174 relpath=gpath).replace(os.sep, '/')
[email protected]f7314732011-08-24 23:03:06175 for include in includes:
176 if include == cur_include: continue
177 out.Write('#include "%s"\n' % include)
178
[email protected]532d461a2012-05-11 18:21:20179 # If we are generating a single release, then create a macro for the highest
180 # available release number.
181 if filenode.GetProperty('NAME').endswith('pp_macros.idl'):
182 releasestr = GetOption('release')
183 if releasestr:
184 release_numbers = re.findall('\d+', releasestr)
185 if release_numbers:
186 out.Write('\n#define PPAPI_RELEASE %s\n' % release_numbers[0])
187
[email protected]f7314732011-08-24 23:03:06188 # Generate all interface defines
189 out.Write('\n')
190 for node in filenode.GetListOf('Interface'):
191 idefs = ''
[email protected]406793d2011-11-14 22:26:54192 macro = cgen.GetInterfaceMacro(node)
[email protected]55e1a702012-01-10 17:55:17193 unique = node.GetUniqueReleases(releases)
194
195 # Skip this interface if there are no matching versions
196 if not unique: continue
197
198 for rel in unique:
[email protected]e8a83feb2011-08-25 21:04:26199 version = node.GetVersion(rel)
[email protected]406793d2011-11-14 22:26:54200 name = cgen.GetInterfaceString(node, version)
[email protected]e8a83feb2011-08-25 21:04:26201 strver = str(version).replace('.', '_')
[email protected]406793d2011-11-14 22:26:54202 idefs += cgen.GetDefine('%s_%s' % (macro, strver), '"%s"' % name)
203 idefs += cgen.GetDefine(macro, '%s_%s' % (macro, strver)) + '\n'
[email protected]f7314732011-08-24 23:03:06204 out.Write(idefs)
205
206 # Generate the @file comment
207 out.Write('%s\n' % Comment(fileinfo, prefix='*\n @file'))
208
209 def GenerateBody(self, out, filenode, releases, options):
[email protected]406793d2011-11-14 22:26:54210 __pychecker__ = 'unusednames=options'
[email protected]f7314732011-08-24 23:03:06211 GenerateHeader(out, filenode, releases)
212
213 def GenerateTail(self, out, filenode, releases, options):
[email protected]406793d2011-11-14 22:26:54214 __pychecker__ = 'unusednames=options,releases'
[email protected]f7314732011-08-24 23:03:06215 gpath = GetOption('guard')
[email protected]6faeb202012-12-06 15:43:05216 def_guard = GetPathFromNode(filenode, relpath=gpath, ext='.h')
[email protected]f93616a2011-10-04 22:54:22217 def_guard = def_guard.replace(os.sep,'_').replace('.','_').upper() + '_'
[email protected]f7314732011-08-24 23:03:06218 out.Write('#endif /* %s */\n\n' % def_guard)
[email protected]5eef2882011-07-19 00:08:54219
[email protected]5eef2882011-07-19 00:08:54220
[email protected]acc3d8e2011-08-22 22:17:40221hgen = HGen()
222
[email protected]6faeb202012-12-06 15:43:05223def main(args):
[email protected]acc3d8e2011-08-22 22:17:40224 # Default invocation will verify the golden files are unchanged.
[email protected]f7314732011-08-24 23:03:06225 failed = 0
[email protected]acc3d8e2011-08-22 22:17:40226 if not args:
227 args = ['--wnone', '--diff', '--test', '--dstroot=.']
228
229 ParseOptions(args)
[email protected]f7314732011-08-24 23:03:06230
[email protected]acc3d8e2011-08-22 22:17:40231 idldir = os.path.split(sys.argv[0])[0]
232 idldir = os.path.join(idldir, 'test_cgen', '*.idl')
233 filenames = glob.glob(idldir)
[email protected]f7314732011-08-24 23:03:06234 ast = ParseFiles(filenames)
235 if hgen.GenerateRelease(ast, 'M14', {}):
236 print "Golden file for M14 failed."
237 failed = 1
238 else:
239 print "Golden file for M14 passed."
240
241
242 idldir = os.path.split(sys.argv[0])[0]
243 idldir = os.path.join(idldir, 'test_cgen_range', '*.idl')
244 filenames = glob.glob(idldir)
[email protected]acc3d8e2011-08-22 22:17:40245
246 ast = ParseFiles(filenames)
[email protected]f7314732011-08-24 23:03:06247 if hgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}):
248 print "Golden file for M13-M15 failed."
249 failed =1
250 else:
251 print "Golden file for M13-M15 passed."
252
253 return failed
[email protected]f0dd202f2011-06-07 01:36:01254
255if __name__ == '__main__':
[email protected]6faeb202012-12-06 15:43:05256 sys.exit(main(sys.argv[1:]))
[email protected]55e1a702012-01-10 17:55:17257