Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ppapi / generators / idl_c_proto.py
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # 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
8 import glob
9 import os
10 import sys
11
12 from idl_log import ErrOut, InfoOut, WarnOut
13 from idl_node import IDLNode
14 from idl_ast import IDLAst
15 from idl_option import GetOption, Option, ParseOptions
16 from idl_parser import ParseFiles
17
18 Option('cgen_debug', 'Debug generate.')
19
20 class CGenError(Exception):
21   def __init__(self, msg):
22     self.value = msg
23
24   def __str__(self):
25     return repr(self.value)
26
27
28 def CommentLines(lines, tabs=0):
29   # Generate a C style comment block by prepending the block with '<tab>/*'
30   # and adding a '<tab> *' per line.
31   tab = '  ' * tabs
32
33   out = '%s/*' % tab + ('\n%s *' % tab).join(lines)
34
35   # Add a terminating ' */' unless the last line is blank which would mean it
36   # already has ' *'
37   if not lines[-1]:
38     out += '/\n'
39   else:
40     out += ' */\n'
41   return out
42
43 def Comment(node, prefix=None, tabs=0):
44   # Generate a comment block from the provided Comment node.
45   comment = node.GetName()
46   lines = comment.split('\n')
47
48   # If an option prefix is provided, then prepend that to the comment
49   # for this node.
50   if prefix:
51     prefix_lines = prefix.split('\n')
52     # If both the prefix and comment start with a blank line ('*') remove
53     # the extra one.
54     if prefix_lines[0] == '*' and lines[0] == '*':
55       lines = prefix_lines + lines[1:]
56     else:
57       lines = prefix_lines + lines;
58   return CommentLines(lines, tabs)
59
60 def GetNodeComments(node, tabs=0):
61   # Generate a comment block joining all comment nodes which are children of
62   # the provided node.
63   comment_txt = ''
64   for doc in node.GetListOf('Comment'):
65     comment_txt += Comment(doc, tabs=tabs)
66   return comment_txt
67
68
69 class CGen(object):
70   # TypeMap
71   #
72   # TypeMap modifies how an object is stored or passed, for example pointers
73   # are passed as 'const' if they are 'in' parameters, and structures are
74   # preceeded by the keyword 'struct' as well as using a pointer.
75   #
76   TypeMap = {
77     'Array': {
78       'in': 'const %s',
79       'inout': '%s',
80       'out': '%s*',
81       'store': '%s',
82       'return': '%s',
83       'ref': '%s*'
84     },
85     'Callspec': {
86       'in': '%s',
87       'inout': '%s',
88       'out': '%s',
89       'store': '%s',
90       'return': '%s'
91     },
92     'Enum': {
93       'in': '%s',
94       'inout': '%s*',
95       'out': '%s*',
96       'store': '%s',
97       'return': '%s'
98     },
99     'Interface': {
100       'in': 'const %s*',
101       'inout': '%s*',
102       'out': '%s**',
103       'return': '%s*',
104       'store': '%s*'
105     },
106     'Struct': {
107       'in': 'const %s*',
108       'inout': '%s*',
109       'out': '%s*',
110       'return': ' %s*',
111       'store': '%s',
112       'ref': '%s*'
113     },
114     'blob_t': {
115       'in': 'const %s',
116       'inout': '%s',
117       'out': '%s',
118       'return': '%s',
119       'store': '%s'
120     },
121     'mem_t': {
122       'in': 'const %s',
123       'inout': '%s',
124       'out': '%s',
125       'return': '%s',
126       'store': '%s'
127     },
128     'mem_ptr_t': {
129       'in': 'const %s',
130       'inout': '%s',
131       'out': '%s',
132       'return': '%s',
133       'store': '%s'
134     },
135     'str_t': {
136       'in': 'const %s',
137       'inout': '%s',
138       'out': '%s',
139       'return': 'const %s',
140       'store': '%s'
141     },
142     'cstr_t': {
143       'in': '%s',
144       'inout': '%s*',
145       'out': '%s*',
146       'return': '%s',
147       'store': '%s'
148     },
149     'TypeValue': {
150       'in': '%s',
151       'inout': '%s*',
152       'out': '%s*',
153       'return': '%s',
154       'store': '%s'
155     },
156   }
157
158
159   #
160   # RemapName
161   #
162   # A diction array of PPAPI types that are converted to language specific
163   # types before being returned by by the C generator
164   #
165   RemapName = {
166   'blob_t': 'void**',
167   'float_t': 'float',
168   'double_t': 'double',
169   'handle_t': 'int',
170   'mem_t': 'void*',
171   'mem_ptr_t': 'void**',
172   'str_t': 'char*',
173   'cstr_t': 'const char*',
174   'interface_t' : 'const void*'
175   }
176
177   def __init__(self):
178     self.dbg_depth = 0
179
180   #
181   # Debug Logging functions
182   #
183   def Log(self, txt):
184     if not GetOption('cgen_debug'): return
185     tabs = '  ' * self.dbg_depth
186     print '%s%s' % (tabs, txt)
187
188   def LogEnter(self, txt):
189     if txt: self.Log(txt)
190     self.dbg_depth += 1
191
192   def LogExit(self, txt):
193     self.dbg_depth -= 1
194     if txt: self.Log(txt)
195
196
197   def GetDefine(self, name, value):
198     out = '#define %s %s' % (name, value)
199     if len(out) > 80:
200       out = '#define %s \\\n    %s' % (name, value)
201     return '%s\n' % out
202
203   #
204   # Interface strings
205   #
206   def GetMacroHelper(self, node):
207     macro = node.GetProperty('macro')
208     if macro: return macro
209     name = node.GetName()
210     name = name.upper()
211     return "%s_INTERFACE" % name
212
213   def GetInterfaceMacro(self, node, version = None):
214     name = self.GetMacroHelper(node)
215     if version is None:
216       return name
217     return '%s_%s' % (name, str(version).replace('.', '_'))
218
219   def GetInterfaceString(self, node, version = None):
220     # If an interface name is specified, use that
221     name = node.GetProperty('iname')
222     if not name:
223       # Otherwise, the interface name is the object's name
224       # With '_Dev' replaced by '(Dev)' if it's a Dev interface.
225       name = node.GetName()
226       if name.endswith('_Dev'):
227         name = '%s(Dev)' % name[:-4]
228     if version is None:
229       return name
230     return "%s;%s" % (name, version)
231
232
233   #
234   # Return the array specification of the object.
235   #
236   def GetArraySpec(self, node):
237     assert(node.cls == 'Array')
238     fixed = node.GetProperty('FIXED')
239     if fixed:
240       return '[%s]' % fixed
241     else:
242       return '[]'
243
244   #
245   # GetTypeName
246   #
247   # For any valid 'typed' object such as Member or Typedef
248   # the typenode object contains the typename
249   #
250   # For a given node return the type name by passing mode.
251   #
252   def GetTypeName(self, node, release, prefix=''):
253     self.LogEnter('GetTypeName of %s rel=%s' % (node, release))
254
255     # For Members, Params, and Typedefs get the type it refers to otherwise
256     # the node in question is it's own type (struct, union etc...)
257     if node.IsA('Member', 'Param', 'Typedef'):
258       typeref = node.GetType(release)
259     else:
260       typeref = node
261
262     if typeref is None:
263       node.Error('No type at release %s.' % release)
264       raise CGenError('No type for %s' % node)
265
266     # If the type is a (BuiltIn) Type then return it's name
267     # remapping as needed
268     if typeref.IsA('Type'):
269       name = CGen.RemapName.get(typeref.GetName(), None)
270       if name is None: name = typeref.GetName()
271       name = '%s%s' % (prefix, name)
272
273     # For Interfaces, use the name + version
274     elif typeref.IsA('Interface'):
275       rel = typeref.first_release[release]
276       name = 'struct %s%s' % (prefix, self.GetStructName(typeref, rel, True))
277
278     # For structures, preceed with 'struct' or 'union' as appropriate
279     elif typeref.IsA('Struct'):
280       if typeref.GetProperty('union'):
281         name = 'union %s%s' % (prefix, typeref.GetName())
282       else:
283         name = 'struct %s%s' % (prefix, typeref.GetName())
284
285     # If it's an enum, or typedef then return the Enum's name
286     elif typeref.IsA('Enum', 'Typedef'):
287       if not typeref.LastRelease(release):
288         first = node.first_release[release]
289         ver = '_' + node.GetVersion(first).replace('.','_')
290       else:
291         ver = ''
292       # The enum may have skipped having a typedef, we need prefix with 'enum'.
293       if typeref.GetProperty('notypedef'):
294         name = 'enum %s%s%s' % (prefix, typeref.GetName(), ver)
295       else:
296         name = '%s%s%s' % (prefix, typeref.GetName(), ver)
297
298     else:
299       raise RuntimeError('Getting name of non-type %s.' % node)
300     self.LogExit('GetTypeName %s is %s' % (node, name))
301     return name
302
303
304   #
305   # GetRootType
306   #
307   # For a given node return basic type of that object.  This is
308   # either a 'Type', 'Callspec', or 'Array'
309   #
310   def GetRootTypeMode(self, node, release, mode):
311     self.LogEnter('GetRootType of %s' % node)
312     # If it has an array spec, then treat it as an array regardless of type
313     if node.GetOneOf('Array'):
314       rootType = 'Array'
315     # Or if it has a callspec, treat it as a function
316     elif node.GetOneOf('Callspec'):
317       rootType, mode = self.GetRootTypeMode(node.GetType(release), release,
318                                             'return')
319
320     # If it's a plain typedef, try that object's root type
321     elif node.IsA('Member', 'Param', 'Typedef'):
322       rootType, mode = self.GetRootTypeMode(node.GetType(release),
323                                             release, mode)
324
325     # If it's an Enum, then it's normal passing rules
326     elif node.IsA('Enum'):
327       rootType = node.cls
328
329     # If it's an Interface or Struct, we may be passing by value
330     elif node.IsA('Interface', 'Struct'):
331       if mode == 'return':
332         if node.GetProperty('returnByValue'):
333           rootType = 'TypeValue'
334         else:
335           rootType = node.cls
336       else:
337         if node.GetProperty('passByValue'):
338           rootType = 'TypeValue'
339         else:
340           rootType = node.cls
341
342     # If it's an Basic Type, check if it's a special type
343     elif node.IsA('Type'):
344       if node.GetName() in CGen.TypeMap:
345         rootType = node.GetName()
346       else:
347         rootType = 'TypeValue'
348     else:
349       raise RuntimeError('Getting root type of non-type %s.' % node)
350     self.LogExit('RootType is "%s"' % rootType)
351     return rootType, mode
352
353
354   def GetTypeByMode(self, node, release, mode):
355     self.LogEnter('GetTypeByMode of %s mode=%s release=%s' %
356                   (node, mode, release))
357     name = self.GetTypeName(node, release)
358     ntype, mode = self.GetRootTypeMode(node, release, mode)
359     out = CGen.TypeMap[ntype][mode] % name
360     self.LogExit('GetTypeByMode %s = %s' % (node, out))
361     return out
362
363
364   # Get the passing mode of the object (in, out, inout).
365   def GetParamMode(self, node):
366     self.Log('GetParamMode for %s' % node)
367     if node.GetProperty('in'): return 'in'
368     if node.GetProperty('out'): return 'out'
369     if node.GetProperty('inout'): return 'inout'
370     return 'return'
371
372   #
373   # GetComponents
374   #
375   # Returns the signature components of an object as a tuple of
376   # (rtype, name, arrays, callspec) where:
377   #   rtype - The store or return type of the object.
378   #   name - The name of the object.
379   #   arrays - A list of array dimensions as [] or [<fixed_num>].
380   #   args -  None if not a function, otherwise a list of parameters.
381   #
382   def GetComponents(self, node, release, mode):
383     self.LogEnter('GetComponents mode %s for %s %s' % (mode, node, release))
384
385     # Generate passing type by modifying root type
386     rtype = self.GetTypeByMode(node, release, mode)
387     if node.IsA('Enum', 'Interface', 'Struct'):
388       rname = node.GetName()
389     else:
390       rname = node.GetType(release).GetName()
391
392     if rname in CGen.RemapName:
393       rname = CGen.RemapName[rname]
394     if '%' in rtype:
395       rtype = rtype % rname
396     name = node.GetName()
397     arrayspec = [self.GetArraySpec(array) for array in node.GetListOf('Array')]
398     callnode = node.GetOneOf('Callspec')
399     if callnode:
400       callspec = []
401       for param in callnode.GetListOf('Param'):
402         if not param.IsRelease(release):
403           continue
404         mode = self.GetParamMode(param)
405         ptype, pname, parray, pspec = self.GetComponents(param, release, mode)
406         callspec.append((ptype, pname, parray, pspec))
407     else:
408       callspec = None
409
410     self.LogExit('GetComponents: %s, %s, %s, %s' %
411                  (rtype, name, arrayspec, callspec))
412     return (rtype, name, arrayspec, callspec)
413
414
415   def Compose(self, rtype, name, arrayspec, callspec, prefix, func_as_ptr,
416               include_name, unsized_as_ptr):
417     self.LogEnter('Compose: %s %s' % (rtype, name))
418     arrayspec = ''.join(arrayspec)
419
420     # Switch unsized array to a ptr. NOTE: Only last element can be unsized.
421     if unsized_as_ptr and arrayspec[-2:] == '[]':
422       prefix +=  '*'
423       arrayspec=arrayspec[:-2]
424
425     if not include_name:
426       name = prefix + arrayspec
427     else:
428       name = prefix + name + arrayspec
429     if callspec is None:
430       out = '%s %s' % (rtype, name)
431     else:
432       params = []
433       for ptype, pname, parray, pspec in callspec:
434         params.append(self.Compose(ptype, pname, parray, pspec, '', True,
435                                    include_name=True,
436                                    unsized_as_ptr=unsized_as_ptr))
437       if func_as_ptr:
438         name = '(*%s)' % name
439       if not params:
440         params = ['void']
441       out = '%s %s(%s)' % (rtype, name, ', '.join(params))
442     self.LogExit('Exit Compose: %s' % out)
443     return out
444
445   #
446   # GetSignature
447   #
448   # Returns the 'C' style signature of the object
449   #  prefix - A prefix for the object's name
450   #  func_as_ptr - Formats a function as a function pointer
451   #  include_name - If true, include member name in the signature.
452   #                 If false, leave it out. In any case, prefix is always
453   #                 included.
454   #  include_version - if True, include version in the member name
455   #
456   def GetSignature(self, node, release, mode, prefix='', func_as_ptr=True,
457                    include_name=True, include_version=False):
458     self.LogEnter('GetSignature %s %s as func=%s' %
459                   (node, mode, func_as_ptr))
460     rtype, name, arrayspec, callspec = self.GetComponents(node, release, mode)
461     if include_version:
462       name = self.GetStructName(node, release, True)
463
464     # If not a callspec (such as a struct) use a ptr instead of []
465     unsized_as_ptr = not callspec
466
467     out = self.Compose(rtype, name, arrayspec, callspec, prefix,
468                        func_as_ptr, include_name, unsized_as_ptr)
469
470     self.LogExit('Exit GetSignature: %s' % out)
471     return out
472
473   # Define a Typedef.
474   def DefineTypedef(self, node, releases, prefix='', comment=False):
475     __pychecker__ = 'unusednames=comment'
476     build_list = node.GetUniqueReleases(releases)
477
478     out = 'typedef %s;\n' % self.GetSignature(node, build_list[-1], 'return',
479                                               prefix, True,
480                                               include_version=False)
481     # Version mangle any other versions
482     for index, rel in enumerate(build_list[:-1]):
483       out += '\n'
484       out += 'typedef %s;\n' % self.GetSignature(node, rel, 'return',
485                                                  prefix, True,
486                                                  include_version=True)
487     self.Log('DefineTypedef: %s' % out)
488     return out
489
490   # Define an Enum.
491   def DefineEnum(self, node, releases, prefix='', comment=False):
492     __pychecker__ = 'unusednames=comment,releases'
493     self.LogEnter('DefineEnum %s' % node)
494     name = '%s%s' % (prefix, node.GetName())
495     notypedef = node.GetProperty('notypedef')
496     unnamed = node.GetProperty('unnamed')
497
498     if unnamed:
499       out = 'enum {'
500     elif notypedef:
501       out = 'enum %s {' % name
502     else:
503       out = 'typedef enum {'
504     enumlist = []
505     for child in node.GetListOf('EnumItem'):
506       value = child.GetProperty('VALUE')
507       comment_txt = GetNodeComments(child, tabs=1)
508       if value:
509         item_txt = '%s%s = %s' % (prefix, child.GetName(), value)
510       else:
511         item_txt = '%s%s' % (prefix, child.GetName())
512       enumlist.append('%s  %s' % (comment_txt, item_txt))
513     self.LogExit('Exit DefineEnum')
514
515     if unnamed or notypedef:
516       out = '%s\n%s\n};\n' % (out, ',\n'.join(enumlist))
517     else:
518       out = '%s\n%s\n} %s;\n' % (out, ',\n'.join(enumlist), name)
519     return out
520
521   def DefineMember(self, node, releases, prefix='', comment=False):
522     __pychecker__ = 'unusednames=prefix,comment'
523     release = releases[0]
524     self.LogEnter('DefineMember %s' % node)
525     if node.GetProperty('ref'):
526       out = '%s;' % self.GetSignature(node, release, 'ref', '', True)
527     else:
528       out = '%s;' % self.GetSignature(node, release, 'store', '', True)
529     self.LogExit('Exit DefineMember')
530     return out
531
532   def GetStructName(self, node, release, include_version=False):
533     suffix = ''
534     if include_version:
535       ver_num = node.GetVersion(release)
536       suffix = ('_%s' % ver_num).replace('.', '_')
537     return node.GetName() + suffix
538
539   def DefineStructInternals(self, node, release,
540                             include_version=False, comment=True):
541     channel = node.GetProperty('FILE').release_map.GetChannel(release)
542     if channel == 'dev':
543       channel_comment = ' /* dev */'
544     else:
545       channel_comment = ''
546     out = ''
547     if node.GetProperty('union'):
548       out += 'union %s {%s\n' % (
549           self.GetStructName(node, release, include_version), channel_comment)
550     else:
551       out += 'struct %s {%s\n' % (
552           self.GetStructName(node, release, include_version), channel_comment)
553
554     channel = node.GetProperty('FILE').release_map.GetChannel(release)
555     # Generate Member Functions
556     members = []
557     for child in node.GetListOf('Member'):
558       if channel == 'stable' and child.NodeIsDevOnly():
559         continue
560       member = self.Define(child, [release], tabs=1, comment=comment)
561       if not member:
562         continue
563       members.append(member)
564     out += '%s\n};\n' % '\n'.join(members)
565     return out
566
567
568   def DefineStruct(self, node, releases, prefix='', comment=False):
569     __pychecker__ = 'unusednames=comment,prefix'
570     self.LogEnter('DefineStruct %s' % node)
571     out = ''
572     build_list = node.GetUniqueReleases(releases)
573
574     newest_stable = None
575     newest_dev = None
576     for rel in build_list:
577       channel = node.GetProperty('FILE').release_map.GetChannel(rel)
578       if channel == 'stable':
579         newest_stable = rel
580       if channel == 'dev':
581         newest_dev = rel
582     last_rel = build_list[-1]
583
584     # TODO(noelallen) : Bug 157017 finish multiversion support
585     if node.IsA('Struct'):
586       if len(build_list) != 1:
587         node.Error('Can not support multiple versions of node.')
588       assert len(build_list) == 1
589       # Build the most recent one versioned, with comments
590       out = self.DefineStructInternals(node, last_rel,
591                                        include_version=False, comment=True)
592
593     if node.IsA('Interface'):
594       # Build the most recent one versioned, with comments
595       out = self.DefineStructInternals(node, last_rel,
596                                        include_version=True, comment=True)
597       if last_rel == newest_stable:
598         # Define an unversioned typedef for the most recent version
599         out += '\ntypedef struct %s %s;\n' % (
600             self.GetStructName(node, last_rel, include_version=True),
601             self.GetStructName(node, last_rel, include_version=False))
602
603       # Build the rest without comments and with the version number appended
604       for rel in build_list[0:-1]:
605         channel = node.GetProperty('FILE').release_map.GetChannel(rel)
606         # Skip dev channel interface versions that are
607         #   Not the newest version, and
608         #   Don't have an equivalent stable version.
609         if channel == 'dev' and rel != newest_dev:
610           if not node.DevInterfaceMatchesStable(rel):
611             continue
612         out += '\n' + self.DefineStructInternals(node, rel,
613                                                  include_version=True,
614                                                  comment=False)
615         if rel == newest_stable:
616           # Define an unversioned typedef for the most recent version
617           out += '\ntypedef struct %s %s;\n' % (
618               self.GetStructName(node, rel, include_version=True),
619               self.GetStructName(node, rel, include_version=False))
620
621     self.LogExit('Exit DefineStruct')
622     return out
623
624
625   #
626   # Copyright and Comment
627   #
628   # Generate a comment or copyright block
629   #
630   def Copyright(self, node, cpp_style=False):
631     lines = node.GetName().split('\n')
632     if cpp_style:
633       return '//' + '\n//'.join(filter(lambda f: f != '', lines)) + '\n'
634     return CommentLines(lines)
635
636
637   def Indent(self, data, tabs=0):
638     """Handles indentation and 80-column line wrapping."""
639     tab = '  ' * tabs
640     lines = []
641     for line in data.split('\n'):
642       # Add indentation
643       line = tab + line
644       space_break = line.rfind(' ', 0, 80)
645       if len(line) <= 80 or 'http://' in line:
646         # Ignore normal line and URLs permitted by the style guide.
647         lines.append(line.rstrip())
648       elif not '(' in line and space_break >= 0:
649         # Break long typedefs on nearest space.
650         lines.append(line[0:space_break])
651         lines.append('    ' + line[space_break + 1:])
652       else:
653         left = line.rfind('(') + 1
654         args = line[left:].split(',')
655         orig_args = args
656         orig_left = left
657         # Try to split on '(arg1)' or '(arg1, arg2)', not '()'
658         while args[0][0] == ')':
659           left = line.rfind('(', 0, left - 1) + 1
660           if left == 0:  # No more parens, take the original option
661             args = orig_args
662             left = orig_left
663             break
664           args = line[left:].split(',')
665
666         line_max = 0
667         for arg in args:
668           if len(arg) > line_max: line_max = len(arg)
669
670         if left + line_max >= 80:
671           indent = '%s    ' % tab
672           args =  (',\n%s' % indent).join([arg.strip() for arg in args])
673           lines.append('%s\n%s%s' % (line[:left], indent, args))
674         else:
675           indent = ' ' * (left - 1)
676           args =  (',\n%s' % indent).join(args)
677           lines.append('%s%s' % (line[:left], args))
678     return '\n'.join(lines)
679
680
681   # Define a top level object.
682   def Define(self, node, releases, tabs=0, prefix='', comment=False):
683     # If this request does not match unique release, or if the release is not
684     # available (possibly deprecated) then skip.
685     unique = node.GetUniqueReleases(releases)
686     if not unique or not node.InReleases(releases):
687       return ''
688
689     self.LogEnter('Define %s tab=%d prefix="%s"' % (node,tabs,prefix))
690     declmap = dict({
691       'Enum': CGen.DefineEnum,
692       'Function': CGen.DefineMember,
693       'Interface': CGen.DefineStruct,
694       'Member': CGen.DefineMember,
695       'Struct': CGen.DefineStruct,
696       'Typedef': CGen.DefineTypedef
697     })
698
699     out = ''
700     func = declmap.get(node.cls, None)
701     if not func:
702       ErrOut.Log('Failed to define %s named %s' % (node.cls, node.GetName()))
703     define_txt = func(self, node, releases, prefix=prefix, comment=comment)
704
705     comment_txt = GetNodeComments(node, tabs=0)
706     if comment_txt and comment:
707       out += comment_txt
708     out += define_txt
709
710     indented_out = self.Indent(out, tabs)
711     self.LogExit('Exit Define')
712     return indented_out
713
714
715 # Clean a string representing an object definition and return then string
716 # as a single space delimited set of tokens.
717 def CleanString(instr):
718   instr = instr.strip()
719   instr = instr.split()
720   return ' '.join(instr)
721
722
723 # Test a file, by comparing all it's objects, with their comments.
724 def TestFile(filenode):
725   cgen = CGen()
726
727   errors = 0
728   for node in filenode.GetChildren()[2:]:
729     instr = node.GetOneOf('Comment')
730     if not instr: continue
731     instr.Dump()
732     instr = CleanString(instr.GetName())
733
734     outstr = cgen.Define(node, releases=['M14'])
735     if GetOption('verbose'):
736       print outstr + '\n'
737     outstr = CleanString(outstr)
738
739     if instr != outstr:
740       ErrOut.Log('Failed match of\n>>%s<<\nto:\n>>%s<<\nFor:\n' %
741                  (instr, outstr))
742       node.Dump(1, comments=True)
743       errors += 1
744   return errors
745
746
747 # Build and resolve the AST and compare each file individual.
748 def TestFiles(filenames):
749   if not filenames:
750     idldir = os.path.split(sys.argv[0])[0]
751     idldir = os.path.join(idldir, 'test_cgen', '*.idl')
752     filenames = glob.glob(idldir)
753
754   filenames = sorted(filenames)
755   ast = ParseFiles(filenames)
756
757   total_errs = 0
758   for filenode in ast.GetListOf('File'):
759     errs = TestFile(filenode)
760     if errs:
761       ErrOut.Log('%s test failed with %d error(s).' %
762                  (filenode.GetName(), errs))
763       total_errs += errs
764
765   if total_errs:
766     ErrOut.Log('Failed generator test.')
767   else:
768     InfoOut.Log('Passed generator test.')
769   return total_errs
770
771 def main(args):
772   filenames = ParseOptions(args)
773   if GetOption('test'):
774     return TestFiles(filenames)
775   ast = ParseFiles(filenames)
776   cgen = CGen()
777   for f in ast.GetListOf('File'):
778     if f.GetProperty('ERRORS') > 0:
779       print 'Skipping %s' % f.GetName()
780       continue
781     for node in f.GetChildren()[2:]:
782       print cgen.Define(node, ast.releases, comment=True, prefix='tst_')
783
784
785 if __name__ == '__main__':
786   sys.exit(main(sys.argv[1:]))
787