ast.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2007 Neal Norwitz
00004 # Portions Copyright 2007 Google Inc.
00005 #
00006 # Licensed under the Apache License, Version 2.0 (the "License");
00007 # you may not use this file except in compliance with the License.
00008 # You may obtain a copy of the License at
00009 #
00010 #      http://www.apache.org/licenses/LICENSE-2.0
00011 #
00012 # Unless required by applicable law or agreed to in writing, software
00013 # distributed under the License is distributed on an "AS IS" BASIS,
00014 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 # See the License for the specific language governing permissions and
00016 # limitations under the License.
00017 
00018 """Generate an Abstract Syntax Tree (AST) for C++."""
00019 
00020 __author__ = 'nnorwitz@google.com (Neal Norwitz)'
00021 
00022 
00023 # TODO:
00024 #  * Tokens should never be exported, need to convert to Nodes
00025 #    (return types, parameters, etc.)
00026 #  * Handle static class data for templatized classes
00027 #  * Handle casts (both C++ and C-style)
00028 #  * Handle conditions and loops (if/else, switch, for, while/do)
00029 #
00030 # TODO much, much later:
00031 #  * Handle #define
00032 #  * exceptions
00033 
00034 
00035 try:
00036     # Python 3.x
00037     import builtins
00038 except ImportError:
00039     # Python 2.x
00040     import __builtin__ as builtins
00041 
00042 import sys
00043 import traceback
00044 
00045 from cpp import keywords
00046 from cpp import tokenize
00047 from cpp import utils
00048 
00049 
00050 if not hasattr(builtins, 'reversed'):
00051     # Support Python 2.3 and earlier.
00052     def reversed(seq):
00053         for i in range(len(seq)-1, -1, -1):
00054             yield seq[i]
00055 
00056 if not hasattr(builtins, 'next'):
00057     # Support Python 2.5 and earlier.
00058     def next(obj):
00059         return obj.next()
00060 
00061 
00062 VISIBILITY_PUBLIC, VISIBILITY_PROTECTED, VISIBILITY_PRIVATE = range(3)
00063 
00064 FUNCTION_NONE = 0x00
00065 FUNCTION_CONST = 0x01
00066 FUNCTION_VIRTUAL = 0x02
00067 FUNCTION_PURE_VIRTUAL = 0x04
00068 FUNCTION_CTOR = 0x08
00069 FUNCTION_DTOR = 0x10
00070 FUNCTION_ATTRIBUTE = 0x20
00071 FUNCTION_UNKNOWN_ANNOTATION = 0x40
00072 FUNCTION_THROW = 0x80
00073 
00074 """
00075 These are currently unused.  Should really handle these properly at some point.
00076 
00077 TYPE_MODIFIER_INLINE   = 0x010000
00078 TYPE_MODIFIER_EXTERN   = 0x020000
00079 TYPE_MODIFIER_STATIC   = 0x040000
00080 TYPE_MODIFIER_CONST    = 0x080000
00081 TYPE_MODIFIER_REGISTER = 0x100000
00082 TYPE_MODIFIER_VOLATILE = 0x200000
00083 TYPE_MODIFIER_MUTABLE  = 0x400000
00084 
00085 TYPE_MODIFIER_MAP = {
00086     'inline': TYPE_MODIFIER_INLINE,
00087     'extern': TYPE_MODIFIER_EXTERN,
00088     'static': TYPE_MODIFIER_STATIC,
00089     'const': TYPE_MODIFIER_CONST,
00090     'register': TYPE_MODIFIER_REGISTER,
00091     'volatile': TYPE_MODIFIER_VOLATILE,
00092     'mutable': TYPE_MODIFIER_MUTABLE,
00093     }
00094 """
00095 
00096 _INTERNAL_TOKEN = 'internal'
00097 _NAMESPACE_POP = 'ns-pop'
00098 
00099 
00100 # TODO(nnorwitz): use this as a singleton for templated_types, etc
00101 # where we don't want to create a new empty dict each time.  It is also const.
00102 class _NullDict(object):
00103     __contains__ = lambda self: False
00104     keys = values = items = iterkeys = itervalues = iteritems = lambda self: ()
00105 
00106 
00107 # TODO(nnorwitz): move AST nodes into a separate module.
00108 class Node(object):
00109     """Base AST node."""
00110 
00111     def __init__(self, start, end):
00112         self.start = start
00113         self.end = end
00114 
00115     def IsDeclaration(self):
00116         """Returns bool if this node is a declaration."""
00117         return False
00118 
00119     def IsDefinition(self):
00120         """Returns bool if this node is a definition."""
00121         return False
00122 
00123     def IsExportable(self):
00124         """Returns bool if this node exportable from a header file."""
00125         return False
00126 
00127     def Requires(self, node):
00128         """Does this AST node require the definition of the node passed in?"""
00129         return False
00130 
00131     def XXX__str__(self):
00132         return self._StringHelper(self.__class__.__name__, '')
00133 
00134     def _StringHelper(self, name, suffix):
00135         if not utils.DEBUG:
00136             return '%s(%s)' % (name, suffix)
00137         return '%s(%d, %d, %s)' % (name, self.start, self.end, suffix)
00138 
00139     def __repr__(self):
00140         return str(self)
00141 
00142 
00143 class Define(Node):
00144     def __init__(self, start, end, name, definition):
00145         Node.__init__(self, start, end)
00146         self.name = name
00147         self.definition = definition
00148 
00149     def __str__(self):
00150         value = '%s %s' % (self.name, self.definition)
00151         return self._StringHelper(self.__class__.__name__, value)
00152 
00153 
00154 class Include(Node):
00155     def __init__(self, start, end, filename, system):
00156         Node.__init__(self, start, end)
00157         self.filename = filename
00158         self.system = system
00159 
00160     def __str__(self):
00161         fmt = '"%s"'
00162         if self.system:
00163             fmt = '<%s>'
00164         return self._StringHelper(self.__class__.__name__, fmt % self.filename)
00165 
00166 
00167 class Goto(Node):
00168     def __init__(self, start, end, label):
00169         Node.__init__(self, start, end)
00170         self.label = label
00171 
00172     def __str__(self):
00173         return self._StringHelper(self.__class__.__name__, str(self.label))
00174 
00175 
00176 class Expr(Node):
00177     def __init__(self, start, end, expr):
00178         Node.__init__(self, start, end)
00179         self.expr = expr
00180 
00181     def Requires(self, node):
00182         # TODO(nnorwitz): impl.
00183         return False
00184 
00185     def __str__(self):
00186         return self._StringHelper(self.__class__.__name__, str(self.expr))
00187 
00188 
00189 class Return(Expr):
00190     pass
00191 
00192 
00193 class Delete(Expr):
00194     pass
00195 
00196 
00197 class Friend(Expr):
00198     def __init__(self, start, end, expr, namespace):
00199         Expr.__init__(self, start, end, expr)
00200         self.namespace = namespace[:]
00201 
00202 
00203 class Using(Node):
00204     def __init__(self, start, end, names):
00205         Node.__init__(self, start, end)
00206         self.names = names
00207 
00208     def __str__(self):
00209         return self._StringHelper(self.__class__.__name__, str(self.names))
00210 
00211 
00212 class Parameter(Node):
00213     def __init__(self, start, end, name, parameter_type, default):
00214         Node.__init__(self, start, end)
00215         self.name = name
00216         self.type = parameter_type
00217         self.default = default
00218 
00219     def Requires(self, node):
00220         # TODO(nnorwitz): handle namespaces, etc.
00221         return self.type.name == node.name
00222 
00223     def __str__(self):
00224         name = str(self.type)
00225         suffix = '%s %s' % (name, self.name)
00226         if self.default:
00227             suffix += ' = ' + ''.join([d.name for d in self.default])
00228         return self._StringHelper(self.__class__.__name__, suffix)
00229 
00230 
00231 class _GenericDeclaration(Node):
00232     def __init__(self, start, end, name, namespace):
00233         Node.__init__(self, start, end)
00234         self.name = name
00235         self.namespace = namespace[:]
00236 
00237     def FullName(self):
00238         prefix = ''
00239         if self.namespace and self.namespace[-1]:
00240             prefix = '::'.join(self.namespace) + '::'
00241         return prefix + self.name
00242 
00243     def _TypeStringHelper(self, suffix):
00244         if self.namespace:
00245             names = [n or '<anonymous>' for n in self.namespace]
00246             suffix += ' in ' + '::'.join(names)
00247         return self._StringHelper(self.__class__.__name__, suffix)
00248 
00249 
00250 # TODO(nnorwitz): merge with Parameter in some way?
00251 class VariableDeclaration(_GenericDeclaration):
00252     def __init__(self, start, end, name, var_type, initial_value, namespace):
00253         _GenericDeclaration.__init__(self, start, end, name, namespace)
00254         self.type = var_type
00255         self.initial_value = initial_value
00256 
00257     def Requires(self, node):
00258         # TODO(nnorwitz): handle namespaces, etc.
00259         return self.type.name == node.name
00260 
00261     def ToString(self):
00262         """Return a string that tries to reconstitute the variable decl."""
00263         suffix = '%s %s' % (self.type, self.name)
00264         if self.initial_value:
00265             suffix += ' = ' + self.initial_value
00266         return suffix
00267 
00268     def __str__(self):
00269         return self._StringHelper(self.__class__.__name__, self.ToString())
00270 
00271 
00272 class Typedef(_GenericDeclaration):
00273     def __init__(self, start, end, name, alias, namespace):
00274         _GenericDeclaration.__init__(self, start, end, name, namespace)
00275         self.alias = alias
00276 
00277     def IsDefinition(self):
00278         return True
00279 
00280     def IsExportable(self):
00281         return True
00282 
00283     def Requires(self, node):
00284         # TODO(nnorwitz): handle namespaces, etc.
00285         name = node.name
00286         for token in self.alias:
00287             if token is not None and name == token.name:
00288                 return True
00289         return False
00290 
00291     def __str__(self):
00292         suffix = '%s, %s' % (self.name, self.alias)
00293         return self._TypeStringHelper(suffix)
00294 
00295 
00296 class _NestedType(_GenericDeclaration):
00297     def __init__(self, start, end, name, fields, namespace):
00298         _GenericDeclaration.__init__(self, start, end, name, namespace)
00299         self.fields = fields
00300 
00301     def IsDefinition(self):
00302         return True
00303 
00304     def IsExportable(self):
00305         return True
00306 
00307     def __str__(self):
00308         suffix = '%s, {%s}' % (self.name, self.fields)
00309         return self._TypeStringHelper(suffix)
00310 
00311 
00312 class Union(_NestedType):
00313     pass
00314 
00315 
00316 class Enum(_NestedType):
00317     pass
00318 
00319 
00320 class Class(_GenericDeclaration):
00321     def __init__(self, start, end, name, bases, templated_types, body, namespace):
00322         _GenericDeclaration.__init__(self, start, end, name, namespace)
00323         self.bases = bases
00324         self.body = body
00325         self.templated_types = templated_types
00326 
00327     def IsDeclaration(self):
00328         return self.bases is None and self.body is None
00329 
00330     def IsDefinition(self):
00331         return not self.IsDeclaration()
00332 
00333     def IsExportable(self):
00334         return not self.IsDeclaration()
00335 
00336     def Requires(self, node):
00337         # TODO(nnorwitz): handle namespaces, etc.
00338         if self.bases:
00339             for token_list in self.bases:
00340                 # TODO(nnorwitz): bases are tokens, do name comparision.
00341                 for token in token_list:
00342                     if token.name == node.name:
00343                         return True
00344         # TODO(nnorwitz): search in body too.
00345         return False
00346 
00347     def __str__(self):
00348         name = self.name
00349         if self.templated_types:
00350             name += '<%s>' % self.templated_types
00351         suffix = '%s, %s, %s' % (name, self.bases, self.body)
00352         return self._TypeStringHelper(suffix)
00353 
00354 
00355 class Struct(Class):
00356     pass
00357 
00358 
00359 class Function(_GenericDeclaration):
00360     def __init__(self, start, end, name, return_type, parameters,
00361                  modifiers, templated_types, body, namespace):
00362         _GenericDeclaration.__init__(self, start, end, name, namespace)
00363         converter = TypeConverter(namespace)
00364         self.return_type = converter.CreateReturnType(return_type)
00365         self.parameters = converter.ToParameters(parameters)
00366         self.modifiers = modifiers
00367         self.body = body
00368         self.templated_types = templated_types
00369 
00370     def IsDeclaration(self):
00371         return self.body is None
00372 
00373     def IsDefinition(self):
00374         return self.body is not None
00375 
00376     def IsExportable(self):
00377         if self.return_type and 'static' in self.return_type.modifiers:
00378             return False
00379         return None not in self.namespace
00380 
00381     def Requires(self, node):
00382         if self.parameters:
00383             # TODO(nnorwitz): parameters are tokens, do name comparision.
00384             for p in self.parameters:
00385                 if p.name == node.name:
00386                     return True
00387         # TODO(nnorwitz): search in body too.
00388         return False
00389 
00390     def __str__(self):
00391         # TODO(nnorwitz): add templated_types.
00392         suffix = ('%s %s(%s), 0x%02x, %s' %
00393                   (self.return_type, self.name, self.parameters,
00394                    self.modifiers, self.body))
00395         return self._TypeStringHelper(suffix)
00396 
00397 
00398 class Method(Function):
00399     def __init__(self, start, end, name, in_class, return_type, parameters,
00400                  modifiers, templated_types, body, namespace):
00401         Function.__init__(self, start, end, name, return_type, parameters,
00402                           modifiers, templated_types, body, namespace)
00403         # TODO(nnorwitz): in_class could also be a namespace which can
00404         # mess up finding functions properly.
00405         self.in_class = in_class
00406 
00407 
00408 class Type(_GenericDeclaration):
00409     """Type used for any variable (eg class, primitive, struct, etc)."""
00410 
00411     def __init__(self, start, end, name, templated_types, modifiers,
00412                  reference, pointer, array):
00413         """
00414         Args:
00415           name: str name of main type
00416           templated_types: [Class (Type?)] template type info between <>
00417           modifiers: [str] type modifiers (keywords) eg, const, mutable, etc.
00418           reference, pointer, array: bools
00419         """
00420         _GenericDeclaration.__init__(self, start, end, name, [])
00421         self.templated_types = templated_types
00422         if not name and modifiers:
00423             self.name = modifiers.pop()
00424         self.modifiers = modifiers
00425         self.reference = reference
00426         self.pointer = pointer
00427         self.array = array
00428 
00429     def __str__(self):
00430         prefix = ''
00431         if self.modifiers:
00432             prefix = ' '.join(self.modifiers) + ' '
00433         name = str(self.name)
00434         if self.templated_types:
00435             name += '<%s>' % self.templated_types
00436         suffix = prefix + name
00437         if self.reference:
00438             suffix += '&'
00439         if self.pointer:
00440             suffix += '*'
00441         if self.array:
00442             suffix += '[]'
00443         return self._TypeStringHelper(suffix)
00444 
00445     # By definition, Is* are always False.  A Type can only exist in
00446     # some sort of variable declaration, parameter, or return value.
00447     def IsDeclaration(self):
00448         return False
00449 
00450     def IsDefinition(self):
00451         return False
00452 
00453     def IsExportable(self):
00454         return False
00455 
00456 
00457 class TypeConverter(object):
00458 
00459     def __init__(self, namespace_stack):
00460         self.namespace_stack = namespace_stack
00461 
00462     def _GetTemplateEnd(self, tokens, start):
00463         count = 1
00464         end = start
00465         while 1:
00466             token = tokens[end]
00467             end += 1
00468             if token.name == '<':
00469                 count += 1
00470             elif token.name == '>':
00471                 count -= 1
00472                 if count == 0:
00473                     break
00474         return tokens[start:end-1], end
00475 
00476     def ToType(self, tokens):
00477         """Convert [Token,...] to [Class(...), ] useful for base classes.
00478         For example, code like class Foo : public Bar<x, y> { ... };
00479         the "Bar<x, y>" portion gets converted to an AST.
00480 
00481         Returns:
00482           [Class(...), ...]
00483         """
00484         result = []
00485         name_tokens = []
00486         reference = pointer = array = False
00487 
00488         def AddType(templated_types):
00489             # Partition tokens into name and modifier tokens.
00490             names = []
00491             modifiers = []
00492             for t in name_tokens:
00493                 if keywords.IsKeyword(t.name):
00494                     modifiers.append(t.name)
00495                 else:
00496                     names.append(t.name)
00497             name = ''.join(names)
00498             result.append(Type(name_tokens[0].start, name_tokens[-1].end,
00499                                name, templated_types, modifiers,
00500                                reference, pointer, array))
00501             del name_tokens[:]
00502 
00503         i = 0
00504         end = len(tokens)
00505         while i < end:
00506             token = tokens[i]
00507             if token.name == '<':
00508                 new_tokens, new_end = self._GetTemplateEnd(tokens, i+1)
00509                 AddType(self.ToType(new_tokens))
00510                 # If there is a comma after the template, we need to consume
00511                 # that here otherwise it becomes part of the name.
00512                 i = new_end
00513                 reference = pointer = array = False
00514             elif token.name == ',':
00515                 AddType([])
00516                 reference = pointer = array = False
00517             elif token.name == '*':
00518                 pointer = True
00519             elif token.name == '&':
00520                 reference = True
00521             elif token.name == '[':
00522                pointer = True
00523             elif token.name == ']':
00524                 pass
00525             else:
00526                 name_tokens.append(token)
00527             i += 1
00528 
00529         if name_tokens:
00530             # No '<' in the tokens, just a simple name and no template.
00531             AddType([])
00532         return result
00533 
00534     def DeclarationToParts(self, parts, needs_name_removed):
00535         name = None
00536         default = []
00537         if needs_name_removed:
00538             # Handle default (initial) values properly.
00539             for i, t in enumerate(parts):
00540                 if t.name == '=':
00541                     default = parts[i+1:]
00542                     name = parts[i-1].name
00543                     if name == ']' and parts[i-2].name == '[':
00544                         name = parts[i-3].name
00545                         i -= 1
00546                     parts = parts[:i-1]
00547                     break
00548             else:
00549                 if parts[-1].token_type == tokenize.NAME:
00550                     name = parts.pop().name
00551                 else:
00552                     # TODO(nnorwitz): this is a hack that happens for code like
00553                     # Register(Foo<T>); where it thinks this is a function call
00554                     # but it's actually a declaration.
00555                     name = '???'
00556         modifiers = []
00557         type_name = []
00558         other_tokens = []
00559         templated_types = []
00560         i = 0
00561         end = len(parts)
00562         while i < end:
00563             p = parts[i]
00564             if keywords.IsKeyword(p.name):
00565                 modifiers.append(p.name)
00566             elif p.name == '<':
00567                 templated_tokens, new_end = self._GetTemplateEnd(parts, i+1)
00568                 templated_types = self.ToType(templated_tokens)
00569                 i = new_end - 1
00570                 # Don't add a spurious :: to data members being initialized.
00571                 next_index = i + 1
00572                 if next_index < end and parts[next_index].name == '::':
00573                     i += 1
00574             elif p.name in ('[', ']', '='):
00575                 # These are handled elsewhere.
00576                 other_tokens.append(p)
00577             elif p.name not in ('*', '&', '>'):
00578                 # Ensure that names have a space between them.
00579                 if (type_name and type_name[-1].token_type == tokenize.NAME and
00580                     p.token_type == tokenize.NAME):
00581                     type_name.append(tokenize.Token(tokenize.SYNTAX, ' ', 0, 0))
00582                 type_name.append(p)
00583             else:
00584                 other_tokens.append(p)
00585             i += 1
00586         type_name = ''.join([t.name for t in type_name])
00587         return name, type_name, templated_types, modifiers, default, other_tokens
00588 
00589     def ToParameters(self, tokens):
00590         if not tokens:
00591             return []
00592 
00593         result = []
00594         name = type_name = ''
00595         type_modifiers = []
00596         pointer = reference = array = False
00597         first_token = None
00598         default = []
00599 
00600         def AddParameter():
00601             if default:
00602                 del default[0]  # Remove flag.
00603             end = type_modifiers[-1].end
00604             parts = self.DeclarationToParts(type_modifiers, True)
00605             (name, type_name, templated_types, modifiers,
00606              unused_default, unused_other_tokens) = parts
00607             parameter_type = Type(first_token.start, first_token.end,
00608                                   type_name, templated_types, modifiers,
00609                                   reference, pointer, array)
00610             p = Parameter(first_token.start, end, name,
00611                           parameter_type, default)
00612             result.append(p)
00613 
00614         template_count = 0
00615         for s in tokens:
00616             if not first_token:
00617                 first_token = s
00618             if s.name == '<':
00619                 template_count += 1
00620             elif s.name == '>':
00621                 template_count -= 1
00622             if template_count > 0:
00623                 type_modifiers.append(s)
00624                 continue
00625 
00626             if s.name == ',':
00627                 AddParameter()
00628                 name = type_name = ''
00629                 type_modifiers = []
00630                 pointer = reference = array = False
00631                 first_token = None
00632                 default = []
00633             elif s.name == '*':
00634                 pointer = True
00635             elif s.name == '&':
00636                 reference = True
00637             elif s.name == '[':
00638                 array = True
00639             elif s.name == ']':
00640                 pass  # Just don't add to type_modifiers.
00641             elif s.name == '=':
00642                 # Got a default value.  Add any value (None) as a flag.
00643                 default.append(None)
00644             elif default:
00645                 default.append(s)
00646             else:
00647                 type_modifiers.append(s)
00648         AddParameter()
00649         return result
00650 
00651     def CreateReturnType(self, return_type_seq):
00652         if not return_type_seq:
00653             return None
00654         start = return_type_seq[0].start
00655         end = return_type_seq[-1].end
00656         _, name, templated_types, modifiers, default, other_tokens = \
00657            self.DeclarationToParts(return_type_seq, False)
00658         names = [n.name for n in other_tokens]
00659         reference = '&' in names
00660         pointer = '*' in names
00661         array = '[' in names
00662         return Type(start, end, name, templated_types, modifiers,
00663                     reference, pointer, array)
00664 
00665     def GetTemplateIndices(self, names):
00666         # names is a list of strings.
00667         start = names.index('<')
00668         end = len(names) - 1
00669         while end > 0:
00670             if names[end] == '>':
00671                 break
00672             end -= 1
00673         return start, end+1
00674 
00675 class AstBuilder(object):
00676     def __init__(self, token_stream, filename, in_class='', visibility=None,
00677                  namespace_stack=[]):
00678         self.tokens = token_stream
00679         self.filename = filename
00680         # TODO(nnorwitz): use a better data structure (deque) for the queue.
00681         # Switching directions of the "queue" improved perf by about 25%.
00682         # Using a deque should be even better since we access from both sides.
00683         self.token_queue = []
00684         self.namespace_stack = namespace_stack[:]
00685         self.in_class = in_class
00686         if in_class is None:
00687             self.in_class_name_only = None
00688         else:
00689             self.in_class_name_only = in_class.split('::')[-1]
00690         self.visibility = visibility
00691         self.in_function = False
00692         self.current_token = None
00693         # Keep the state whether we are currently handling a typedef or not.
00694         self._handling_typedef = False
00695 
00696         self.converter = TypeConverter(self.namespace_stack)
00697 
00698     def HandleError(self, msg, token):
00699         printable_queue = list(reversed(self.token_queue[-20:]))
00700         sys.stderr.write('Got %s in %s @ %s %s\n' %
00701                          (msg, self.filename, token, printable_queue))
00702 
00703     def Generate(self):
00704         while 1:
00705             token = self._GetNextToken()
00706             if not token:
00707                 break
00708 
00709             # Get the next token.
00710             self.current_token = token
00711 
00712             # Dispatch on the next token type.
00713             if token.token_type == _INTERNAL_TOKEN:
00714                 if token.name == _NAMESPACE_POP:
00715                     self.namespace_stack.pop()
00716                 continue
00717 
00718             try:
00719                 result = self._GenerateOne(token)
00720                 if result is not None:
00721                     yield result
00722             except:
00723                 self.HandleError('exception', token)
00724                 raise
00725 
00726     def _CreateVariable(self, pos_token, name, type_name, type_modifiers,
00727                         ref_pointer_name_seq, templated_types, value=None):
00728         reference = '&' in ref_pointer_name_seq
00729         pointer = '*' in ref_pointer_name_seq
00730         array = '[' in ref_pointer_name_seq
00731         var_type = Type(pos_token.start, pos_token.end, type_name,
00732                         templated_types, type_modifiers,
00733                         reference, pointer, array)
00734         return VariableDeclaration(pos_token.start, pos_token.end,
00735                                    name, var_type, value, self.namespace_stack)
00736 
00737     def _GenerateOne(self, token):
00738         if token.token_type == tokenize.NAME:
00739             if (keywords.IsKeyword(token.name) and
00740                 not keywords.IsBuiltinType(token.name)):
00741                 method = getattr(self, 'handle_' + token.name)
00742                 return method()
00743             elif token.name == self.in_class_name_only:
00744                 # The token name is the same as the class, must be a ctor if
00745                 # there is a paren.  Otherwise, it's the return type.
00746                 # Peek ahead to get the next token to figure out which.
00747                 next = self._GetNextToken()
00748                 self._AddBackToken(next)
00749                 if next.token_type == tokenize.SYNTAX and next.name == '(':
00750                     return self._GetMethod([token], FUNCTION_CTOR, None, True)
00751                 # Fall through--handle like any other method.
00752 
00753             # Handle data or function declaration/definition.
00754             syntax = tokenize.SYNTAX
00755             temp_tokens, last_token = \
00756                 self._GetVarTokensUpTo(syntax, '(', ';', '{', '[')
00757             temp_tokens.insert(0, token)
00758             if last_token.name == '(':
00759                 # If there is an assignment before the paren,
00760                 # this is an expression, not a method.
00761                 expr = bool([e for e in temp_tokens if e.name == '='])
00762                 if expr:
00763                     new_temp = self._GetTokensUpTo(tokenize.SYNTAX, ';')
00764                     temp_tokens.append(last_token)
00765                     temp_tokens.extend(new_temp)
00766                     last_token = tokenize.Token(tokenize.SYNTAX, ';', 0, 0)
00767 
00768             if last_token.name == '[':
00769                 # Handle array, this isn't a method, unless it's an operator.
00770                 # TODO(nnorwitz): keep the size somewhere.
00771                 # unused_size = self._GetTokensUpTo(tokenize.SYNTAX, ']')
00772                 temp_tokens.append(last_token)
00773                 if temp_tokens[-2].name == 'operator':
00774                     temp_tokens.append(self._GetNextToken())
00775                 else:
00776                     temp_tokens2, last_token = \
00777                         self._GetVarTokensUpTo(tokenize.SYNTAX, ';')
00778                     temp_tokens.extend(temp_tokens2)
00779 
00780             if last_token.name == ';':
00781                 # Handle data, this isn't a method.
00782                 parts = self.converter.DeclarationToParts(temp_tokens, True)
00783                 (name, type_name, templated_types, modifiers, default,
00784                  unused_other_tokens) = parts
00785 
00786                 t0 = temp_tokens[0]
00787                 names = [t.name for t in temp_tokens]
00788                 if templated_types:
00789                     start, end = self.converter.GetTemplateIndices(names)
00790                     names = names[:start] + names[end:]
00791                 default = ''.join([t.name for t in default])
00792                 return self._CreateVariable(t0, name, type_name, modifiers,
00793                                             names, templated_types, default)
00794             if last_token.name == '{':
00795                 self._AddBackTokens(temp_tokens[1:])
00796                 self._AddBackToken(last_token)
00797                 method_name = temp_tokens[0].name
00798                 method = getattr(self, 'handle_' + method_name, None)
00799                 if not method:
00800                     # Must be declaring a variable.
00801                     # TODO(nnorwitz): handle the declaration.
00802                     return None
00803                 return method()
00804             return self._GetMethod(temp_tokens, 0, None, False)
00805         elif token.token_type == tokenize.SYNTAX:
00806             if token.name == '~' and self.in_class:
00807                 # Must be a dtor (probably not in method body).
00808                 token = self._GetNextToken()
00809                 # self.in_class can contain A::Name, but the dtor will only
00810                 # be Name.  Make sure to compare against the right value.
00811                 if (token.token_type == tokenize.NAME and
00812                     token.name == self.in_class_name_only):
00813                     return self._GetMethod([token], FUNCTION_DTOR, None, True)
00814             # TODO(nnorwitz): handle a lot more syntax.
00815         elif token.token_type == tokenize.PREPROCESSOR:
00816             # TODO(nnorwitz): handle more preprocessor directives.
00817             # token starts with a #, so remove it and strip whitespace.
00818             name = token.name[1:].lstrip()
00819             if name.startswith('include'):
00820                 # Remove "include".
00821                 name = name[7:].strip()
00822                 assert name
00823                 # Handle #include <newline> "header-on-second-line.h".
00824                 if name.startswith('\\'):
00825                     name = name[1:].strip()
00826                 assert name[0] in '<"', token
00827                 assert name[-1] in '>"', token
00828                 system = name[0] == '<'
00829                 filename = name[1:-1]
00830                 return Include(token.start, token.end, filename, system)
00831             if name.startswith('define'):
00832                 # Remove "define".
00833                 name = name[6:].strip()
00834                 assert name
00835                 value = ''
00836                 for i, c in enumerate(name):
00837                     if c.isspace():
00838                         value = name[i:].lstrip()
00839                         name = name[:i]
00840                         break
00841                 return Define(token.start, token.end, name, value)
00842             if name.startswith('if') and name[2:3].isspace():
00843                 condition = name[3:].strip()
00844                 if condition.startswith('0') or condition.startswith('(0)'):
00845                     self._SkipIf0Blocks()
00846         return None
00847 
00848     def _GetTokensUpTo(self, expected_token_type, expected_token):
00849         return self._GetVarTokensUpTo(expected_token_type, expected_token)[0]
00850 
00851     def _GetVarTokensUpTo(self, expected_token_type, *expected_tokens):
00852         last_token = self._GetNextToken()
00853         tokens = []
00854         while (last_token.token_type != expected_token_type or
00855                last_token.name not in expected_tokens):
00856             tokens.append(last_token)
00857             last_token = self._GetNextToken()
00858         return tokens, last_token
00859 
00860     # TODO(nnorwitz): remove _IgnoreUpTo() it shouldn't be necesary.
00861     def _IgnoreUpTo(self, token_type, token):
00862         unused_tokens = self._GetTokensUpTo(token_type, token)
00863 
00864     def _SkipIf0Blocks(self):
00865         count = 1
00866         while 1:
00867             token = self._GetNextToken()
00868             if token.token_type != tokenize.PREPROCESSOR:
00869                 continue
00870 
00871             name = token.name[1:].lstrip()
00872             if name.startswith('endif'):
00873                 count -= 1
00874                 if count == 0:
00875                     break
00876             elif name.startswith('if'):
00877                 count += 1
00878 
00879     def _GetMatchingChar(self, open_paren, close_paren, GetNextToken=None):
00880         if GetNextToken is None:
00881             GetNextToken = self._GetNextToken
00882         # Assumes the current token is open_paren and we will consume
00883         # and return up to the close_paren.
00884         count = 1
00885         token = GetNextToken()
00886         while 1:
00887             if token.token_type == tokenize.SYNTAX:
00888                 if token.name == open_paren:
00889                     count += 1
00890                 elif token.name == close_paren:
00891                     count -= 1
00892                     if count == 0:
00893                         break
00894             yield token
00895             token = GetNextToken()
00896         yield token
00897 
00898     def _GetParameters(self):
00899         return self._GetMatchingChar('(', ')')
00900 
00901     def GetScope(self):
00902         return self._GetMatchingChar('{', '}')
00903 
00904     def _GetNextToken(self):
00905         if self.token_queue:
00906             return self.token_queue.pop()
00907         return next(self.tokens)
00908 
00909     def _AddBackToken(self, token):
00910         if token.whence == tokenize.WHENCE_STREAM:
00911             token.whence = tokenize.WHENCE_QUEUE
00912             self.token_queue.insert(0, token)
00913         else:
00914             assert token.whence == tokenize.WHENCE_QUEUE, token
00915             self.token_queue.append(token)
00916 
00917     def _AddBackTokens(self, tokens):
00918         if tokens:
00919             if tokens[-1].whence == tokenize.WHENCE_STREAM:
00920                 for token in tokens:
00921                     token.whence = tokenize.WHENCE_QUEUE
00922                 self.token_queue[:0] = reversed(tokens)
00923             else:
00924                 assert tokens[-1].whence == tokenize.WHENCE_QUEUE, tokens
00925                 self.token_queue.extend(reversed(tokens))
00926 
00927     def GetName(self, seq=None):
00928         """Returns ([tokens], next_token_info)."""
00929         GetNextToken = self._GetNextToken
00930         if seq is not None:
00931             it = iter(seq)
00932             GetNextToken = lambda: next(it)
00933         next_token = GetNextToken()
00934         tokens = []
00935         last_token_was_name = False
00936         while (next_token.token_type == tokenize.NAME or
00937                (next_token.token_type == tokenize.SYNTAX and
00938                 next_token.name in ('::', '<'))):
00939             # Two NAMEs in a row means the identifier should terminate.
00940             # It's probably some sort of variable declaration.
00941             if last_token_was_name and next_token.token_type == tokenize.NAME:
00942                 break
00943             last_token_was_name = next_token.token_type == tokenize.NAME
00944             tokens.append(next_token)
00945             # Handle templated names.
00946             if next_token.name == '<':
00947                 tokens.extend(self._GetMatchingChar('<', '>', GetNextToken))
00948                 last_token_was_name = True
00949             next_token = GetNextToken()
00950         return tokens, next_token
00951 
00952     def GetMethod(self, modifiers, templated_types):
00953         return_type_and_name = self._GetTokensUpTo(tokenize.SYNTAX, '(')
00954         assert len(return_type_and_name) >= 1
00955         return self._GetMethod(return_type_and_name, modifiers, templated_types,
00956                                False)
00957 
00958     def _GetMethod(self, return_type_and_name, modifiers, templated_types,
00959                    get_paren):
00960         template_portion = None
00961         if get_paren:
00962             token = self._GetNextToken()
00963             assert token.token_type == tokenize.SYNTAX, token
00964             if token.name == '<':
00965                 # Handle templatized dtors.
00966                 template_portion = [token]
00967                 template_portion.extend(self._GetMatchingChar('<', '>'))
00968                 token = self._GetNextToken()
00969             assert token.token_type == tokenize.SYNTAX, token
00970             assert token.name == '(', token
00971 
00972         name = return_type_and_name.pop()
00973         # Handle templatized ctors.
00974         if name.name == '>':
00975             index = 1
00976             while return_type_and_name[index].name != '<':
00977                 index += 1
00978             template_portion = return_type_and_name[index:] + [name]
00979             del return_type_and_name[index:]
00980             name = return_type_and_name.pop()
00981         elif name.name == ']':
00982             rt = return_type_and_name
00983             assert rt[-1].name == '[', return_type_and_name
00984             assert rt[-2].name == 'operator', return_type_and_name
00985             name_seq = return_type_and_name[-2:]
00986             del return_type_and_name[-2:]
00987             name = tokenize.Token(tokenize.NAME, 'operator[]',
00988                                   name_seq[0].start, name.end)
00989             # Get the open paren so _GetParameters() below works.
00990             unused_open_paren = self._GetNextToken()
00991 
00992         # TODO(nnorwitz): store template_portion.
00993         return_type = return_type_and_name
00994         indices = name
00995         if return_type:
00996             indices = return_type[0]
00997 
00998         # Force ctor for templatized ctors.
00999         if name.name == self.in_class and not modifiers:
01000             modifiers |= FUNCTION_CTOR
01001         parameters = list(self._GetParameters())
01002         del parameters[-1]              # Remove trailing ')'.
01003 
01004         # Handling operator() is especially weird.
01005         if name.name == 'operator' and not parameters:
01006             token = self._GetNextToken()
01007             assert token.name == '(', token
01008             parameters = list(self._GetParameters())
01009             del parameters[-1]          # Remove trailing ')'.
01010 
01011         token = self._GetNextToken()
01012         while token.token_type == tokenize.NAME:
01013             modifier_token = token
01014             token = self._GetNextToken()
01015             if modifier_token.name == 'const':
01016                 modifiers |= FUNCTION_CONST
01017             elif modifier_token.name == '__attribute__':
01018                 # TODO(nnorwitz): handle more __attribute__ details.
01019                 modifiers |= FUNCTION_ATTRIBUTE
01020                 assert token.name == '(', token
01021                 # Consume everything between the (parens).
01022                 unused_tokens = list(self._GetMatchingChar('(', ')'))
01023                 token = self._GetNextToken()
01024             elif modifier_token.name == 'throw':
01025                 modifiers |= FUNCTION_THROW
01026                 assert token.name == '(', token
01027                 # Consume everything between the (parens).
01028                 unused_tokens = list(self._GetMatchingChar('(', ')'))
01029                 token = self._GetNextToken()
01030             elif modifier_token.name == modifier_token.name.upper():
01031                 # HACK(nnorwitz):  assume that all upper-case names
01032                 # are some macro we aren't expanding.
01033                 modifiers |= FUNCTION_UNKNOWN_ANNOTATION
01034             else:
01035                 self.HandleError('unexpected token', modifier_token)
01036 
01037         assert token.token_type == tokenize.SYNTAX, token
01038         # Handle ctor initializers.
01039         if token.name == ':':
01040             # TODO(nnorwitz): anything else to handle for initializer list?
01041             while token.name != ';' and token.name != '{':
01042                 token = self._GetNextToken()
01043 
01044         # Handle pointer to functions that are really data but look
01045         # like method declarations.
01046         if token.name == '(':
01047             if parameters[0].name == '*':
01048                 # name contains the return type.
01049                 name = parameters.pop()
01050                 # parameters contains the name of the data.
01051                 modifiers = [p.name for p in parameters]
01052                 # Already at the ( to open the parameter list.
01053                 function_parameters = list(self._GetMatchingChar('(', ')'))
01054                 del function_parameters[-1]  # Remove trailing ')'.
01055                 # TODO(nnorwitz): store the function_parameters.
01056                 token = self._GetNextToken()
01057                 assert token.token_type == tokenize.SYNTAX, token
01058                 assert token.name == ';', token
01059                 return self._CreateVariable(indices, name.name, indices.name,
01060                                             modifiers, '', None)
01061             # At this point, we got something like:
01062             #  return_type (type::*name_)(params);
01063             # This is a data member called name_ that is a function pointer.
01064             # With this code: void (sq_type::*field_)(string&);
01065             # We get: name=void return_type=[] parameters=sq_type ... field_
01066             # TODO(nnorwitz): is return_type always empty?
01067             # TODO(nnorwitz): this isn't even close to being correct.
01068             # Just put in something so we don't crash and can move on.
01069             real_name = parameters[-1]
01070             modifiers = [p.name for p in self._GetParameters()]
01071             del modifiers[-1]           # Remove trailing ')'.
01072             return self._CreateVariable(indices, real_name.name, indices.name,
01073                                         modifiers, '', None)
01074 
01075         if token.name == '{':
01076             body = list(self.GetScope())
01077             del body[-1]                # Remove trailing '}'.
01078         else:
01079             body = None
01080             if token.name == '=':
01081                 token = self._GetNextToken()
01082                 assert token.token_type == tokenize.CONSTANT, token
01083                 assert token.name == '0', token
01084                 modifiers |= FUNCTION_PURE_VIRTUAL
01085                 token = self._GetNextToken()
01086 
01087             if token.name == '[':
01088                 # TODO(nnorwitz): store tokens and improve parsing.
01089                 # template <typename T, size_t N> char (&ASH(T (&seq)[N]))[N];
01090                 tokens = list(self._GetMatchingChar('[', ']'))
01091                 token = self._GetNextToken()
01092 
01093             assert token.name == ';', (token, return_type_and_name, parameters)
01094 
01095         # Looks like we got a method, not a function.
01096         if len(return_type) > 2 and return_type[-1].name == '::':
01097             return_type, in_class = \
01098                          self._GetReturnTypeAndClassName(return_type)
01099             return Method(indices.start, indices.end, name.name, in_class,
01100                           return_type, parameters, modifiers, templated_types,
01101                           body, self.namespace_stack)
01102         return Function(indices.start, indices.end, name.name, return_type,
01103                         parameters, modifiers, templated_types, body,
01104                         self.namespace_stack)
01105 
01106     def _GetReturnTypeAndClassName(self, token_seq):
01107         # Splitting the return type from the class name in a method
01108         # can be tricky.  For example, Return::Type::Is::Hard::To::Find().
01109         # Where is the return type and where is the class name?
01110         # The heuristic used is to pull the last name as the class name.
01111         # This includes all the templated type info.
01112         # TODO(nnorwitz): if there is only One name like in the
01113         # example above, punt and assume the last bit is the class name.
01114 
01115         # Ignore a :: prefix, if exists so we can find the first real name.
01116         i = 0
01117         if token_seq[0].name == '::':
01118             i = 1
01119         # Ignore a :: suffix, if exists.
01120         end = len(token_seq) - 1
01121         if token_seq[end-1].name == '::':
01122             end -= 1
01123 
01124         # Make a copy of the sequence so we can append a sentinel
01125         # value. This is required for GetName will has to have some
01126         # terminating condition beyond the last name.
01127         seq_copy = token_seq[i:end]
01128         seq_copy.append(tokenize.Token(tokenize.SYNTAX, '', 0, 0))
01129         names = []
01130         while i < end:
01131             # Iterate through the sequence parsing out each name.
01132             new_name, next = self.GetName(seq_copy[i:])
01133             assert new_name, 'Got empty new_name, next=%s' % next
01134             # We got a pointer or ref.  Add it to the name.
01135             if next and next.token_type == tokenize.SYNTAX:
01136                 new_name.append(next)
01137             names.append(new_name)
01138             i += len(new_name)
01139 
01140         # Now that we have the names, it's time to undo what we did.
01141 
01142         # Remove the sentinel value.
01143         names[-1].pop()
01144         # Flatten the token sequence for the return type.
01145         return_type = [e for seq in names[:-1] for e in seq]
01146         # The class name is the last name.
01147         class_name = names[-1]
01148         return return_type, class_name
01149 
01150     def handle_bool(self):
01151         pass
01152 
01153     def handle_char(self):
01154         pass
01155 
01156     def handle_int(self):
01157         pass
01158 
01159     def handle_long(self):
01160         pass
01161 
01162     def handle_short(self):
01163         pass
01164 
01165     def handle_double(self):
01166         pass
01167 
01168     def handle_float(self):
01169         pass
01170 
01171     def handle_void(self):
01172         pass
01173 
01174     def handle_wchar_t(self):
01175         pass
01176 
01177     def handle_unsigned(self):
01178         pass
01179 
01180     def handle_signed(self):
01181         pass
01182 
01183     def _GetNestedType(self, ctor):
01184         name = None
01185         name_tokens, token = self.GetName()
01186         if name_tokens:
01187             name = ''.join([t.name for t in name_tokens])
01188 
01189         # Handle forward declarations.
01190         if token.token_type == tokenize.SYNTAX and token.name == ';':
01191             return ctor(token.start, token.end, name, None,
01192                         self.namespace_stack)
01193 
01194         if token.token_type == tokenize.NAME and self._handling_typedef:
01195             self._AddBackToken(token)
01196             return ctor(token.start, token.end, name, None,
01197                         self.namespace_stack)
01198 
01199         # Must be the type declaration.
01200         fields = list(self._GetMatchingChar('{', '}'))
01201         del fields[-1]                  # Remove trailing '}'.
01202         if token.token_type == tokenize.SYNTAX and token.name == '{':
01203             next = self._GetNextToken()
01204             new_type = ctor(token.start, token.end, name, fields,
01205                             self.namespace_stack)
01206             # A name means this is an anonymous type and the name
01207             # is the variable declaration.
01208             if next.token_type != tokenize.NAME:
01209                 return new_type
01210             name = new_type
01211             token = next
01212 
01213         # Must be variable declaration using the type prefixed with keyword.
01214         assert token.token_type == tokenize.NAME, token
01215         return self._CreateVariable(token, token.name, name, [], '', None)
01216 
01217     def handle_struct(self):
01218         # Special case the handling typedef/aliasing of structs here.
01219         # It would be a pain to handle in the class code.
01220         name_tokens, var_token = self.GetName()
01221         if name_tokens:
01222             next_token = self._GetNextToken()
01223             is_syntax = (var_token.token_type == tokenize.SYNTAX and
01224                          var_token.name[0] in '*&')
01225             is_variable = (var_token.token_type == tokenize.NAME and
01226                            next_token.name == ';')
01227             variable = var_token
01228             if is_syntax and not is_variable:
01229                 variable = next_token
01230                 temp = self._GetNextToken()
01231                 if temp.token_type == tokenize.SYNTAX and temp.name == '(':
01232                     # Handle methods declared to return a struct.
01233                     t0 = name_tokens[0]
01234                     struct = tokenize.Token(tokenize.NAME, 'struct',
01235                                             t0.start-7, t0.start-2)
01236                     type_and_name = [struct]
01237                     type_and_name.extend(name_tokens)
01238                     type_and_name.extend((var_token, next_token))
01239                     return self._GetMethod(type_and_name, 0, None, False)
01240                 assert temp.name == ';', (temp, name_tokens, var_token)
01241             if is_syntax or (is_variable and not self._handling_typedef):
01242                 modifiers = ['struct']
01243                 type_name = ''.join([t.name for t in name_tokens])
01244                 position = name_tokens[0]
01245                 return self._CreateVariable(position, variable.name, type_name,
01246                                             modifiers, var_token.name, None)
01247             name_tokens.extend((var_token, next_token))
01248             self._AddBackTokens(name_tokens)
01249         else:
01250             self._AddBackToken(var_token)
01251         return self._GetClass(Struct, VISIBILITY_PUBLIC, None)
01252 
01253     def handle_union(self):
01254         return self._GetNestedType(Union)
01255 
01256     def handle_enum(self):
01257         return self._GetNestedType(Enum)
01258 
01259     def handle_auto(self):
01260         # TODO(nnorwitz): warn about using auto?  Probably not since it
01261         # will be reclaimed and useful for C++0x.
01262         pass
01263 
01264     def handle_register(self):
01265         pass
01266 
01267     def handle_const(self):
01268         pass
01269 
01270     def handle_inline(self):
01271         pass
01272 
01273     def handle_extern(self):
01274         pass
01275 
01276     def handle_static(self):
01277         pass
01278 
01279     def handle_virtual(self):
01280         # What follows must be a method.
01281         token = token2 = self._GetNextToken()
01282         if token.name == 'inline':
01283             # HACK(nnorwitz): handle inline dtors by ignoring 'inline'.
01284             token2 = self._GetNextToken()
01285         if token2.token_type == tokenize.SYNTAX and token2.name == '~':
01286             return self.GetMethod(FUNCTION_VIRTUAL + FUNCTION_DTOR, None)
01287         assert token.token_type == tokenize.NAME or token.name == '::', token
01288         return_type_and_name = self._GetTokensUpTo(tokenize.SYNTAX, '(')
01289         return_type_and_name.insert(0, token)
01290         if token2 is not token:
01291             return_type_and_name.insert(1, token2)
01292         return self._GetMethod(return_type_and_name, FUNCTION_VIRTUAL,
01293                                None, False)
01294 
01295     def handle_volatile(self):
01296         pass
01297 
01298     def handle_mutable(self):
01299         pass
01300 
01301     def handle_public(self):
01302         assert self.in_class
01303         self.visibility = VISIBILITY_PUBLIC
01304 
01305     def handle_protected(self):
01306         assert self.in_class
01307         self.visibility = VISIBILITY_PROTECTED
01308 
01309     def handle_private(self):
01310         assert self.in_class
01311         self.visibility = VISIBILITY_PRIVATE
01312 
01313     def handle_friend(self):
01314         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';')
01315         assert tokens
01316         t0 = tokens[0]
01317         return Friend(t0.start, t0.end, tokens, self.namespace_stack)
01318 
01319     def handle_static_cast(self):
01320         pass
01321 
01322     def handle_const_cast(self):
01323         pass
01324 
01325     def handle_dynamic_cast(self):
01326         pass
01327 
01328     def handle_reinterpret_cast(self):
01329         pass
01330 
01331     def handle_new(self):
01332         pass
01333 
01334     def handle_delete(self):
01335         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';')
01336         assert tokens
01337         return Delete(tokens[0].start, tokens[0].end, tokens)
01338 
01339     def handle_typedef(self):
01340         token = self._GetNextToken()
01341         if (token.token_type == tokenize.NAME and
01342             keywords.IsKeyword(token.name)):
01343             # Token must be struct/enum/union/class.
01344             method = getattr(self, 'handle_' + token.name)
01345             self._handling_typedef = True
01346             tokens = [method()]
01347             self._handling_typedef = False
01348         else:
01349             tokens = [token]
01350 
01351         # Get the remainder of the typedef up to the semi-colon.
01352         tokens.extend(self._GetTokensUpTo(tokenize.SYNTAX, ';'))
01353 
01354         # TODO(nnorwitz): clean all this up.
01355         assert tokens
01356         name = tokens.pop()
01357         indices = name
01358         if tokens:
01359             indices = tokens[0]
01360         if not indices:
01361             indices = token
01362         if name.name == ')':
01363             # HACK(nnorwitz): Handle pointers to functions "properly".
01364             if (len(tokens) >= 4 and
01365                 tokens[1].name == '(' and tokens[2].name == '*'):
01366                 tokens.append(name)
01367                 name = tokens[3]
01368         elif name.name == ']':
01369             # HACK(nnorwitz): Handle arrays properly.
01370             if len(tokens) >= 2:
01371                 tokens.append(name)
01372                 name = tokens[1]
01373         new_type = tokens
01374         if tokens and isinstance(tokens[0], tokenize.Token):
01375             new_type = self.converter.ToType(tokens)[0]
01376         return Typedef(indices.start, indices.end, name.name,
01377                        new_type, self.namespace_stack)
01378 
01379     def handle_typeid(self):
01380         pass  # Not needed yet.
01381 
01382     def handle_typename(self):
01383         pass  # Not needed yet.
01384 
01385     def _GetTemplatedTypes(self):
01386         result = {}
01387         tokens = list(self._GetMatchingChar('<', '>'))
01388         len_tokens = len(tokens) - 1    # Ignore trailing '>'.
01389         i = 0
01390         while i < len_tokens:
01391             key = tokens[i].name
01392             i += 1
01393             if keywords.IsKeyword(key) or key == ',':
01394                 continue
01395             type_name = default = None
01396             if i < len_tokens:
01397                 i += 1
01398                 if tokens[i-1].name == '=':
01399                     assert i < len_tokens, '%s %s' % (i, tokens)
01400                     default, unused_next_token = self.GetName(tokens[i:])
01401                     i += len(default)
01402                 else:
01403                     if tokens[i-1].name != ',':
01404                         # We got something like: Type variable.
01405                         # Re-adjust the key (variable) and type_name (Type).
01406                         key = tokens[i-1].name
01407                         type_name = tokens[i-2]
01408 
01409             result[key] = (type_name, default)
01410         return result
01411 
01412     def handle_template(self):
01413         token = self._GetNextToken()
01414         assert token.token_type == tokenize.SYNTAX, token
01415         assert token.name == '<', token
01416         templated_types = self._GetTemplatedTypes()
01417         # TODO(nnorwitz): for now, just ignore the template params.
01418         token = self._GetNextToken()
01419         if token.token_type == tokenize.NAME:
01420             if token.name == 'class':
01421                 return self._GetClass(Class, VISIBILITY_PRIVATE, templated_types)
01422             elif token.name == 'struct':
01423                 return self._GetClass(Struct, VISIBILITY_PUBLIC, templated_types)
01424             elif token.name == 'friend':
01425                 return self.handle_friend()
01426         self._AddBackToken(token)
01427         tokens, last = self._GetVarTokensUpTo(tokenize.SYNTAX, '(', ';')
01428         tokens.append(last)
01429         self._AddBackTokens(tokens)
01430         if last.name == '(':
01431             return self.GetMethod(FUNCTION_NONE, templated_types)
01432         # Must be a variable definition.
01433         return None
01434 
01435     def handle_true(self):
01436         pass  # Nothing to do.
01437 
01438     def handle_false(self):
01439         pass  # Nothing to do.
01440 
01441     def handle_asm(self):
01442         pass  # Not needed yet.
01443 
01444     def handle_class(self):
01445         return self._GetClass(Class, VISIBILITY_PRIVATE, None)
01446 
01447     def _GetBases(self):
01448         # Get base classes.
01449         bases = []
01450         while 1:
01451             token = self._GetNextToken()
01452             assert token.token_type == tokenize.NAME, token
01453             # TODO(nnorwitz): store kind of inheritance...maybe.
01454             if token.name not in ('public', 'protected', 'private'):
01455                 # If inheritance type is not specified, it is private.
01456                 # Just put the token back so we can form a name.
01457                 # TODO(nnorwitz): it would be good to warn about this.
01458                 self._AddBackToken(token)
01459             else:
01460                 # Check for virtual inheritance.
01461                 token = self._GetNextToken()
01462                 if token.name != 'virtual':
01463                     self._AddBackToken(token)
01464                 else:
01465                     # TODO(nnorwitz): store that we got virtual for this base.
01466                     pass
01467             base, next_token = self.GetName()
01468             bases_ast = self.converter.ToType(base)
01469             assert len(bases_ast) == 1, bases_ast
01470             bases.append(bases_ast[0])
01471             assert next_token.token_type == tokenize.SYNTAX, next_token
01472             if next_token.name == '{':
01473                 token = next_token
01474                 break
01475             # Support multiple inheritance.
01476             assert next_token.name == ',', next_token
01477         return bases, token
01478 
01479     def _GetClass(self, class_type, visibility, templated_types):
01480         class_name = None
01481         class_token = self._GetNextToken()
01482         if class_token.token_type != tokenize.NAME:
01483             assert class_token.token_type == tokenize.SYNTAX, class_token
01484             token = class_token
01485         else:
01486             # Skip any macro (e.g. storage class specifiers) after the
01487             # 'class' keyword.
01488             next_token = self._GetNextToken()
01489             if next_token.token_type == tokenize.NAME:
01490                 self._AddBackToken(next_token)
01491             else:
01492                 self._AddBackTokens([class_token, next_token])
01493             name_tokens, token = self.GetName()
01494             class_name = ''.join([t.name for t in name_tokens])
01495         bases = None
01496         if token.token_type == tokenize.SYNTAX:
01497             if token.name == ';':
01498                 # Forward declaration.
01499                 return class_type(class_token.start, class_token.end,
01500                                   class_name, None, templated_types, None,
01501                                   self.namespace_stack)
01502             if token.name in '*&':
01503                 # Inline forward declaration.  Could be method or data.
01504                 name_token = self._GetNextToken()
01505                 next_token = self._GetNextToken()
01506                 if next_token.name == ';':
01507                     # Handle data
01508                     modifiers = ['class']
01509                     return self._CreateVariable(class_token, name_token.name,
01510                                                 class_name,
01511                                                 modifiers, token.name, None)
01512                 else:
01513                     # Assume this is a method.
01514                     tokens = (class_token, token, name_token, next_token)
01515                     self._AddBackTokens(tokens)
01516                     return self.GetMethod(FUNCTION_NONE, None)
01517             if token.name == ':':
01518                 bases, token = self._GetBases()
01519 
01520         body = None
01521         if token.token_type == tokenize.SYNTAX and token.name == '{':
01522             assert token.token_type == tokenize.SYNTAX, token
01523             assert token.name == '{', token
01524 
01525             ast = AstBuilder(self.GetScope(), self.filename, class_name,
01526                              visibility, self.namespace_stack)
01527             body = list(ast.Generate())
01528 
01529             if not self._handling_typedef:
01530                 token = self._GetNextToken()
01531                 if token.token_type != tokenize.NAME:
01532                     assert token.token_type == tokenize.SYNTAX, token
01533                     assert token.name == ';', token
01534                 else:
01535                     new_class = class_type(class_token.start, class_token.end,
01536                                            class_name, bases, None,
01537                                            body, self.namespace_stack)
01538 
01539                     modifiers = []
01540                     return self._CreateVariable(class_token,
01541                                                 token.name, new_class,
01542                                                 modifiers, token.name, None)
01543         else:
01544             if not self._handling_typedef:
01545                 self.HandleError('non-typedef token', token)
01546             self._AddBackToken(token)
01547 
01548         return class_type(class_token.start, class_token.end, class_name,
01549                           bases, templated_types, body, self.namespace_stack)
01550 
01551     def handle_namespace(self):
01552         token = self._GetNextToken()
01553         # Support anonymous namespaces.
01554         name = None
01555         if token.token_type == tokenize.NAME:
01556             name = token.name
01557             token = self._GetNextToken()
01558         self.namespace_stack.append(name)
01559         assert token.token_type == tokenize.SYNTAX, token
01560         # Create an internal token that denotes when the namespace is complete.
01561         internal_token = tokenize.Token(_INTERNAL_TOKEN, _NAMESPACE_POP,
01562                                         None, None)
01563         internal_token.whence = token.whence
01564         if token.name == '=':
01565             # TODO(nnorwitz): handle aliasing namespaces.
01566             name, next_token = self.GetName()
01567             assert next_token.name == ';', next_token
01568             self._AddBackToken(internal_token)
01569         else:
01570             assert token.name == '{', token
01571             tokens = list(self.GetScope())
01572             # Replace the trailing } with the internal namespace pop token.
01573             tokens[-1] = internal_token
01574             # Handle namespace with nothing in it.
01575             self._AddBackTokens(tokens)
01576         return None
01577 
01578     def handle_using(self):
01579         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';')
01580         assert tokens
01581         return Using(tokens[0].start, tokens[0].end, tokens)
01582 
01583     def handle_explicit(self):
01584         assert self.in_class
01585         # Nothing much to do.
01586         # TODO(nnorwitz): maybe verify the method name == class name.
01587         # This must be a ctor.
01588         return self.GetMethod(FUNCTION_CTOR, None)
01589 
01590     def handle_this(self):
01591         pass  # Nothing to do.
01592 
01593     def handle_operator(self):
01594         # Pull off the next token(s?) and make that part of the method name.
01595         pass
01596 
01597     def handle_sizeof(self):
01598         pass
01599 
01600     def handle_case(self):
01601         pass
01602 
01603     def handle_switch(self):
01604         pass
01605 
01606     def handle_default(self):
01607         token = self._GetNextToken()
01608         assert token.token_type == tokenize.SYNTAX
01609         assert token.name == ':'
01610 
01611     def handle_if(self):
01612         pass
01613 
01614     def handle_else(self):
01615         pass
01616 
01617     def handle_return(self):
01618         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';')
01619         if not tokens:
01620             return Return(self.current_token.start, self.current_token.end, None)
01621         return Return(tokens[0].start, tokens[0].end, tokens)
01622 
01623     def handle_goto(self):
01624         tokens = self._GetTokensUpTo(tokenize.SYNTAX, ';')
01625         assert len(tokens) == 1, str(tokens)
01626         return Goto(tokens[0].start, tokens[0].end, tokens[0].name)
01627 
01628     def handle_try(self):
01629         pass  # Not needed yet.
01630 
01631     def handle_catch(self):
01632         pass  # Not needed yet.
01633 
01634     def handle_throw(self):
01635         pass  # Not needed yet.
01636 
01637     def handle_while(self):
01638         pass
01639 
01640     def handle_do(self):
01641         pass
01642 
01643     def handle_for(self):
01644         pass
01645 
01646     def handle_break(self):
01647         self._IgnoreUpTo(tokenize.SYNTAX, ';')
01648 
01649     def handle_continue(self):
01650         self._IgnoreUpTo(tokenize.SYNTAX, ';')
01651 
01652 
01653 def BuilderFromSource(source, filename):
01654     """Utility method that returns an AstBuilder from source code.
01655 
01656     Args:
01657       source: 'C++ source code'
01658       filename: 'file1'
01659 
01660     Returns:
01661       AstBuilder
01662     """
01663     return AstBuilder(tokenize.GetTokens(source), filename)
01664 
01665 
01666 def PrintIndentifiers(filename, should_print):
01667     """Prints all identifiers for a C++ source file.
01668 
01669     Args:
01670       filename: 'file1'
01671       should_print: predicate with signature: bool Function(token)
01672     """
01673     source = utils.ReadFile(filename, False)
01674     if source is None:
01675         sys.stderr.write('Unable to find: %s\n' % filename)
01676         return
01677 
01678     #print('Processing %s' % actual_filename)
01679     builder = BuilderFromSource(source, filename)
01680     try:
01681         for node in builder.Generate():
01682             if should_print(node):
01683                 print(node.name)
01684     except KeyboardInterrupt:
01685         return
01686     except:
01687         pass
01688 
01689 
01690 def PrintAllIndentifiers(filenames, should_print):
01691     """Prints all identifiers for each C++ source file in filenames.
01692 
01693     Args:
01694       filenames: ['file1', 'file2', ...]
01695       should_print: predicate with signature: bool Function(token)
01696     """
01697     for path in filenames:
01698         PrintIndentifiers(path, should_print)
01699 
01700 
01701 def main(argv):
01702     for filename in argv[1:]:
01703         source = utils.ReadFile(filename)
01704         if source is None:
01705             continue
01706 
01707         print('Processing %s' % filename)
01708         builder = BuilderFromSource(source, filename)
01709         try:
01710             entire_ast = filter(None, builder.Generate())
01711         except KeyboardInterrupt:
01712             return
01713         except:
01714             # Already printed a warning, print the traceback and continue.
01715             traceback.print_exc()
01716         else:
01717             if utils.DEBUG:
01718                 for ast in entire_ast:
01719                     print(ast)
01720 
01721 
01722 if __name__ == '__main__':
01723     main(sys.argv)


ros_opcua_impl_freeopcua
Author(s): Denis Štogl
autogenerated on Sat Jun 8 2019 18:24:39