| OLD | NEW | 
| (Empty) |  | 
 |     1 #!/usr/bin/env python | 
 |     2 # | 
 |     3 # Copyright 2007 Neal Norwitz | 
 |     4 # Portions Copyright 2007 Google Inc. | 
 |     5 # | 
 |     6 # Licensed under the Apache License, Version 2.0 (the "License"); | 
 |     7 # you may not use this file except in compliance with the License. | 
 |     8 # You may obtain a copy of the License at | 
 |     9 # | 
 |    10 #      http://www.apache.org/licenses/LICENSE-2.0 | 
 |    11 # | 
 |    12 # Unless required by applicable law or agreed to in writing, software | 
 |    13 # distributed under the License is distributed on an "AS IS" BASIS, | 
 |    14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |    15 # See the License for the specific language governing permissions and | 
 |    16 # limitations under the License. | 
 |    17  | 
 |    18 """Generate an Abstract Syntax Tree (AST) for C++.""" | 
 |    19  | 
 |    20 __author__ = 'nnorwitz@google.com (Neal Norwitz)' | 
 |    21  | 
 |    22  | 
 |    23 # TODO: | 
 |    24 #  * Tokens should never be exported, need to convert to Nodes | 
 |    25 #    (return types, parameters, etc.) | 
 |    26 #  * Handle static class data for templatized classes | 
 |    27 #  * Handle casts (both C++ and C-style) | 
 |    28 #  * Handle conditions and loops (if/else, switch, for, while/do) | 
 |    29 # | 
 |    30 # TODO much, much later: | 
 |    31 #  * Handle #define | 
 |    32 #  * exceptions | 
 |    33  | 
 |    34  | 
 |    35 try: | 
 |    36     # Python 3.x | 
 |    37     import builtins | 
 |    38 except ImportError: | 
 |    39     # Python 2.x | 
 |    40     import __builtin__ as builtins | 
 |    41  | 
 |    42 import sys | 
 |    43 import traceback | 
 |    44  | 
 |    45 from cpp import keywords | 
 |    46 from cpp import tokenize | 
 |    47 from cpp import utils | 
 |    48  | 
 |    49  | 
 |    50 if not hasattr(builtins, 'reversed'): | 
 |    51     # Support Python 2.3 and earlier. | 
 |    52     def reversed(seq): | 
 |    53         for i in range(len(seq)-1, -1, -1): | 
 |    54             yield seq[i] | 
 |    55  | 
 |    56 if not hasattr(builtins, 'next'): | 
 |    57     # Support Python 2.5 and earlier. | 
 |    58     def next(obj): | 
 |    59         return obj.next() | 
 |    60  | 
 |    61  | 
 |    62 VISIBILITY_PUBLIC, VISIBILITY_PROTECTED, VISIBILITY_PRIVATE = range(3) | 
 |    63  | 
 |    64 FUNCTION_NONE = 0x00 | 
 |    65 FUNCTION_CONST = 0x01 | 
 |    66 FUNCTION_VIRTUAL = 0x02 | 
 |    67 FUNCTION_PURE_VIRTUAL = 0x04 | 
 |    68 FUNCTION_CTOR = 0x08 | 
 |    69 FUNCTION_DTOR = 0x10 | 
 |    70 FUNCTION_ATTRIBUTE = 0x20 | 
 |    71 FUNCTION_UNKNOWN_ANNOTATION = 0x40 | 
 |    72 FUNCTION_THROW = 0x80 | 
 |    73  | 
 |    74 """ | 
 |    75 These are currently unused.  Should really handle these properly at some point. | 
 |    76  | 
 |    77 TYPE_MODIFIER_INLINE   = 0x010000 | 
 |    78 TYPE_MODIFIER_EXTERN   = 0x020000 | 
 |    79 TYPE_MODIFIER_STATIC   = 0x040000 | 
 |    80 TYPE_MODIFIER_CONST    = 0x080000 | 
 |    81 TYPE_MODIFIER_REGISTER = 0x100000 | 
 |    82 TYPE_MODIFIER_VOLATILE = 0x200000 | 
 |    83 TYPE_MODIFIER_MUTABLE  = 0x400000 | 
 |    84  | 
 |    85 TYPE_MODIFIER_MAP = { | 
 |    86     'inline': TYPE_MODIFIER_INLINE, | 
 |    87     'extern': TYPE_MODIFIER_EXTERN, | 
 |    88     'static': TYPE_MODIFIER_STATIC, | 
 |    89     'const': TYPE_MODIFIER_CONST, | 
 |    90     'register': TYPE_MODIFIER_REGISTER, | 
 |    91     'volatile': TYPE_MODIFIER_VOLATILE, | 
 |    92     'mutable': TYPE_MODIFIER_MUTABLE, | 
 |    93     } | 
 |    94 """ | 
 |    95  | 
 |    96 _INTERNAL_TOKEN = 'internal' | 
 |    97 _NAMESPACE_POP = 'ns-pop' | 
 |    98  | 
 |    99  | 
 |   100 # TODO(nnorwitz): use this as a singleton for templated_types, etc | 
 |   101 # where we don't want to create a new empty dict each time.  It is also const. | 
 |   102 class _NullDict(object): | 
 |   103     __contains__ = lambda self: False | 
 |   104     keys = values = items = iterkeys = itervalues = iteritems = lambda self: () | 
 |   105  | 
 |   106  | 
 |   107 # TODO(nnorwitz): move AST nodes into a separate module. | 
 |   108 class Node(object): | 
 |   109     """Base AST node.""" | 
 |   110  | 
 |   111     def __init__(self, start, end): | 
 |   112         self.start = start | 
 |   113         self.end = end | 
 |   114  | 
 |   115     def IsDeclaration(self): | 
 |   116         """Returns bool if this node is a declaration.""" | 
 |   117         return False | 
 |   118  | 
 |   119     def IsDefinition(self): | 
 |   120         """Returns bool if this node is a definition.""" | 
 |   121         return False | 
 |   122  | 
 |   123     def IsExportable(self): | 
 |   124         """Returns bool if this node exportable from a header file.""" | 
 |   125         return False | 
 |   126  | 
 |   127     def Requires(self, node): | 
 |   128         """Does this AST node require the definition of the node passed in?""" | 
 |   129         return False | 
 |   130  | 
 |   131     def XXX__str__(self): | 
 |   132         return self._StringHelper(self.__class__.__name__, '') | 
 |   133  | 
 |   134     def _StringHelper(self, name, suffix): | 
 |   135         if not utils.DEBUG: | 
 |   136             return '%s(%s)' % (name, suffix) | 
 |   137         return '%s(%d, %d, %s)' % (name, self.start, self.end, suffix) | 
 |   138  | 
 |   139     def __repr__(self): | 
 |   140         return str(self) | 
 |   141  | 
 |   142  | 
 |   143 class Define(Node): | 
 |   144     def __init__(self, start, end, name, definition): | 
 |   145         Node.__init__(self, start, end) | 
 |   146         self.name = name | 
 |   147         self.definition = definition | 
 |   148  | 
 |   149     def __str__(self): | 
 |   150         value = '%s %s' % (self.name, self.definition) | 
 |   151         return self._StringHelper(self.__class__.__name__, value) | 
 |   152  | 
 |   153  | 
 |   154 class Include(Node): | 
 |   155     def __init__(self, start, end, filename, system): | 
 |   156         Node.__init__(self, start, end) | 
 |   157         self.filename = filename | 
 |   158         self.system = system | 
 |   159  | 
 |   160     def __str__(self): | 
 |   161         fmt = '"%s"' | 
 |   162         if self.system: | 
 |   163             fmt = '<%s>' | 
 |   164         return self._StringHelper(self.__class__.__name__, fmt % self.filename) | 
 |   165  | 
 |   166  | 
 |   167 class Goto(Node): | 
 |   168     def __init__(self, start, end, label): | 
 |   169         Node.__init__(self, start, end) | 
 |   170         self.label = label | 
 |   171  | 
 |   172     def __str__(self): | 
 |   173         return self._StringHelper(self.__class__.__name__, str(self.label)) | 
 |   174  | 
 |   175  | 
 |   176 class Expr(Node): | 
 |   177     def __init__(self, start, end, expr): | 
 |   178         Node.__init__(self, start, end) | 
 |   179         self.expr = expr | 
 |   180  | 
 |   181     def Requires(self, node): | 
 |   182         # TODO(nnorwitz): impl. | 
 |   183         return False | 
 |   184  | 
 |   185     def __str__(self): | 
 |   186         return self._StringHelper(self.__class__.__name__, str(self.expr)) | 
 |   187  | 
 |   188  | 
 |   189 class Return(Expr): | 
 |   190     pass | 
 |   191  | 
 |   192  | 
 |   193 class Delete(Expr): | 
 |   194     pass | 
 |   195  | 
 |   196  | 
 |   197 class Friend(Expr): | 
 |   198     def __init__(self, start, end, expr, namespace): | 
 |   199         Expr.__init__(self, start, end, expr) | 
 |   200         self.namespace = namespace[:] | 
 |   201  | 
 |   202  | 
 |   203 class Using(Node): | 
 |   204     def __init__(self, start, end, names): | 
 |   205         Node.__init__(self, start, end) | 
 |   206         self.names = names | 
 |   207  | 
 |   208     def __str__(self): | 
 |   209         return self._StringHelper(self.__class__.__name__, str(self.names)) | 
 |   210  | 
 |   211  | 
 |   212 class Parameter(Node): | 
 |   213     def __init__(self, start, end, name, parameter_type, default): | 
 |   214         Node.__init__(self, start, end) | 
 |   215         self.name = name | 
 |   216         self.type = parameter_type | 
 |   217         self.default = default | 
 |   218  | 
 |   219     def Requires(self, node): | 
 |   220         # TODO(nnorwitz): handle namespaces, etc. | 
 |   221         return self.type.name == node.name | 
 |   222  | 
 |   223     def __str__(self): | 
 |   224         name = str(self.type) | 
 |   225         suffix = '%s %s' % (name, self.name) | 
 |   226         if self.default: | 
 |   227             suffix += ' = ' + ''.join([d.name for d in self.default]) | 
 |   228         return self._StringHelper(self.__class__.__name__, suffix) | 
 |   229  | 
 |   230  | 
 |   231 class _GenericDeclaration(Node): | 
 |   232     def __init__(self, start, end, name, namespace): | 
 |   233         Node.__init__(self, start, end) | 
 |   234         self.name = name | 
 |   235         self.namespace = namespace[:] | 
 |   236  | 
 |   237     def FullName(self): | 
 |   238         prefix = '' | 
 |   239         if self.namespace and self.namespace[-1]: | 
 |   240             prefix = '::'.join(self.namespace) + '::' | 
 |   241         return prefix + self.name | 
 |   242  | 
 |   243     def _TypeStringHelper(self, suffix): | 
 |   244         if self.namespace: | 
 |   245             names = [n or '<anonymous>' for n in self.namespace] | 
 |   246             suffix += ' in ' + '::'.join(names) | 
 |   247         return self._StringHelper(self.__class__.__name__, suffix) | 
 |   248  | 
 |   249  | 
 |   250 # TODO(nnorwitz): merge with Parameter in some way? | 
 |   251 class VariableDeclaration(_GenericDeclaration): | 
 |   252     def __init__(self, start, end, name, var_type, initial_value, namespace): | 
 |   253         _GenericDeclaration.__init__(self, start, end, name, namespace) | 
 |   254         self.type = var_type | 
 |   255         self.initial_value = initial_value | 
 |   256  | 
 |   257     def Requires(self, node): | 
 |   258         # TODO(nnorwitz): handle namespaces, etc. | 
 |   259         return self.type.name == node.name | 
 |   260  | 
 |   261     def ToString(self): | 
 |   262         """Return a string that tries to reconstitute the variable decl.""" | 
 |   263         suffix = '%s %s' % (self.type, self.name) | 
 |   264         if self.initial_value: | 
 |   265             suffix += ' = ' + self.initial_value | 
 |   266         return suffix | 
 |   267  | 
 |   268     def __str__(self): | 
 |   269         return self._StringHelper(self.__class__.__name__, self.ToString()) | 
 |   270  | 
 |   271  | 
 |   272 class Typedef(_GenericDeclaration): | 
 |   273     def __init__(self, start, end, name, alias, namespace): | 
 |   274         _GenericDeclaration.__init__(self, start, end, name, namespace) | 
 |   275         self.alias = alias | 
 |   276  | 
 |   277     def IsDefinition(self): | 
 |   278         return True | 
 |   279  | 
 |   280     def IsExportable(self): | 
 |   281         return True | 
 |   282  | 
 |   283     def Requires(self, node): | 
 |   284         # TODO(nnorwitz): handle namespaces, etc. | 
 |   285         name = node.name | 
 |   286         for token in self.alias: | 
 |   287             if token is not None and name == token.name: | 
 |   288                 return True | 
 |   289         return False | 
 |   290  | 
 |   291     def __str__(self): | 
 |   292         suffix = '%s, %s' % (self.name, self.alias) | 
 |   293         return self._TypeStringHelper(suffix) | 
 |   294  | 
 |   295  | 
 |   296 class _NestedType(_GenericDeclaration): | 
 |   297     def __init__(self, start, end, name, fields, namespace): | 
 |   298         _GenericDeclaration.__init__(self, start, end, name, namespace) | 
 |   299         self.fields = fields | 
 |   300  | 
 |   301     def IsDefinition(self): | 
 |   302         return True | 
 |   303  | 
 |   304     def IsExportable(self): | 
 |   305         return True | 
 |   306  | 
 |   307     def __str__(self): | 
 |   308         suffix = '%s, {%s}' % (self.name, self.fields) | 
 |   309         return self._TypeStringHelper(suffix) | 
 |   310  | 
 |   311  | 
 |   312 class Union(_NestedType): | 
 |   313     pass | 
 |   314  | 
 |   315  | 
 |   316 class Enum(_NestedType): | 
 |   317     pass | 
 |   318  | 
 |   319  | 
 |   320 class Class(_GenericDeclaration): | 
 |   321     def __init__(self, start, end, name, bases, templated_types, body, namespace
      ): | 
 |   322         _GenericDeclaration.__init__(self, start, end, name, namespace) | 
 |   323         self.bases = bases | 
 |   324         self.body = body | 
 |   325         self.templated_types = templated_types | 
 |   326  | 
 |   327     def IsDeclaration(self): | 
 |   328         return self.bases is None and self.body is None | 
 |   329  | 
 |   330     def IsDefinition(self): | 
 |   331         return not self.IsDeclaration() | 
 |   332  | 
 |   333     def IsExportable(self): | 
 |   334         return not self.IsDeclaration() | 
 |   335  | 
 |   336     def Requires(self, node): | 
 |   337         # TODO(nnorwitz): handle namespaces, etc. | 
 |   338         if self.bases: | 
 |   339             for token_list in self.bases: | 
 |   340                 # TODO(nnorwitz): bases are tokens, do name comparision. | 
 |   341                 for token in token_list: | 
 |   342                     if token.name == node.name: | 
 |   343                         return True | 
 |   344         # TODO(nnorwitz): search in body too. | 
 |   345         return False | 
 |   346  | 
 |   347     def __str__(self): | 
 |   348         name = self.name | 
 |   349         if self.templated_types: | 
 |   350             name += '<%s>' % self.templated_types | 
 |   351         suffix = '%s, %s, %s' % (name, self.bases, self.body) | 
 |   352         return self._TypeStringHelper(suffix) | 
 |   353  | 
 |   354  | 
 |   355 class Struct(Class): | 
 |   356     pass | 
 |   357  | 
 |   358  | 
 |   359 class Function(_GenericDeclaration): | 
 |   360     def __init__(self, start, end, name, return_type, parameters, | 
 |   361                  modifiers, templated_types, body, namespace): | 
 |   362         _GenericDeclaration.__init__(self, start, end, name, namespace) | 
 |   363         converter = TypeConverter(namespace) | 
 |   364         self.return_type = converter.CreateReturnType(return_type) | 
 |   365         self.parameters = converter.ToParameters(parameters) | 
 |   366         self.modifiers = modifiers | 
 |   367         self.body = body | 
 |   368         self.templated_types = templated_types | 
 |   369  | 
 |   370     def IsDeclaration(self): | 
 |   371         return self.body is None | 
 |   372  | 
 |   373     def IsDefinition(self): | 
 |   374         return self.body is not None | 
 |   375  | 
 |   376     def IsExportable(self): | 
 |   377         if self.return_type and 'static' in self.return_type.modifiers: | 
 |   378             return False | 
 |   379         return None not in self.namespace | 
 |   380  | 
 |   381     def Requires(self, node): | 
 |   382         if self.parameters: | 
 |   383             # TODO(nnorwitz): parameters are tokens, do name comparision. | 
 |   384             for p in self.parameters: | 
 |   385                 if p.name == node.name: | 
 |   386                     return True | 
 |   387         # TODO(nnorwitz): search in body too. | 
 |   388         return False | 
 |   389  | 
 |   390     def __str__(self): | 
 |   391         # TODO(nnorwitz): add templated_types. | 
 |   392         suffix = ('%s %s(%s), 0x%02x, %s' % | 
 |   393                   (self.return_type, self.name, self.parameters, | 
 |   394                    self.modifiers, self.body)) | 
 |   395         return self._TypeStringHelper(suffix) | 
 |   396  | 
 |   397  | 
 |   398 class Method(Function): | 
 |   399     def __init__(self, start, end, name, in_class, return_type, parameters, | 
 |   400                  modifiers, templated_types, body, namespace): | 
 |   401         Function.__init__(self, start, end, name, return_type, parameters, | 
 |   402                           modifiers, templated_types, body, namespace) | 
 |   403         # TODO(nnorwitz): in_class could also be a namespace which can | 
 |   404         # mess up finding functions properly. | 
 |   405         self.in_class = in_class | 
 |   406  | 
 |   407  | 
 |   408 class Type(_GenericDeclaration): | 
 |   409     """Type used for any variable (eg class, primitive, struct, etc).""" | 
 |   410  | 
 |   411     def __init__(self, start, end, name, templated_types, modifiers, | 
 |   412                  reference, pointer, array): | 
 |   413         """ | 
 |   414         Args: | 
 |   415           name: str name of main type | 
 |   416           templated_types: [Class (Type?)] template type info between <> | 
 |   417           modifiers: [str] type modifiers (keywords) eg, const, mutable, etc. | 
 |   418           reference, pointer, array: bools | 
 |   419         """ | 
 |   420         _GenericDeclaration.__init__(self, start, end, name, []) | 
 |   421         self.templated_types = templated_types | 
 |   422         if not name and modifiers: | 
 |   423             self.name = modifiers.pop() | 
 |   424         self.modifiers = modifiers | 
 |   425         self.reference = reference | 
 |   426         self.pointer = pointer | 
 |   427         self.array = array | 
 |   428  | 
 |   429     def __str__(self): | 
 |   430         prefix = '' | 
 |   431         if self.modifiers: | 
 |   432             prefix = ' '.join(self.modifiers) + ' ' | 
 |   433         name = str(self.name) | 
 |   434         if self.templated_types: | 
 |   435             name += '<%s>' % self.templated_types | 
 |   436         suffix = prefix + name | 
 |   437         if self.reference: | 
 |   438             suffix += '&' | 
 |   439         if self.pointer: | 
 |   440             suffix += '*' | 
 |   441         if self.array: | 
 |   442             suffix += '[]' | 
 |   443         return self._TypeStringHelper(suffix) | 
 |   444  | 
 |   445     # By definition, Is* are always False.  A Type can only exist in | 
 |   446     # some sort of variable declaration, parameter, or return value. | 
 |   447     def IsDeclaration(self): | 
 |   448         return False | 
 |   449  | 
 |   450     def IsDefinition(self): | 
 |   451         return False | 
 |   452  | 
 |   453     def IsExportable(self): | 
 |   454         return False | 
 |   455  | 
 |   456  | 
 |   457 class TypeConverter(object): | 
 |   458  | 
 |   459     def __init__(self, namespace_stack): | 
 |   460         self.namespace_stack = namespace_stack | 
 |   461  | 
 |   462     def _GetTemplateEnd(self, tokens, start): | 
 |   463         count = 1 | 
 |   464         end = start | 
 |   465         while 1: | 
 |   466             token = tokens[end] | 
 |   467             end += 1 | 
 |   468             if token.name == '<': | 
 |   469                 count += 1 | 
 |   470             elif token.name == '>': | 
 |   471                 count -= 1 | 
 |   472                 if count == 0: | 
 |   473                     break | 
 |   474         return tokens[start:end-1], end | 
 |   475  | 
 |   476     def ToType(self, tokens): | 
 |   477         """Convert [Token,...] to [Class(...), ] useful for base classes. | 
 |   478         For example, code like class Foo : public Bar<x, y> { ... }; | 
 |   479         the "Bar<x, y>" portion gets converted to an AST. | 
 |   480  | 
 |   481         Returns: | 
 |   482           [Class(...), ...] | 
 |   483         """ | 
 |   484         result = [] | 
 |   485         name_tokens = [] | 
 |   486         reference = pointer = array = False | 
 |   487  | 
 |   488         def AddType(templated_types): | 
 |   489             # Partition tokens into name and modifier tokens. | 
 |   490             names = [] | 
 |   491             modifiers = [] | 
 |   492             for t in name_tokens: | 
 |   493                 if keywords.IsKeyword(t.name): | 
 |   494                     modifiers.append(t.name) | 
 |   495                 else: | 
 |   496                     names.append(t.name) | 
 |   497             name = ''.join(names) | 
 |   498             result.append(Type(name_tokens[0].start, name_tokens[-1].end, | 
 |   499                                name, templated_types, modifiers, | 
 |   500                                reference, pointer, array)) | 
 |   501             del name_tokens[:] | 
 |   502  | 
 |   503         i = 0 | 
 |   504         end = len(tokens) | 
 |   505         while i < end: | 
 |   506             token = tokens[i] | 
 |   507             if token.name == '<': | 
 |   508                 new_tokens, new_end = self._GetTemplateEnd(tokens, i+1) | 
 |   509                 AddType(self.ToType(new_tokens)) | 
 |   510                 # If there is a comma after the template, we need to consume | 
 |   511                 # that here otherwise it becomes part of the name. | 
 |   512                 i = new_end | 
 |   513                 reference = pointer = array = False | 
 |   514             elif token.name == ',': | 
 |   515                 AddType([]) | 
 |   516                 reference = pointer = array = False | 
 |   517             elif token.name == '*': | 
 |   518                 pointer = True | 
 |   519             elif token.name == '&': | 
 |   520                 reference = True | 
 |   521             elif token.name == '[': | 
 |   522                pointer = True | 
 |   523             elif token.name == ']': | 
 |   524                 pass | 
 |   525             else: | 
 |   526                 name_tokens.append(token) | 
 |   527             i += 1 | 
 |   528  | 
 |   529         if name_tokens: | 
 |   530             # No '<' in the tokens, just a simple name and no template. | 
 |   531             AddType([]) | 
 |   532         return result | 
 |   533  | 
 |   534     def DeclarationToParts(self, parts, needs_name_removed): | 
 |   535         name = None | 
 |   536         default = [] | 
 |   537         if needs_name_removed: | 
 |   538             # Handle default (initial) values properly. | 
 |   539             for i, t in enumerate(parts): | 
 |   540                 if t.name == '=': | 
 |   541                     default = parts[i+1:] | 
 |   542                     name = parts[i-1].name | 
 |   543                     if name == ']' and parts[i-2].name == '[': | 
 |   544                         name = parts[i-3].name | 
 |   545                         i -= 1 | 
 |   546                     parts = parts[:i-1] | 
 |   547                     break | 
 |   548             else: | 
 |   549                 if parts[-1].token_type == tokenize.NAME: | 
 |   550                     name = parts.pop().name | 
 |   551                 else: | 
 |   552                     # TODO(nnorwitz): this is a hack that happens for code like | 
 |   553                     # Register(Foo<T>); where it thinks this is a function call | 
 |   554                     # but it's actually a declaration. | 
 |   555                     name = '???' | 
 |   556         modifiers = [] | 
 |   557         type_name = [] | 
 |   558         other_tokens = [] | 
 |   559         templated_types = [] | 
 |   560         i = 0 | 
 |   561         end = len(parts) | 
 |   562         while i < end: | 
 |   563             p = parts[i] | 
 |   564             if keywords.IsKeyword(p.name): | 
 |   565                 modifiers.append(p.name) | 
 |   566             elif p.name == '<': | 
 |   567                 templated_tokens, new_end = self._GetTemplateEnd(parts, i+1) | 
 |   568                 templated_types = self.ToType(templated_tokens) | 
 |   569                 i = new_end - 1 | 
 |   570                 # Don't add a spurious :: to data members being initialized. | 
 |   571                 next_index = i + 1 | 
 |   572                 if next_index < end and parts[next_index].name == '::': | 
 |   573                     i += 1 | 
 |   574             elif p.name in ('[', ']', '='): | 
 |   575                 # These are handled elsewhere. | 
 |   576                 other_tokens.append(p) | 
 |   577             elif p.name not in ('*', '&', '>'): | 
 |   578                 # Ensure that names have a space between them. | 
 |   579                 if (type_name and type_name[-1].token_type == tokenize.NAME and | 
 |   580                     p.token_type == tokenize.NAME): | 
 |   581                     type_name.append(tokenize.Token(tokenize.SYNTAX, ' ', 0, 0)) | 
 |   582                 type_name.append(p) | 
 |   583             else: | 
 |   584                 other_tokens.append(p) | 
 |   585             i += 1 | 
 |   586         type_name = ''.join([t.name for t in type_name]) | 
 |   587         return name, type_name, templated_types, modifiers, default, other_token
      s | 
 |   588  | 
 |   589     def ToParameters(self, tokens): | 
 |   590         if not tokens: | 
 |   591             return [] | 
 |   592  | 
 |   593         result = [] | 
 |   594         name = type_name = '' | 
 |   595         type_modifiers = [] | 
 |   596         pointer = reference = array = False | 
 |   597         first_token = None | 
 |   598         default = [] | 
 |   599  | 
 |   600         def AddParameter(): | 
 |   601             if default: | 
 |   602                 del default[0]  # Remove flag. | 
 |   603             end = type_modifiers[-1].end | 
 |   604             parts = self.DeclarationToParts(type_modifiers, True) | 
 |   605             (name, type_name, templated_types, modifiers, | 
 |   606              unused_default, unused_other_tokens) = parts | 
 |   607             parameter_type = Type(first_token.start, first_token.end, | 
 |   608                                   type_name, templated_types, modifiers, | 
 |   609                                   reference, pointer, array) | 
 |   610             p = Parameter(first_token.start, end, name, | 
 |   611                           parameter_type, default) | 
 |   612             result.append(p) | 
 |   613  | 
 |   614         template_count = 0 | 
 |   615         for s in tokens: | 
 |   616             if not first_token: | 
 |   617                 first_token = s | 
 |   618             if s.name == '<': | 
 |   619                 template_count += 1 | 
 |   620             elif s.name == '>': | 
 |   621                 template_count -= 1 | 
 |   622             if template_count > 0: | 
 |   623                 type_modifiers.append(s) | 
 |   624                 continue | 
 |   625  | 
 |   626             if s.name == ',': | 
 |   627                 AddParameter() | 
 |   628                 name = type_name = '' | 
 |   629                 type_modifiers = [] | 
 |   630                 pointer = reference = array = False | 
 |   631                 first_token = None | 
 |   632                 default = [] | 
 |   633             elif s.name == '*': | 
 |   634                 pointer = True | 
 |   635             elif s.name == '&': | 
 |   636                 reference = True | 
 |   637             elif s.name == '[': | 
 |   638                 array = True | 
 |   639             elif s.name == ']': | 
 |   640                 pass  # Just don't add to type_modifiers. | 
 |   641             elif s.name == '=': | 
 |   642                 # Got a default value.  Add any value (None) as a flag. | 
 |   643                 default.append(None) | 
 |   644             elif default: | 
 |   645                 default.append(s) | 
 |   646             else: | 
 |   647                 type_modifiers.append(s) | 
 |   648         AddParameter() | 
 |   649         return result | 
 |   650  | 
 |   651     def CreateReturnType(self, return_type_seq): | 
 |   652         if not return_type_seq: | 
 |   653             return None | 
 |   654         start = return_type_seq[0].start | 
 |   655         end = return_type_seq[-1].end | 
 |   656         _, name, templated_types, modifiers, default, other_tokens = \ | 
 |   657            self.DeclarationToParts(return_type_seq, False) | 
 |   658         names = [n.name for n in other_tokens] | 
 |   659         reference = '&' in names | 
 |   660         pointer = '*' in names | 
 |   661         array = '[' in names | 
 |   662         return Type(start, end, name, templated_types, modifiers, | 
 |   663                     reference, pointer, array) | 
 |   664  | 
 |   665     def GetTemplateIndices(self, names): | 
 |   666         # names is a list of strings. | 
 |   667         start = names.index('<') | 
 |   668         end = len(names) - 1 | 
 |   669         while end > 0: | 
 |   670             if names[end] == '>': | 
 |   671                 break | 
 |   672             end -= 1 | 
 |   673         return start, end+1 | 
 |   674  | 
 |   675 class AstBuilder(object): | 
 |   676     def __init__(self, token_stream, filename, in_class='', visibility=None, | 
 |   677                  namespace_stack=[]): | 
 |   678         self.tokens = token_stream | 
 |   679         self.filename = filename | 
 |   680         # TODO(nnorwitz): use a better data structure (deque) for the queue. | 
 |   681         # Switching directions of the "queue" improved perf by about 25%. | 
 |   682         # Using a deque should be even better since we access from both sides. | 
 |   683         self.token_queue = [] | 
 |   684         self.namespace_stack = namespace_stack[:] | 
 |   685         self.in_class = in_class | 
 |   686         if in_class is None: | 
 |   687             self.in_class_name_only = None | 
 |   688         else: | 
 |   689             self.in_class_name_only = in_class.split('::')[-1] | 
 |   690         self.visibility = visibility | 
 |   691         self.in_function = False | 
 |   692         self.current_token = None | 
 |   693         # Keep the state whether we are currently handling a typedef or not. | 
 |   694         self._handling_typedef = False | 
 |   695  | 
 |   696         self.converter = TypeConverter(self.namespace_stack) | 
 |   697  | 
 |   698     def HandleError(self, msg, token): | 
 |   699         printable_queue = list(reversed(self.token_queue[-20:])) | 
 |   700         sys.stderr.write('Got %s in %s @ %s %s\n' % | 
 |   701                          (msg, self.filename, token, printable_queue)) | 
 |   702  | 
 |   703     def Generate(self): | 
 |   704         while 1: | 
 |   705             token = self._GetNextToken() | 
 |   706             if not token: | 
 |   707                 break | 
 |   708  | 
 |   709             # Get the next token. | 
 |   710             self.current_token = token | 
 |   711  | 
 |   712             # Dispatch on the next token type. | 
 |   713             if token.token_type == _INTERNAL_TOKEN: | 
 |   714                 if token.name == _NAMESPACE_POP: | 
 |   715                     self.namespace_stack.pop() | 
 |   716                 continue | 
 |   717  | 
 |   718             try: | 
 |   719                 result = self._GenerateOne(token) | 
 |   720                 if result is not None: | 
 |   721                     yield result | 
 |   722             except: | 
 |   723                 self.HandleError('exception', token) | 
 |   724                 raise | 
 |   725  | 
 |   726     def _CreateVariable(self, pos_token, name, type_name, type_modifiers, | 
 |   727                         ref_pointer_name_seq, templated_types, value=None): | 
 |   728         reference = '&' in ref_pointer_name_seq | 
 |   729         pointer = '*' in ref_pointer_name_seq | 
 |   730         array = '[' in ref_pointer_name_seq | 
 |   731         var_type = Type(pos_token.start, pos_token.end, type_name, | 
 |   732                         templated_types, type_modifiers, | 
 |   733                         reference, pointer, array) | 
 |   734         return VariableDeclaration(pos_token.start, pos_token.end, | 
 |   735                                    name, var_type, value, self.namespace_stack) | 
 |   736  | 
 |   737     def _GenerateOne(self, token): | 
 |   738         if token.token_type == tokenize.NAME: | 
 |   739             if (keywords.IsKeyword(token.name) and | 
 |   740                 not keywords.IsBuiltinType(token.name)): | 
 |   741                 method = getattr(self, 'handle_' + token.name) | 
 |   742                 return method() | 
 |   743             elif token.name == self.in_class_name_only: | 
 |   744                 # The token name is the same as the class, must be a ctor if | 
 |   745                 # there is a paren.  Otherwise, it's the return type. | 
 |   746                 # Peek ahead to get the next token to figure out which. | 
 |   747                 next = self._GetNextToken() | 
 |   748                 self._AddBackToken(next) | 
 |   749                 if next.token_type == tokenize.SYNTAX and next.name == '(': | 
 |   750                     return self._GetMethod([token], FUNCTION_CTOR, None, True) | 
 |   751                 # Fall through--handle like any other method. | 
 |   752  | 
 |   753             # Handle data or function declaration/definition. | 
 |   754             syntax = tokenize.SYNTAX | 
 |   755             temp_tokens, last_token = \ | 
 |   756                 self._GetVarTokensUpTo(syntax, '(', ';', '{', '[') | 
 |   757             temp_tokens.insert(0, token) | 
 |   758             if last_token.name == '(': | 
 |   759                 # If there is an assignment before the paren, | 
 |   760                 # this is an expression, not a method. | 
 |   761                 expr = bool([e for e in temp_tokens if e.name == '=']) | 
 |   762                 if expr: | 
 |   763                     new_temp = self._GetTokensUpTo(tokenize.SYNTAX, ';') | 
 |   764                     temp_tokens.append(last_token) | 
 |   765                     temp_tokens.extend(new_temp) | 
 |   766                     last_token = tokenize.Token(tokenize.SYNTAX, ';', 0, 0) | 
 |   767  | 
 |   768             if last_token.name == '[': | 
 |   769                 # Handle array, this isn't a method, unless it's an operator. | 
 |   770                 # TODO(nnorwitz): keep the size somewhere. | 
 |   771                 # unused_size = self._GetTokensUpTo(tokenize.SYNTAX, ']') | 
 |   772                 temp_tokens.append(last_token) | 
 |   773                 if temp_tokens[-2].name == 'operator': | 
 |   774                     temp_tokens.append(self._GetNextToken()) | 
 |   775                 else: | 
 |   776                     temp_tokens2, last_token = \ | 
 |   777                         self._GetVarTokensUpTo(tokenize.SYNTAX, ';') | 
 |   778                     temp_tokens.extend(temp_tokens2) | 
 |   779  | 
 |   780             if last_token.name == ';': | 
 |   781                 # Handle data, this isn't a method. | 
 |   782                 parts = self.converter.DeclarationToParts(temp_tokens, True) | 
 |   783                 (name, type_name, templated_types, modifiers, default, | 
 |   784                  unused_other_tokens) = parts | 
 |   785                        | 
 |   786                 t0 = temp_tokens[0] | 
 |   787                 names = [t.name for t in temp_tokens] | 
 |   788                 if templated_types: | 
 |   789                     start, end = self.converter.GetTemplateIndices(names) | 
 |   790                     names = names[:start] + names[end:] | 
 |   791                 default = ''.join([t.name for t in default]) | 
 |   792                 return self._CreateVariable(t0, name, type_name, modifiers, | 
 |   793                                             names, templated_types, default) | 
 |   794             if last_token.name == '{': | 
 |   795                 self._AddBackTokens(temp_tokens[1:]) | 
 |   796                 self._AddBackToken(last_token) | 
 |   797                 method_name = temp_tokens[0].name | 
 |   798                 method = getattr(self, 'handle_' + method_name, None) | 
 |   799                 if not method: | 
 |   800                     # Must be declaring a variable. | 
 |   801                     # TODO(nnorwitz): handle the declaration. | 
 |   802                     return None | 
 |   803                 return method() | 
 |   804             return self._GetMethod(temp_tokens, 0, None, False) | 
 |   805         elif token.token_type == tokenize.SYNTAX: | 
 |   806             if token.name == '~' and self.in_class: | 
 |   807                 # Must be a dtor (probably not in method body). | 
 |   808                 token = self._GetNextToken() | 
 |   809                 # self.in_class can contain A::Name, but the dtor will only | 
 |   810                 # be Name.  Make sure to compare against the right value. | 
 |   811                 if (token.token_type == tokenize.NAME and | 
 |   812                     token.name == self.in_class_name_only): | 
 |   813                     return self._GetMethod([token], FUNCTION_DTOR, None, True) | 
 |   814             # TODO(nnorwitz): handle a lot more syntax. | 
 |   815         elif token.token_type == tokenize.PREPROCESSOR: | 
 |   816             # TODO(nnorwitz): handle more preprocessor directives. | 
 |   817             # token starts with a #, so remove it and strip whitespace. | 
 |   818             name = token.name[1:].lstrip() | 
 |   819             if name.startswith('include'): | 
 |   820                 # Remove "include". | 
 |   821                 name = name[7:].strip() | 
 |   822                 assert name | 
 |   823                 # Handle #include \<newline> "header-on-second-line.h". | 
 |   824                 if name.startswith('\\'): | 
 |   825                     name = name[1:].strip() | 
 |   826                 assert name[0] in '<"', token | 
 |   827                 assert name[-1] in '>"', token | 
 |   828                 system = name[0] == '<' | 
 |   829                 filename = name[1:-1] | 
 |   830                 return Include(token.start, token.end, filename, system) | 
 |   831             if name.startswith('define'): | 
 |   832                 # Remove "define". | 
 |   833                 name = name[6:].strip() | 
 |   834                 assert name | 
 |   835                 value = '' | 
 |   836                 for i, c in enumerate(name): | 
 |   837                     if c.isspace(): | 
 |   838                         value = name[i:].lstrip() | 
 |   839                         name = name[:i] | 
 |   840                         break | 
 |   841                 return Define(token.start, token.end, name, value) | 
 |   842             if name.startswith('if') and name[2:3].isspace(): | 
 |   843                 condition = name[3:].strip() | 
 |   844                 if condition.startswith('0') or condition.startswith('(0)'): | 
 |   845                     self._SkipIf0Blocks() | 
 |   846         return None | 
 |   847  | 
 |   848     def _GetTokensUpTo(self, expected_token_type, expected_token): | 
 |   849         return self._GetVarTokensUpTo(expected_token_type, expected_token)[0] | 
 |   850  | 
 |   851     def _GetVarTokensUpTo(self, expected_token_type, *expected_tokens): | 
 |   852         last_token = self._GetNextToken() | 
 |   853         tokens = [] | 
 |   854         while (last_token.token_type != expected_token_type or | 
 |   855                last_token.name not in expected_tokens): | 
 |   856             tokens.append(last_token) | 
 |   857             last_token = self._GetNextToken() | 
 |   858         return tokens, last_token | 
 |   859  | 
 |   860     # TODO(nnorwitz): remove _IgnoreUpTo() it shouldn't be necesary. | 
 |   861     def _IgnoreUpTo(self, token_type, token): | 
 |   862         unused_tokens = self._GetTokensUpTo(token_type, token) | 
 |   863  | 
 |   864     def _SkipIf0Blocks(self): | 
 |   865         count = 1 | 
 |   866         while 1: | 
 |   867             token = self._GetNextToken() | 
 |   868             if token.token_type != tokenize.PREPROCESSOR: | 
 |   869                 continue | 
 |   870  | 
 |   871             name = token.name[1:].lstrip() | 
 |   872             if name.startswith('endif'): | 
 |   873                 count -= 1 | 
 |   874                 if count == 0: | 
 |   875                     break | 
 |   876             elif name.startswith('if'): | 
 |   877                 count += 1 | 
 |   878  | 
 |   879     def _GetMatchingChar(self, open_paren, close_paren, GetNextToken=None): | 
 |   880         if GetNextToken is None: | 
 |   881             GetNextToken = self._GetNextToken | 
 |   882         # Assumes the current token is open_paren and we will consume | 
 |   883         # and return up to the close_paren. | 
 |   884         count = 1 | 
 |   885         token = GetNextToken() | 
 |   886         while 1: | 
 |   887             if token.token_type == tokenize.SYNTAX: | 
 |   888                 if token.name == open_paren: | 
 |   889                     count += 1 | 
 |   890                 elif token.name == close_paren: | 
 |   891                     count -= 1 | 
 |   892                     if count == 0: | 
 |   893                         break | 
 |   894             yield token | 
 |   895             token = GetNextToken() | 
 |   896         yield token | 
 |   897  | 
 |   898     def _GetParameters(self): | 
 |   899         return self._GetMatchingChar('(', ')') | 
 |   900  | 
 |   901     def GetScope(self): | 
 |   902         return self._GetMatchingChar('{', '}') | 
 |   903  | 
 |   904     def _GetNextToken(self): | 
 |   905         if self.token_queue: | 
 |   906             return self.token_queue.pop() | 
 |   907         return next(self.tokens) | 
 |   908  | 
 |   909     def _AddBackToken(self, token): | 
 |   910         if token.whence == tokenize.WHENCE_STREAM: | 
 |   911             token.whence = tokenize.WHENCE_QUEUE | 
 |   912             self.token_queue.insert(0, token) | 
 |   913         else: | 
 |   914             assert token.whence == tokenize.WHENCE_QUEUE, token | 
 |   915             self.token_queue.append(token) | 
 |   916  | 
 |   917     def _AddBackTokens(self, tokens): | 
 |   918         if tokens: | 
 |   919             if tokens[-1].whence == tokenize.WHENCE_STREAM: | 
 |   920                 for token in tokens: | 
 |   921                     token.whence = tokenize.WHENCE_QUEUE | 
 |   922                 self.token_queue[:0] = reversed(tokens) | 
 |   923             else: | 
 |   924                 assert tokens[-1].whence == tokenize.WHENCE_QUEUE, tokens | 
 |   925                 self.token_queue.extend(reversed(tokens)) | 
 |   926  | 
 |   927     def GetName(self, seq=None): | 
 |   928         """Returns ([tokens], next_token_info).""" | 
 |   929         GetNextToken = self._GetNextToken | 
 |   930         if seq is not None: | 
 |   931             it = iter(seq) | 
 |   932             GetNextToken = lambda: next(it) | 
 |   933         next_token = GetNextToken() | 
 |   934         tokens = [] | 
 |   935         last_token_was_name = False | 
 |   936         while (next_token.token_type == tokenize.NAME or | 
 |   937                (next_token.token_type == tokenize.SYNTAX and | 
 |   938                 next_token.name in ('::', '<'))): | 
 |   939             # Two NAMEs in a row means the identifier should terminate. | 
 |   940             # It's probably some sort of variable declaration. | 
 |   941             if last_token_was_name and next_token.token_type == tokenize.NAME: | 
 |   942                 break | 
 |   943             last_token_was_name = next_token.token_type == tokenize.NAME | 
 |   944             tokens.append(next_token) | 
 |   945             # Handle templated names. | 
 |   946             if next_token.name == '<': | 
 |   947                 tokens.extend(self._GetMatchingChar('<', '>', GetNextToken)) | 
 |   948                 last_token_was_name = True | 
 |   949             next_token = GetNextToken() | 
 |   950         return tokens, next_token | 
 |   951  | 
 |   952     def GetMethod(self, modifiers, templated_types): | 
 |   953         return_type_and_name = self._GetTokensUpTo(tokenize.SYNTAX, '(') | 
 |   954         assert len(return_type_and_name) >= 1 | 
 |   955         return self._GetMethod(return_type_and_name, modifiers, templated_types, | 
 |   956                                False) | 
 |   957  | 
 |   958     def _GetMethod(self, return_type_and_name, modifiers, templated_types, | 
 |   959                    get_paren): | 
 |   960         template_portion = None | 
 |   961         if get_paren: | 
 |   962             token = self._GetNextToken() | 
 |   963             assert token.token_type == tokenize.SYNTAX, token | 
 |   964             if token.name == '<': | 
 |   965                 # Handle templatized dtors. | 
 |   966                 template_portion = [token] | 
 |   967                 template_portion.extend(self._GetMatchingChar('<', '>')) | 
 |   968                 token = self._GetNextToken() | 
 |   969             assert token.token_type == tokenize.SYNTAX, token | 
 |   970             assert token.name == '(', token | 
 |   971  | 
 |   972         name = return_type_and_name.pop() | 
 |   973         # Handle templatized ctors. | 
 |   974         if name.name == '>': | 
 |   975             index = 1 | 
 |   976             while return_type_and_name[index].name != '<': | 
 |   977                 index += 1 | 
 |   978             template_portion = return_type_and_name[index:] + [name] | 
 |   979             del return_type_and_name[index:] | 
 |   980             name = return_type_and_name.pop() | 
 |   981         elif name.name == ']': | 
 |   982             rt = return_type_and_name | 
 |   983             assert rt[-1].name == '[', return_type_and_name | 
 |   984             assert rt[-2].name == 'operator', return_type_and_name | 
 |   985             name_seq = return_type_and_name[-2:] | 
 |   986             del return_type_and_name[-2:] | 
 |   987             name = tokenize.Token(tokenize.NAME, 'operator[]', | 
 |   988                                   name_seq[0].start, name.end) | 
 |   989             # Get the open paren so _GetParameters() below works. | 
 |   990             unused_open_paren = self._GetNextToken() | 
 |   991  | 
 |   992         # TODO(nnorwitz): store template_portion. | 
 |   993         return_type = return_type_and_name | 
 |   994         indices = name | 
 |   995         if return_type: | 
 |   996             indices = return_type[0] | 
 |   997  | 
 |   998         # Force ctor for templatized ctors. | 
 |   999         if name.name == self.in_class and not modifiers: | 
 |  1000             modifiers |= FUNCTION_CTOR | 
 |  1001         parameters = list(self._GetParameters()) | 
 |  1002         del parameters[-1]              # Remove trailing ')'. | 
 |  1003  | 
 |  1004         # Handling operator() is especially weird. | 
 |  1005         if name.name == 'operator' and not parameters: | 
 |  1006             token = self._GetNextToken() | 
 |  1007             assert token.name == '(', token | 
 |  1008             parameters = list(self._GetParameters()) | 
 |  1009             del parameters[-1]          # Remove trailing ')'. | 
 |  1010  | 
 |  1011         token = self._GetNextToken() | 
 |  1012         while token.token_type == tokenize.NAME: | 
 |  1013             modifier_token = token | 
 |  1014             token = self._GetNextToken() | 
 |  1015             if modifier_token.name == 'const': | 
 |  1016                 modifiers |= FUNCTION_CONST | 
 |  1017             elif modifier_token.name == '__attribute__': | 
 |  1018                 # TODO(nnorwitz): handle more __attribute__ details. | 
 |  1019                 modifiers |= FUNCTION_ATTRIBUTE | 
 |  1020                 assert token.name == '(', token | 
 |  1021                 # Consume everything between the (parens). | 
 |  1022                 unused_tokens = list(self._GetMatchingChar('(', ')')) | 
 |  1023                 token = self._GetNextToken() | 
 |  1024             elif modifier_token.name == 'throw': | 
 |  1025                 modifiers |= FUNCTION_THROW | 
 |  1026                 assert token.name == '(', token | 
 |  1027                 # Consume everything between the (parens). | 
 |  1028                 unused_tokens = list(self._GetMatchingChar('(', ')')) | 
 |  1029                 token = self._GetNextToken() | 
 |  1030             elif modifier_token.name == modifier_token.name.upper(): | 
 |  1031                 # HACK(nnorwitz):  assume that all upper-case names | 
 |  1032                 # are some macro we aren't expanding. | 
 |  1033                 modifiers |= FUNCTION_UNKNOWN_ANNOTATION | 
 |  1034             else: | 
 |  1035                 self.HandleError('unexpected token', modifier_token) | 
 |  1036  | 
 |  1037         assert token.token_type == tokenize.SYNTAX, token | 
 |  1038         # Handle ctor initializers. | 
 |  1039         if token.name == ':': | 
 |  1040             # TODO(nnorwitz): anything else to handle for initializer list? | 
 |  1041             while token.name != ';' and token.name != '{': | 
 |  1042                 token = self._GetNextToken() | 
 |  1043  | 
 |  1044         # Handle pointer to functions that are really data but look | 
 |  1045         # like method declarations. | 
 |  1046         if token.name == '(': | 
 |  1047             if parameters[0].name == '*': | 
 |  1048                 # name contains the return type. | 
 |  1049                 name = parameters.pop() | 
 |  1050                 # parameters contains the name of the data. | 
 |  1051                 modifiers = [p.name for p in parameters] | 
 |  1052                 # Already at the ( to open the parameter list. | 
 |  1053                 function_parameters = list(self._GetMatchingChar('(', ')')) | 
 |  1054                 del function_parameters[-1]  # Remove trailing ')'. | 
 |  1055                 # TODO(nnorwitz): store the function_parameters. | 
 |  1056                 token = self._GetNextToken() | 
 |  1057                 assert token.token_type == tokenize.SYNTAX, token | 
 |  1058                 assert token.name == ';', token | 
 |  1059                 return self._CreateVariable(indices, name.name, indices.name, | 
 |  1060                                             modifiers, '', None) | 
 |  1061             # At this point, we got something like: | 
 |  1062             #  return_type (type::*name_)(params); | 
 |  1063             # This is a data member called name_ that is a function pointer. | 
 |  1064             # With this code: void (sq_type::*field_)(string&); | 
 |  1065             # We get: name=void return_type=[] parameters=sq_type ... field_ | 
 |  1066             # TODO(nnorwitz): is return_type always empty? | 
 |  1067             # TODO(nnorwitz): this isn't even close to being correct. | 
 |  1068             # Just put in something so we don't crash and can move on. | 
 |  1069             real_name = parameters[-1] | 
 |  1070             modifiers = [p.name for p in self._GetParameters()] | 
 |  1071             del modifiers[-1]           # Remove trailing ')'. | 
 |  1072             return self._CreateVariable(indices, real_name.name, indices.name, | 
 |  1073                                         modifiers, '', None) | 
 |  1074  | 
 |  1075         if token.name == '{': | 
 |  1076             body = list(self.GetScope()) | 
 |  1077             del body[-1]                # Remove trailing '}'. | 
 |  1078         else: | 
 |  1079             body = None | 
 |  1080             if token.name == '=': | 
 |  1081                 token = self._GetNextToken() | 
 |  1082                 assert token.token_type == tokenize.CONSTANT, token | 
 |  1083                 assert token.name == '0', token | 
 |  1084                 modifiers |= FUNCTION_PURE_VIRTUAL | 
 |  1085                 token = self._GetNextToken() | 
 |  1086  | 
 |  1087             if token.name == '[': | 
 |  1088                 # TODO(nnorwitz): store tokens and improve parsing. | 
 |  1089                 # template <typename T, size_t N> char (&ASH(T (&seq)[N]))[N]; | 
 |  1090                 tokens = list(self._GetMatchingChar('[', ']')) | 
 |  1091                 token = self._GetNextToken() | 
 |  1092  | 
 |  1093             assert token.name == ';', (token, return_type_and_name, parameters) | 
 |  1094  | 
 |  1095         # Looks like we got a method, not a function. | 
 |  1096         if len(return_type) > 2 and return_type[-1].name == '::': | 
 |  1097             return_type, in_class = \ | 
 |  1098                          self._GetReturnTypeAndClassName(return_type) | 
 |  1099             return Method(indices.start, indices.end, name.name, in_class, | 
 |  1100                           return_type, parameters, modifiers, templated_types, | 
 |  1101                           body, self.namespace_stack) | 
 |  1102         return Function(indices.start, indices.end, name.name, return_type, | 
 |  1103                         parameters, modifiers, templated_types, body, | 
 |  1104                         self.namespace_stack) | 
 |  1105  | 
 |  1106     def _GetReturnTypeAndClassName(self, token_seq): | 
 |  1107         # Splitting the return type from the class name in a method | 
 |  1108         # can be tricky.  For example, Return::Type::Is::Hard::To::Find(). | 
 |  1109         # Where is the return type and where is the class name? | 
 |  1110         # The heuristic used is to pull the last name as the class name. | 
 |  1111         # This includes all the templated type info. | 
 |  1112         # TODO(nnorwitz): if there is only One name like in the | 
 |  1113         # example above, punt and assume the last bit is the class name. | 
 |  1114  | 
 |  1115         # Ignore a :: prefix, if exists so we can find the first real name. | 
 |  1116         i = 0 | 
 |  1117         if token_seq[0].name == '::': | 
 |  1118             i = 1 | 
 |  1119         # Ignore a :: suffix, if exists. | 
 |  1120         end = len(token_seq) - 1 | 
 |  1121         if token_seq[end-1].name == '::': | 
 |  1122             end -= 1 | 
 |  1123  | 
 |  1124         # Make a copy of the sequence so we can append a sentinel | 
 |  1125         # value. This is required for GetName will has to have some | 
 |  1126         # terminating condition beyond the last name. | 
 |  1127         seq_copy = token_seq[i:end] | 
 |  1128         seq_copy.append(tokenize.Token(tokenize.SYNTAX, '', 0, 0)) | 
 |  1129         names = [] | 
 |  1130         while i < end: | 
 |  1131             # Iterate through the sequence parsing out each name. | 
 |  1132             new_name, next = self.GetName(seq_copy[i:]) | 
 |  1133             assert new_name, 'Got empty new_name, next=%s' % next | 
 |  1134             # We got a pointer or ref.  Add it to the name. | 
 |  1135             if next and next.token_type == tokenize.SYNTAX: | 
 |  1136                 new_name.append(next) | 
 |  1137             names.append(new_name) | 
 |  1138             i += len(new_name) | 
 |  1139  | 
 |  1140         # Now that we have the names, it's time to undo what we did. | 
 |  1141  | 
 |  1142         # Remove the sentinel value. | 
 |  1143         names[-1].pop() | 
 |  1144         # Flatten the token sequence for the return type. | 
 |  1145         return_type = [e for seq in names[:-1] for e in seq] | 
 |  1146         # The class name is the last name. | 
 |  1147         class_name = names[-1] | 
 |  1148         return return_type, class_name | 
 |  1149  | 
 |  1150     def handle_bool(self): | 
 |  1151         pass | 
 |  1152  | 
 |  1153     def handle_char(self): | 
 |  1154         pass | 
 |  1155  | 
 |  1156     def handle_int(self): | 
 |  1157         pass | 
 |  1158  | 
 |  1159     def handle_long(self): | 
 |  1160         pass | 
 |  1161  | 
 |  1162     def handle_short(self): | 
 |  1163         pass | 
 |  1164  | 
 |  1165     def handle_double(self): | 
 |  1166         pass | 
 |  1167  | 
 |  1168     def handle_float(self): | 
 |  1169         pass | 
 |  1170  | 
 |  1171     def handle_void(self): | 
 |  1172         pass | 
 |  1173  | 
 |  1174     def handle_wchar_t(self): | 
 |  1175         pass | 
 |  1176  | 
 |  1177     def handle_unsigned(self): | 
 |  1178         pass | 
 |  1179  | 
 |  1180     def handle_signed(self): | 
 |  1181         pass | 
 |  1182  | 
 |  1183     def _GetNestedType(self, ctor): | 
 |  1184         name = None | 
 |  1185         name_tokens, token = self.GetName() | 
 |  1186         if name_tokens: | 
 |  1187             name = ''.join([t.name for t in name_tokens]) | 
 |  1188  | 
 |  1189         # Handle forward declarations. | 
 |  1190         if token.token_type == tokenize.SYNTAX and token.name == ';': | 
 |  1191             return ctor(token.start, token.end, name, None, | 
 |  1192                         self.namespace_stack) | 
 |  1193  | 
 |  1194         if token.token_type == tokenize.NAME and self._handling_typedef: | 
 |  1195             self._AddBackToken(token) | 
 |  1196             return ctor(token.start, token.end, name, None, | 
 |  1197                         self.namespace_stack) | 
 |  1198  | 
 |  1199         # Must be the type declaration. | 
 |  1200         fields = list(self._GetMatchingChar('{', '}')) | 
 |  1201         del fields[-1]                  # Remove trailing '}'. | 
 |  1202         if token.token_type == tokenize.SYNTAX and token.name == '{': | 
 |  1203             next = self._GetNextToken() | 
 |  1204             new_type = ctor(token.start, token.end, name, fields, | 
 |  1205                             self.namespace_stack) | 
 |  1206             # A name means this is an anonymous type and the name | 
 |  1207             # is the variable declaration. | 
 |  1208             if next.token_type != tokenize.NAME: | 
 |  1209                 return new_type | 
 |  1210             name = new_type | 
 |  1211             token = next | 
 |  1212  | 
 |  1213         # Must be variable declaration using the type prefixed with keyword. | 
 |  1214         assert token.token_type == tokenize.NAME, token | 
 |  1215         return self._CreateVariable(token, token.name, name, [], '', None) | 
 |  1216  | 
 |  1217     def handle_struct(self): | 
 |  1218         # Special case the handling typedef/aliasing of structs here. | 
 |  1219         # It would be a pain to handle in the class code. | 
 |  1220         name_tokens, var_token = self.GetName() | 
 |  1221         if name_tokens: | 
 |  1222             next_token = self._GetNextToken() | 
 |  1223             is_syntax = (var_token.token_type == tokenize.SYNTAX and | 
 |  1224                          var_token.name[0] in '*&') | 
 |  1225             is_variable = (var_token.token_type == tokenize.NAME and | 
 |  1226                            next_token.name == ';') | 
 |  1227             variable = var_token | 
 |  1228             if is_syntax and not is_variable: | 
 |  1229                 variable = next_token | 
 |  1230                 temp = self._GetNextToken() | 
 |  1231                 if temp.token_type == tokenize.SYNTAX and temp.name == '(': | 
 |  1232                     # Handle methods declared to return a struct. | 
 |  1233                     t0 = name_tokens[0] | 
 |  1234                     struct = tokenize.Token(tokenize.NAME, 'struct', | 
 |  1235                                             t0.start-7, t0.start-2) | 
 |  1236                     type_and_name = [struct] | 
 |  1237                     type_and_name.extend(name_tokens) | 
 |  1238                     type_and_name.extend((var_token, next_token)) | 
 |  1239                     return self._GetMethod(type_and_name, 0, None, False) | 
 |  1240                 assert temp.name == ';', (temp, name_tokens, var_token) | 
 |  1241             if is_syntax or (is_variable and not self._handling_typedef): | 
 |  1242                 modifiers = ['struct'] | 
 |  1243                 type_name = ''.join([t.name for t in name_tokens]) | 
 |  1244                 position = name_tokens[0] | 
 |  1245                 return self._CreateVariable(position, variable.name, type_name, | 
 |  1246                                             modifiers, var_token.name, None) | 
 |  1247             name_tokens.extend((var_token, next_token)) | 
 |  1248             self._AddBackTokens(name_tokens) | 
 |  1249         else: | 
 |  1250             self._AddBackToken(var_token) | 
 |  1251         return self._GetClass(Struct, VISIBILITY_PUBLIC, None) | 
 |  1252  | 
 |  1253     def handle_union(self): | 
 |  1254         return self._GetNestedType(Union) | 
 |  1255  | 
 |  1256     def handle_enum(self): | 
 |  1257         return self._GetNestedType(Enum) | 
 |  1258  | 
 |  1259     def handle_auto(self): | 
 |  1260         # TODO(nnorwitz): warn about using auto?  Probably not since it | 
 |  1261         # will be reclaimed and useful for C++0x. | 
 |  1262         pass | 
 |  1263  | 
 |  1264     def handle_register(self): | 
 |  1265         pass | 
 |  1266  | 
 |  1267     def handle_const(self): | 
 |  1268         pass | 
 |  1269  | 
 |  1270     def handle_inline(self): | 
 |  1271         pass | 
 |  1272  | 
 |  1273     def handle_extern(self): | 
 |  1274         pass | 
 |  1275  | 
 |  1276     def handle_static(self): | 
 |  1277         pass | 
 |  1278  | 
 |  1279     def handle_virtual(self): | 
 |  1280         # What follows must be a method. | 
 |  1281         token = token2 = self._GetNextToken() | 
 |  1282         if token.name == 'inline': | 
 |  1283             # HACK(nnorwitz): handle inline dtors by ignoring 'inline'. | 
 |  1284             token2 = self._GetNextToken() | 
 |  1285         if token2.token_type == tokenize.SYNTAX and token2.name == '~': | 
 |  1286             return self.GetMethod(FUNCTION_VIRTUAL + FUNCTION_DTOR, None) | 
 |  1287         assert token.token_type == tokenize.NAME or token.name == '::', token | 
 |  1288         return_type_and_name = self._GetTokensUpTo(tokenize.SYNTAX, '(') | 
 |  1289         return_type_and_name.insert(0, token) | 
 |  1290         if token2 is not token: | 
 |  1291             return_type_and_name.insert(1, token2) | 
 |  1292         return self._GetMethod(return_type_and_name, FUNCTION_VIRTUAL, | 
 |  1293                                None, False) | 
 |  1294  | 
 |  1295     def handle_volatile(self): | 
 |  1296         pass | 
 |  1297  | 
 |  1298     def handle_mutable(self): | 
 |  1299         pass | 
 |  1300  | 
 |  1301     def handle_public(self): | 
 |  1302         assert self.in_class | 
 |  1303         self.visibility = VISIBILITY_PUBLIC | 
 |  1304  | 
 |  1305     def handle_protected(self): | 
 |  1306         assert self.in_class | 
 |  1307         self.visibility = VISIBILITY_PROTECTED | 
 |  1308  | 
 |  1309     def handle_private(self): | 
 |  1310         assert self.in_class | 
 |  1311         self.visibility = VISIBILITY_PRIVATE | 
 |  1312  | 
 |  1313     def handle_friend(self): | 
 |  1314         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') | 
 |  1315         assert tokens | 
 |  1316         t0 = tokens[0] | 
 |  1317         return Friend(t0.start, t0.end, tokens, self.namespace_stack) | 
 |  1318  | 
 |  1319     def handle_static_cast(self): | 
 |  1320         pass | 
 |  1321  | 
 |  1322     def handle_const_cast(self): | 
 |  1323         pass | 
 |  1324  | 
 |  1325     def handle_dynamic_cast(self): | 
 |  1326         pass | 
 |  1327  | 
 |  1328     def handle_reinterpret_cast(self): | 
 |  1329         pass | 
 |  1330  | 
 |  1331     def handle_new(self): | 
 |  1332         pass | 
 |  1333  | 
 |  1334     def handle_delete(self): | 
 |  1335         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') | 
 |  1336         assert tokens | 
 |  1337         return Delete(tokens[0].start, tokens[0].end, tokens) | 
 |  1338  | 
 |  1339     def handle_typedef(self): | 
 |  1340         token = self._GetNextToken() | 
 |  1341         if (token.token_type == tokenize.NAME and | 
 |  1342             keywords.IsKeyword(token.name)): | 
 |  1343             # Token must be struct/enum/union/class. | 
 |  1344             method = getattr(self, 'handle_' + token.name) | 
 |  1345             self._handling_typedef = True | 
 |  1346             tokens = [method()] | 
 |  1347             self._handling_typedef = False | 
 |  1348         else: | 
 |  1349             tokens = [token] | 
 |  1350  | 
 |  1351         # Get the remainder of the typedef up to the semi-colon. | 
 |  1352         tokens.extend(self._GetTokensUpTo(tokenize.SYNTAX, ';')) | 
 |  1353  | 
 |  1354         # TODO(nnorwitz): clean all this up. | 
 |  1355         assert tokens | 
 |  1356         name = tokens.pop() | 
 |  1357         indices = name | 
 |  1358         if tokens: | 
 |  1359             indices = tokens[0] | 
 |  1360         if not indices: | 
 |  1361             indices = token | 
 |  1362         if name.name == ')': | 
 |  1363             # HACK(nnorwitz): Handle pointers to functions "properly". | 
 |  1364             if (len(tokens) >= 4 and | 
 |  1365                 tokens[1].name == '(' and tokens[2].name == '*'): | 
 |  1366                 tokens.append(name) | 
 |  1367                 name = tokens[3] | 
 |  1368         elif name.name == ']': | 
 |  1369             # HACK(nnorwitz): Handle arrays properly. | 
 |  1370             if len(tokens) >= 2: | 
 |  1371                 tokens.append(name) | 
 |  1372                 name = tokens[1] | 
 |  1373         new_type = tokens | 
 |  1374         if tokens and isinstance(tokens[0], tokenize.Token): | 
 |  1375             new_type = self.converter.ToType(tokens)[0] | 
 |  1376         return Typedef(indices.start, indices.end, name.name, | 
 |  1377                        new_type, self.namespace_stack) | 
 |  1378  | 
 |  1379     def handle_typeid(self): | 
 |  1380         pass  # Not needed yet. | 
 |  1381  | 
 |  1382     def handle_typename(self): | 
 |  1383         pass  # Not needed yet. | 
 |  1384  | 
 |  1385     def _GetTemplatedTypes(self): | 
 |  1386         result = {} | 
 |  1387         tokens = list(self._GetMatchingChar('<', '>')) | 
 |  1388         len_tokens = len(tokens) - 1    # Ignore trailing '>'. | 
 |  1389         i = 0 | 
 |  1390         while i < len_tokens: | 
 |  1391             key = tokens[i].name | 
 |  1392             i += 1 | 
 |  1393             if keywords.IsKeyword(key) or key == ',': | 
 |  1394                 continue | 
 |  1395             type_name = default = None | 
 |  1396             if i < len_tokens: | 
 |  1397                 i += 1 | 
 |  1398                 if tokens[i-1].name == '=': | 
 |  1399                     assert i < len_tokens, '%s %s' % (i, tokens) | 
 |  1400                     default, unused_next_token = self.GetName(tokens[i:]) | 
 |  1401                     i += len(default) | 
 |  1402                 else: | 
 |  1403                     if tokens[i-1].name != ',': | 
 |  1404                         # We got something like: Type variable. | 
 |  1405                         # Re-adjust the key (variable) and type_name (Type). | 
 |  1406                         key = tokens[i-1].name | 
 |  1407                         type_name = tokens[i-2] | 
 |  1408  | 
 |  1409             result[key] = (type_name, default) | 
 |  1410         return result | 
 |  1411  | 
 |  1412     def handle_template(self): | 
 |  1413         token = self._GetNextToken() | 
 |  1414         assert token.token_type == tokenize.SYNTAX, token | 
 |  1415         assert token.name == '<', token | 
 |  1416         templated_types = self._GetTemplatedTypes() | 
 |  1417         # TODO(nnorwitz): for now, just ignore the template params. | 
 |  1418         token = self._GetNextToken() | 
 |  1419         if token.token_type == tokenize.NAME: | 
 |  1420             if token.name == 'class': | 
 |  1421                 return self._GetClass(Class, VISIBILITY_PRIVATE, templated_types
      ) | 
 |  1422             elif token.name == 'struct': | 
 |  1423                 return self._GetClass(Struct, VISIBILITY_PUBLIC, templated_types
      ) | 
 |  1424             elif token.name == 'friend': | 
 |  1425                 return self.handle_friend() | 
 |  1426         self._AddBackToken(token) | 
 |  1427         tokens, last = self._GetVarTokensUpTo(tokenize.SYNTAX, '(', ';') | 
 |  1428         tokens.append(last) | 
 |  1429         self._AddBackTokens(tokens) | 
 |  1430         if last.name == '(': | 
 |  1431             return self.GetMethod(FUNCTION_NONE, templated_types) | 
 |  1432         # Must be a variable definition. | 
 |  1433         return None | 
 |  1434  | 
 |  1435     def handle_true(self): | 
 |  1436         pass  # Nothing to do. | 
 |  1437  | 
 |  1438     def handle_false(self): | 
 |  1439         pass  # Nothing to do. | 
 |  1440  | 
 |  1441     def handle_asm(self): | 
 |  1442         pass  # Not needed yet. | 
 |  1443  | 
 |  1444     def handle_class(self): | 
 |  1445         return self._GetClass(Class, VISIBILITY_PRIVATE, None) | 
 |  1446  | 
 |  1447     def _GetBases(self): | 
 |  1448         # Get base classes. | 
 |  1449         bases = [] | 
 |  1450         while 1: | 
 |  1451             token = self._GetNextToken() | 
 |  1452             assert token.token_type == tokenize.NAME, token | 
 |  1453             # TODO(nnorwitz): store kind of inheritance...maybe. | 
 |  1454             if token.name not in ('public', 'protected', 'private'): | 
 |  1455                 # If inheritance type is not specified, it is private. | 
 |  1456                 # Just put the token back so we can form a name. | 
 |  1457                 # TODO(nnorwitz): it would be good to warn about this. | 
 |  1458                 self._AddBackToken(token) | 
 |  1459             else: | 
 |  1460                 # Check for virtual inheritance. | 
 |  1461                 token = self._GetNextToken() | 
 |  1462                 if token.name != 'virtual': | 
 |  1463                     self._AddBackToken(token) | 
 |  1464                 else: | 
 |  1465                     # TODO(nnorwitz): store that we got virtual for this base. | 
 |  1466                     pass | 
 |  1467             base, next_token = self.GetName() | 
 |  1468             bases_ast = self.converter.ToType(base) | 
 |  1469             assert len(bases_ast) == 1, bases_ast | 
 |  1470             bases.append(bases_ast[0]) | 
 |  1471             assert next_token.token_type == tokenize.SYNTAX, next_token | 
 |  1472             if next_token.name == '{': | 
 |  1473                 token = next_token | 
 |  1474                 break | 
 |  1475             # Support multiple inheritance. | 
 |  1476             assert next_token.name == ',', next_token | 
 |  1477         return bases, token | 
 |  1478  | 
 |  1479     def _GetClass(self, class_type, visibility, templated_types): | 
 |  1480         class_name = None | 
 |  1481         class_token = self._GetNextToken() | 
 |  1482         if class_token.token_type != tokenize.NAME: | 
 |  1483             assert class_token.token_type == tokenize.SYNTAX, class_token | 
 |  1484             token = class_token | 
 |  1485         else: | 
 |  1486             self._AddBackToken(class_token) | 
 |  1487             name_tokens, token = self.GetName() | 
 |  1488             class_name = ''.join([t.name for t in name_tokens]) | 
 |  1489         bases = None | 
 |  1490         if token.token_type == tokenize.SYNTAX: | 
 |  1491             if token.name == ';': | 
 |  1492                 # Forward declaration. | 
 |  1493                 return class_type(class_token.start, class_token.end, | 
 |  1494                                   class_name, None, templated_types, None, | 
 |  1495                                   self.namespace_stack) | 
 |  1496             if token.name in '*&': | 
 |  1497                 # Inline forward declaration.  Could be method or data. | 
 |  1498                 name_token = self._GetNextToken() | 
 |  1499                 next_token = self._GetNextToken() | 
 |  1500                 if next_token.name == ';': | 
 |  1501                     # Handle data | 
 |  1502                     modifiers = ['class'] | 
 |  1503                     return self._CreateVariable(class_token, name_token.name, | 
 |  1504                                                 class_name, | 
 |  1505                                                 modifiers, token.name, None) | 
 |  1506                 else: | 
 |  1507                     # Assume this is a method. | 
 |  1508                     tokens = (class_token, token, name_token, next_token) | 
 |  1509                     self._AddBackTokens(tokens) | 
 |  1510                     return self.GetMethod(FUNCTION_NONE, None) | 
 |  1511             if token.name == ':': | 
 |  1512                 bases, token = self._GetBases() | 
 |  1513  | 
 |  1514         body = None | 
 |  1515         if token.token_type == tokenize.SYNTAX and token.name == '{': | 
 |  1516             assert token.token_type == tokenize.SYNTAX, token | 
 |  1517             assert token.name == '{', token | 
 |  1518  | 
 |  1519             ast = AstBuilder(self.GetScope(), self.filename, class_name, | 
 |  1520                              visibility, self.namespace_stack) | 
 |  1521             body = list(ast.Generate()) | 
 |  1522  | 
 |  1523             if not self._handling_typedef: | 
 |  1524                 token = self._GetNextToken() | 
 |  1525                 if token.token_type != tokenize.NAME: | 
 |  1526                     assert token.token_type == tokenize.SYNTAX, token | 
 |  1527                     assert token.name == ';', token | 
 |  1528                 else: | 
 |  1529                     new_class = class_type(class_token.start, class_token.end, | 
 |  1530                                            class_name, bases, None, | 
 |  1531                                            body, self.namespace_stack) | 
 |  1532  | 
 |  1533                     modifiers = [] | 
 |  1534                     return self._CreateVariable(class_token, | 
 |  1535                                                 token.name, new_class, | 
 |  1536                                                 modifiers, token.name, None) | 
 |  1537         else: | 
 |  1538             if not self._handling_typedef: | 
 |  1539                 self.HandleError('non-typedef token', token) | 
 |  1540             self._AddBackToken(token) | 
 |  1541  | 
 |  1542         return class_type(class_token.start, class_token.end, class_name, | 
 |  1543                           bases, None, body, self.namespace_stack) | 
 |  1544  | 
 |  1545     def handle_namespace(self): | 
 |  1546         token = self._GetNextToken() | 
 |  1547         # Support anonymous namespaces. | 
 |  1548         name = None | 
 |  1549         if token.token_type == tokenize.NAME: | 
 |  1550             name = token.name | 
 |  1551             token = self._GetNextToken() | 
 |  1552         self.namespace_stack.append(name) | 
 |  1553         assert token.token_type == tokenize.SYNTAX, token | 
 |  1554         if token.name == '=': | 
 |  1555             # TODO(nnorwitz): handle aliasing namespaces. | 
 |  1556             name, next_token = self.GetName() | 
 |  1557             assert next_token.name == ';', next_token | 
 |  1558         else: | 
 |  1559             assert token.name == '{', token | 
 |  1560             tokens = list(self.GetScope()) | 
 |  1561             del tokens[-1]              # Remove trailing '}'. | 
 |  1562             # Handle namespace with nothing in it. | 
 |  1563             self._AddBackTokens(tokens) | 
 |  1564         token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP, None, None) | 
 |  1565         self._AddBackToken(token) | 
 |  1566         return None | 
 |  1567  | 
 |  1568     def handle_using(self): | 
 |  1569         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') | 
 |  1570         assert tokens | 
 |  1571         return Using(tokens[0].start, tokens[0].end, tokens) | 
 |  1572  | 
 |  1573     def handle_explicit(self): | 
 |  1574         assert self.in_class | 
 |  1575         # Nothing much to do. | 
 |  1576         # TODO(nnorwitz): maybe verify the method name == class name. | 
 |  1577         # This must be a ctor. | 
 |  1578         return self.GetMethod(FUNCTION_CTOR, None) | 
 |  1579  | 
 |  1580     def handle_this(self): | 
 |  1581         pass  # Nothing to do. | 
 |  1582  | 
 |  1583     def handle_operator(self): | 
 |  1584         # Pull off the next token(s?) and make that part of the method name. | 
 |  1585         pass | 
 |  1586  | 
 |  1587     def handle_sizeof(self): | 
 |  1588         pass | 
 |  1589  | 
 |  1590     def handle_case(self): | 
 |  1591         pass | 
 |  1592  | 
 |  1593     def handle_switch(self): | 
 |  1594         pass | 
 |  1595  | 
 |  1596     def handle_default(self): | 
 |  1597         token = self._GetNextToken() | 
 |  1598         assert token.token_type == tokenize.SYNTAX | 
 |  1599         assert token.name == ':' | 
 |  1600  | 
 |  1601     def handle_if(self): | 
 |  1602         pass | 
 |  1603  | 
 |  1604     def handle_else(self): | 
 |  1605         pass | 
 |  1606  | 
 |  1607     def handle_return(self): | 
 |  1608         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') | 
 |  1609         if not tokens: | 
 |  1610             return Return(self.current_token.start, self.current_token.end, None
      ) | 
 |  1611         return Return(tokens[0].start, tokens[0].end, tokens) | 
 |  1612  | 
 |  1613     def handle_goto(self): | 
 |  1614         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';') | 
 |  1615         assert len(tokens) == 1, str(tokens) | 
 |  1616         return Goto(tokens[0].start, tokens[0].end, tokens[0].name) | 
 |  1617  | 
 |  1618     def handle_try(self): | 
 |  1619         pass  # Not needed yet. | 
 |  1620  | 
 |  1621     def handle_catch(self): | 
 |  1622         pass  # Not needed yet. | 
 |  1623  | 
 |  1624     def handle_throw(self): | 
 |  1625         pass  # Not needed yet. | 
 |  1626  | 
 |  1627     def handle_while(self): | 
 |  1628         pass | 
 |  1629  | 
 |  1630     def handle_do(self): | 
 |  1631         pass | 
 |  1632  | 
 |  1633     def handle_for(self): | 
 |  1634         pass | 
 |  1635  | 
 |  1636     def handle_break(self): | 
 |  1637         self._IgnoreUpTo(tokenize.SYNTAX, ';') | 
 |  1638  | 
 |  1639     def handle_continue(self): | 
 |  1640         self._IgnoreUpTo(tokenize.SYNTAX, ';') | 
 |  1641  | 
 |  1642  | 
 |  1643 def BuilderFromSource(source, filename): | 
 |  1644     """Utility method that returns an AstBuilder from source code. | 
 |  1645  | 
 |  1646     Args: | 
 |  1647       source: 'C++ source code' | 
 |  1648       filename: 'file1' | 
 |  1649  | 
 |  1650     Returns: | 
 |  1651       AstBuilder | 
 |  1652     """ | 
 |  1653     return AstBuilder(tokenize.GetTokens(source), filename) | 
 |  1654  | 
 |  1655  | 
 |  1656 def PrintIndentifiers(filename, should_print): | 
 |  1657     """Prints all identifiers for a C++ source file. | 
 |  1658  | 
 |  1659     Args: | 
 |  1660       filename: 'file1' | 
 |  1661       should_print: predicate with signature: bool Function(token) | 
 |  1662     """ | 
 |  1663     source = utils.ReadFile(filename, False) | 
 |  1664     if source is None: | 
 |  1665         sys.stderr.write('Unable to find: %s\n' % filename) | 
 |  1666         return | 
 |  1667  | 
 |  1668     #print('Processing %s' % actual_filename) | 
 |  1669     builder = BuilderFromSource(source, filename) | 
 |  1670     try: | 
 |  1671         for node in builder.Generate(): | 
 |  1672             if should_print(node): | 
 |  1673                 print(node.name) | 
 |  1674     except KeyboardInterrupt: | 
 |  1675       return | 
 |  1676     except: | 
 |  1677         pass | 
 |  1678  | 
 |  1679  | 
 |  1680 def PrintAllIndentifiers(filenames, should_print): | 
 |  1681     """Prints all identifiers for each C++ source file in filenames. | 
 |  1682  | 
 |  1683     Args: | 
 |  1684       filenames: ['file1', 'file2', ...] | 
 |  1685       should_print: predicate with signature: bool Function(token) | 
 |  1686     """ | 
 |  1687     for path in filenames: | 
 |  1688         PrintIndentifiers(path, should_print) | 
 |  1689  | 
 |  1690  | 
 |  1691 def main(argv): | 
 |  1692     for filename in argv[1:]: | 
 |  1693         source = utils.ReadFile(filename) | 
 |  1694         if source is None: | 
 |  1695             continue | 
 |  1696  | 
 |  1697         print('Processing %s' % filename) | 
 |  1698         builder = BuilderFromSource(source, filename) | 
 |  1699         try: | 
 |  1700             entire_ast = filter(None, builder.Generate()) | 
 |  1701         except KeyboardInterrupt: | 
 |  1702             return | 
 |  1703         except: | 
 |  1704             # Already printed a warning, print the traceback and continue. | 
 |  1705             traceback.print_exc() | 
 |  1706         else: | 
 |  1707             if utils.DEBUG: | 
 |  1708                 for ast in entire_ast: | 
 |  1709                     print(ast) | 
 |  1710  | 
 |  1711  | 
 |  1712 if __name__ == '__main__': | 
 |  1713     main(sys.argv) | 
| OLD | NEW |