idl_c_proto.py revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 8import glob 9import os 10import sys 11 12from idl_log import ErrOut, InfoOut, WarnOut 13from idl_node import IDLNode 14from idl_ast import IDLAst 15from idl_option import GetOption, Option, ParseOptions 16from idl_parser import ParseFiles 17 18Option('cgen_debug', 'Debug generate.') 19 20class CGenError(Exception): 21 def __init__(self, msg): 22 self.value = msg 23 24 def __str__(self): 25 return repr(self.value) 26 27 28def 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 43def 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 60def 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 69class 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 out = '' 542 if node.GetProperty('union'): 543 out += 'union %s {\n' % ( 544 self.GetStructName(node, release, include_version)) 545 else: 546 out += 'struct %s {\n' % ( 547 self.GetStructName(node, release, include_version)) 548 549 # Generate Member Functions 550 members = [] 551 for child in node.GetListOf('Member'): 552 member = self.Define(child, [release], tabs=1, comment=comment) 553 if not member: 554 continue 555 members.append(member) 556 out += '%s\n};\n' % '\n'.join(members) 557 return out 558 559 560 def DefineStruct(self, node, releases, prefix='', comment=False): 561 __pychecker__ = 'unusednames=comment,prefix' 562 self.LogEnter('DefineStruct %s' % node) 563 out = '' 564 build_list = node.GetUniqueReleases(releases) 565 566 # TODO(noelallen) : Bug 157017 finish multiversion support 567 if node.IsA('Struct'): 568 if len(build_list) != 1: 569 node.Error('Can not support multiple versions of node.') 570 assert len(build_list) == 1 571 out = self.DefineStructInternals(node, build_list[-1], 572 include_version=False, comment=True) 573 574 if node.IsA('Interface'): 575 # Build the most recent one versioned, with comments 576 out = self.DefineStructInternals(node, build_list[-1], 577 include_version=True, comment=True) 578 # Define an unversioned typedef for the most recent version 579 out += '\ntypedef struct %s %s;\n' % ( 580 self.GetStructName(node, build_list[-1], include_version=True), 581 self.GetStructName(node, build_list[-1], include_version=False)) 582 # Build the rest without comments and with the version number appended 583 for rel in build_list[0:-1]: 584 out += '\n' + self.DefineStructInternals(node, rel, 585 include_version=True, 586 comment=False) 587 588 self.LogExit('Exit DefineStruct') 589 return out 590 591 592 # 593 # Copyright and Comment 594 # 595 # Generate a comment or copyright block 596 # 597 def Copyright(self, node, cpp_style=False): 598 lines = node.GetName().split('\n') 599 if cpp_style: 600 return '//' + '\n//'.join(filter(lambda f: f != '', lines)) + '\n' 601 return CommentLines(lines) 602 603 604 def Indent(self, data, tabs=0): 605 """Handles indentation and 80-column line wrapping.""" 606 tab = ' ' * tabs 607 lines = [] 608 for line in data.split('\n'): 609 # Add indentation 610 line = tab + line 611 space_break = line.rfind(' ', 0, 80) 612 if len(line) <= 80 or 'http' in line: 613 # Ignore normal line and URLs permitted by the style guide. 614 lines.append(line.rstrip()) 615 elif not '(' in line and space_break >= 0: 616 # Break long typedefs on nearest space. 617 lines.append(line[0:space_break]) 618 lines.append(' ' + line[space_break + 1:]) 619 else: 620 left = line.rfind('(') + 1 621 args = line[left:].split(',') 622 orig_args = args 623 orig_left = left 624 # Try to split on '(arg1)' or '(arg1, arg2)', not '()' 625 while args[0][0] == ')': 626 left = line.rfind('(', 0, left - 1) + 1 627 if left == 0: # No more parens, take the original option 628 args = orig_args 629 left = orig_left 630 break 631 args = line[left:].split(',') 632 633 line_max = 0 634 for arg in args: 635 if len(arg) > line_max: line_max = len(arg) 636 637 if left + line_max >= 80: 638 indent = '%s ' % tab 639 args = (',\n%s' % indent).join([arg.strip() for arg in args]) 640 lines.append('%s\n%s%s' % (line[:left], indent, args)) 641 else: 642 indent = ' ' * (left - 1) 643 args = (',\n%s' % indent).join(args) 644 lines.append('%s%s' % (line[:left], args)) 645 return '\n'.join(lines) 646 647 648 # Define a top level object. 649 def Define(self, node, releases, tabs=0, prefix='', comment=False): 650 # If this request does not match unique release, or if the release is not 651 # available (possibly deprecated) then skip. 652 unique = node.GetUniqueReleases(releases) 653 if not unique or not node.InReleases(releases): 654 return '' 655 656 self.LogEnter('Define %s tab=%d prefix="%s"' % (node,tabs,prefix)) 657 declmap = dict({ 658 'Enum': CGen.DefineEnum, 659 'Function': CGen.DefineMember, 660 'Interface': CGen.DefineStruct, 661 'Member': CGen.DefineMember, 662 'Struct': CGen.DefineStruct, 663 'Typedef': CGen.DefineTypedef 664 }) 665 666 out = '' 667 func = declmap.get(node.cls, None) 668 if not func: 669 ErrOut.Log('Failed to define %s named %s' % (node.cls, node.GetName())) 670 define_txt = func(self, node, releases, prefix=prefix, comment=comment) 671 672 comment_txt = GetNodeComments(node, tabs=0) 673 if comment_txt and comment: 674 out += comment_txt 675 out += define_txt 676 677 indented_out = self.Indent(out, tabs) 678 self.LogExit('Exit Define') 679 return indented_out 680 681 682# Clean a string representing an object definition and return then string 683# as a single space delimited set of tokens. 684def CleanString(instr): 685 instr = instr.strip() 686 instr = instr.split() 687 return ' '.join(instr) 688 689 690# Test a file, by comparing all it's objects, with their comments. 691def TestFile(filenode): 692 cgen = CGen() 693 694 errors = 0 695 for node in filenode.GetChildren()[2:]: 696 instr = node.GetOneOf('Comment') 697 if not instr: continue 698 instr.Dump() 699 instr = CleanString(instr.GetName()) 700 701 outstr = cgen.Define(node, releases=['M14']) 702 if GetOption('verbose'): 703 print outstr + '\n' 704 outstr = CleanString(outstr) 705 706 if instr != outstr: 707 ErrOut.Log('Failed match of\n>>%s<<\nto:\n>>%s<<\nFor:\n' % 708 (instr, outstr)) 709 node.Dump(1, comments=True) 710 errors += 1 711 return errors 712 713 714# Build and resolve the AST and compare each file individual. 715def TestFiles(filenames): 716 if not filenames: 717 idldir = os.path.split(sys.argv[0])[0] 718 idldir = os.path.join(idldir, 'test_cgen', '*.idl') 719 filenames = glob.glob(idldir) 720 721 filenames = sorted(filenames) 722 ast = ParseFiles(filenames) 723 724 total_errs = 0 725 for filenode in ast.GetListOf('File'): 726 errs = TestFile(filenode) 727 if errs: 728 ErrOut.Log('%s test failed with %d error(s).' % 729 (filenode.GetName(), errs)) 730 total_errs += errs 731 732 if total_errs: 733 ErrOut.Log('Failed generator test.') 734 else: 735 InfoOut.Log('Passed generator test.') 736 return total_errs 737 738def main(args): 739 filenames = ParseOptions(args) 740 if GetOption('test'): 741 return TestFiles(filenames) 742 ast = ParseFiles(filenames) 743 cgen = CGen() 744 for f in ast.GetListOf('File'): 745 if f.GetProperty('ERRORS') > 0: 746 print 'Skipping %s' % f.GetName() 747 continue 748 for node in f.GetChildren()[2:]: 749 print cgen.Define(node, ast.releases, comment=True, prefix='tst_') 750 751 752if __name__ == '__main__': 753 sys.exit(main(sys.argv[1:])) 754 755