OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [vendor/] [googletest/] [googlemock/] [scripts/] [generator/] [cpp/] [ast.py] - Blame information for rev 2

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.