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 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. 717def 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. 724def 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. 748def 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 771def 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 785if __name__ == '__main__': 786 sys.exit(main(sys.argv[1:])) 787 788