Synopsis - Synopsis/ASG.py

File: Synopsis/ASG.py

      1#
      2# Copyright (C) 2000 Stefan Seefeld
      3# Copyright (C) 2000 Stephen Davies
      4# All rights reserved.
      5# Licensed to the public under the terms of the GNU LGPL (>= 2),
      6# see the file COPYING for details.
      7#
      8
      9"""Abstract Syntax Tree classes.
     10
     11This file contains classes which encapsulate nodes in the ASG. The base class
     12is the Declaration class that encapsulates a named declaration. All names used
     13are scoped tuples.
     14
     15Also defined in module scope are the constants DEFAULT, PUBLIC, PROTECTED and
     16PRIVATE.
     17"""
     18
     19# Accessibility constants
     20DEFAULT = 0
     21PUBLIC = 1
     22PROTECTED = 2
     23PRIVATE = 3
     24
     25def ccmp(a,b):
     26    """Compares classes of two objects"""
     27    return cmp(type(a),type(b)) or cmp(a.__class__,b.__class__)
     28
     29
     30class Error:
     31   """Exception class used by ASG internals."""
     32
     33   def __init__(self, err):
     34      self.err = err
     35   def __repr__(self):
     36      return self.err
     37
     38
     39class Debugger(type):
     40    """Wrap the object's 'accept' method, printing out the visitor's type.
     41    Useful for tracing visitors visiting declarations."""
     42
     43    def __init__(cls, name, bases, dict):
     44
     45        accept = dict['accept']
     46        "The original instancemethod."
     47
     48        def accept_wrapper(self, visitor):
     49            "The wrapper. The original 'accept' method is part of its closure."
     50            print '%s accepting %s.%s'%(self.__class__.__name__,
     51                                        visitor.__module__,
     52                                        visitor.__class__.__name__)
     53            accept(self, visitor)
     54
     55        setattr(cls, 'accept', accept_wrapper)
     56
     57
     58class TypeId(object):
     59    """Type-id abstract class."""
     60
     61    def __init__(self, language):
     62        self.language = language
     63
     64    def accept(self, visitor):
     65        """visitor pattern accept. @see Visitor"""
     66        pass
     67
     68    def __cmp__(self, other):
     69        "Comparison operator"
     70        return cmp(id(self),id(other))
     71
     72class NamedTypeId(TypeId):
     73    """Named type abstract class"""
     74
     75    def __init__(self, language, name):
     76        super(NamedTypeId, self).__init__(language)
     77        self.name = name
     78
     79class BuiltinTypeId(NamedTypeId):
     80    """Class for builtin type-ids"""
     81
     82    def __init__(self, language, name):
     83        super(BuiltinTypeId, self).__init__(language, name)
     84    def accept(self, visitor): visitor.visit_builtin_type_id(self)
     85    def __cmp__(self, other):
     86        "Comparison operator"
     87        return ccmp(self,other) or cmp(self.name,other.name)
     88    def __str__(self): return str(self.name)
     89
     90class DependentTypeId(NamedTypeId):
     91    """Class for template dependent type-ids"""
     92
     93    def __init__(self, language, name):
     94        super(DependentTypeId, self).__init__(language, name)
     95    def accept(self, visitor): visitor.visit_dependent_type_id(self)
     96    def __cmp__(self, other):
     97        "Comparison operator"
     98        return ccmp(self,other) or cmp(self.name,other.name)
     99    def __str__(self): return str(self.name)
    100
    101class UnknownTypeId(NamedTypeId):
    102    """Class for not (yet) known type-ids."""
    103    base = TypeId
    104    def __init__(self, language, name):
    105        super(UnknownTypeId, self).__init__(language, name)
    106        self.link = name
    107    def resolve(self, language, name, link):
    108        """Associate this type-id with an external reference, instead of a declaration."""
    109        self.base.language = language
    110        self.name = name
    111        self.link = link
    112    def accept(self, visitor): visitor.visit_unknown_type_id(self)
    113    def __cmp__(self, other):
    114        "Comparison operator"
    115        return ccmp(self,other) or cmp(self.name,other.name)
    116    def __str__(self): return str(self.name)
    117
    118class DeclaredTypeId(NamedTypeId):
    119    """Class for declared types"""
    120
    121    def __init__(self, language, name, declaration):
    122        super(DeclaredTypeId, self).__init__(language, name)
    123        self.declaration = declaration
    124
    125    def accept(self, visitor): visitor.visit_declared_type_id(self)
    126    def __cmp__(self, other):
    127        "Comparison operator"
    128        return ccmp(self,other) or cmp(self.name,other.name)
    129    def __str__(self): return str(self.name)
    130
    131class TemplateId(DeclaredTypeId):
    132    """Class for template-ids."""
    133
    134    def __init__(self, language, name, declaration, parameters):
    135
    136        super(TemplateId, self).__init__(language, name, declaration)
    137        self.parameters = parameters
    138    def accept(self, visitor): visitor.visit_template_id(self)
    139    def __cmp__(self, other):
    140        "Comparison operator"
    141        return ccmp(self,other) or cmp(self.parameters,other.parameters)
    142    def __str__(self):
    143        return "template<%s>%s"%(','.join([str(p) for p in self.parameters]), str(self.name))
    144
    145class ModifierTypeId(TypeId):
    146    """Class for alias types with modifiers (such as 'const', '&', etc.)"""
    147
    148    def __init__(self, language, alias, premod, postmod):
    149        super(ModifierTypeId, self).__init__(language)
    150        self.alias = alias
    151        self.premod = premod
    152        self.postmod = postmod
    153
    154    def accept(self, visitor): visitor.visit_modifier_type_id(self)
    155
    156    def __cmp__(self, other):
    157        "Comparison operator"
    158        return (ccmp(self,other)
    159                or cmp(self.alias,other.alias)
    160                or cmp(self.premod,other.premod)
    161                or cmp(self.postmod,other.postmod))
    162    def __str__(self):
    163        return "%s%s%s"%(''.join(['%s '%s for s in self.premod]),
    164                         str(self.alias),
    165                         ''.join(self.postmod))
    166
    167class ArrayTypeId(TypeId):
    168    """A modifier that adds array dimensions to a type-id."""
    169
    170    def __init__(self, language, alias, sizes):
    171        super(ArrayId, self).__init__(language)
    172        self.alias = alias
    173        self.sizes = sizes
    174    def accept(self, visitor): visitor.visit_array_type_id(self)
    175    def __cmp__(self, other):
    176        "Comparison operator"
    177        return (ccmp(self,other)
    178                or cmp(self.alias,other.alias)
    179                or cmp(self.sizes,other.sizes))
    180    def __str__(self):
    181        return "%s%s"%(str(self.alias),
    182                       ''.join(['[%d]'%s for s in self.sizes]))
    183
    184class ParametrizedTypeId(TypeId):
    185    """Class for parametrized type-id instances."""
    186
    187    def __init__(self, language, template, parameters):
    188
    189        super(ParametrizedTypeId, self).__init__(language)
    190        self.template = template
    191        self.parameters = parameters
    192
    193    def accept(self, visitor): visitor.visit_parametrized_type_id(self)
    194
    195    def __cmp__(self, other):
    196        "Comparison operator"
    197        return ccmp(self,other) or cmp(self.template,other.template)
    198    def __str__(self):
    199        return "%s<%s>"%('::'.join(self.template.name),
    200                         ','.join([str(a) for a in self.parameters]))
    201
    202class FunctionTypeId(TypeId):
    203    """Class for function (pointer) types."""
    204    def __init__(self, language, return_type, premod, parameters):
    205
    206        super(FunctionTypeId, self).__init__(language)
    207        self.return_type = return_type
    208        self.premod = premod
    209        self.parameters = parameters
    210
    211    def accept(self, visitor): visitor.visit_function_type_id(self)
    212
    213
    214class Dictionary(dict):
    215    """Dictionary extends the builtin 'dict' by adding a lookup method to it."""
    216
    217    def lookup(self, name, scopes):
    218        """locate 'name' in one of the scopes"""
    219        for s in scopes:
    220            scope = list(s)
    221            while len(scope) > 0:
    222                if self.has_key(scope + name):
    223                    return self[scope + name]
    224                else: del scope[-1]
    225        if self.has_key(name):
    226            return self[name]
    227        return None
    228
    229    def merge(self, dict):
    230        """merge in a foreign dictionary, overriding already defined types only
    231        if they are of type 'Unknown'."""
    232        for i in dict.keys():
    233            if self.has_key(i):
    234                if isinstance(self[i], UnknownTypeId):
    235                    self[i] = dict[i]
    236                else:
    237                    pass
    238            else: self[i] = dict[i]
    239
    240
    241class Declaration(object):
    242    """Declaration base class. Every declaration has a name, type,
    243    accessibility and annotations. The default accessibility is DEFAULT except for
    244    C++ where the Parser always sets it to one of the other three. """
    245
    246    #__metaclass__ = Debugger
    247
    248    def __init__(self, file, line, type, name):
    249
    250        self.file  = file
    251        """SourceFile instance this declaration is part of."""
    252        self.line  = line
    253        """The line number of this declaration."""
    254        self.name = name
    255        """The (fully qualified) name of the declared object."""
    256        self.type = type
    257        """A string describing the (language-specific) type of the declared object."""
    258        self.accessibility = DEFAULT
    259        """Accessibility descriptor for the declared object."""
    260        self.annotations = {}
    261        """A dictionary holding any annotations of this object."""
    262
    263    def accept(self, visitor):
    264        """Visit the given visitor"""
    265        visitor.visit_declaration(self)
    266
    267
    268class Builtin(Declaration):
    269   """A node for internal use only."""
    270
    271   def accept(self, visitor): visitor.visit_builtin(self)
    272
    273
    274class UsingDirective(Builtin):
    275   """Import one module's content into another."""
    276
    277   def accept(self, visitor): visitor.visit_using_directive(self)
    278
    279
    280class UsingDeclaration(Builtin):
    281    """Import a declaration into this module."""
    282
    283    def __init__(self, file, line, type, name, alias):
    284
    285        super(UsingDeclaration, self).__init__(file, line, type, name)
    286        self.alias = alias
    287
    288    def accept(self, visitor):
    289        visitor.visit_using_declaration(self)
    290
    291
    292class Macro(Declaration):
    293   """A preprocessor macro. Note that macros are not strictly part of the
    294   ASG, and as such are always in the global scope. A macro is "temporary" if
    295   it was #undefined in the same file it was #defined in."""
    296
    297   def __init__(self, file, line, type, name, parameters, text):
    298
    299      Declaration.__init__(self, file, line, type, name)
    300      self.parameters = parameters
    301      self.text = text
    302
    303   def accept(self, visitor): visitor.visit_macro(self)
    304
    305
    306class Forward(Declaration):
    307   """Forward declaration"""
    308
    309   def __init__(self, file, line, type, name, is_template_specialization = False):
    310
    311      Declaration.__init__(self, file, line, type, name)
    312      self.template = None
    313      self.is_template_specialization = is_template_specialization
    314      self.primary_template = None
    315      self.specializations = []
    316
    317   def accept(self, visitor):
    318
    319       visitor.visit_forward(self)
    320
    321
    322class Group(Declaration):
    323   """Base class for groups which contain declarations.
    324   This class doesn't correspond to any language construct.
    325   Rather, it may be used with comment-embedded grouping tags
    326   to regroup declarations that are to appear together in the
    327   manual."""
    328
    329   def __init__(self, file, line, type, name):
    330
    331      Declaration.__init__(self, file, line, type, name)
    332      self.declarations = []
    333
    334   def accept(self, visitor):
    335
    336      visitor.visit_group(self)
    337
    338
    339class Scope(Declaration):
    340   """Base class for scopes (named groups)."""
    341
    342   def __init__(self, file, line, type, name):
    343
    344      Declaration.__init__(self, file, line, type, name)
    345      self.declarations = []
    346
    347   def accept(self, visitor): visitor.visit_scope(self)
    348
    349
    350class Module(Scope):
    351   """Module class"""
    352   def __init__(self, file, line, type, name):
    353
    354      Scope.__init__(self, file, line, type, name)
    355
    356   def accept(self, visitor): visitor.visit_module(self)
    357
    358
    359class MetaModule(Module):
    360   """Module Class that references all places where this Module occurs"""
    361
    362   def __init__(self, type, name):
    363
    364      Scope.__init__(self, None, "", type, name)
    365      self.module_declarations = []
    366
    367   def accept(self, visitor): visitor.visit_meta_module(self)
    368
    369
    370class Inheritance(object):
    371   """Inheritance class. This class encapsulates the information about an
    372   inheritance, such as attributes like 'virtual' and 'public' """
    373
    374   def __init__(self, type, parent, attributes):
    375      self.type = type
    376      self.parent = parent
    377      self.attributes = attributes
    378
    379   def accept(self, visitor): visitor.visit_inheritance(self)
    380
    381
    382class Class(Scope):
    383
    384   def __init__(self, file, line, type, name, is_template_specialization = False):
    385
    386      Scope.__init__(self, file, line, type, name)
    387      self.parents = []
    388      self.is_template_specialization = is_template_specialization
    389      self.primary_template = None
    390
    391   def accept(self, visitor): visitor.visit_class(self)
    392
    393
    394class ClassTemplate(Scope):
    395
    396   def __init__(self, file, line, type, name,
    397                template = None, is_template_specialization = False):
    398
    399      Scope.__init__(self, file, line, type, name)
    400      self.parents = []
    401      self.template = template
    402      self.is_template_specialization = is_template_specialization
    403      self.primary_template = None
    404      self.specializations = []
    405
    406   def accept(self, visitor): visitor.visit_class_template(self)
    407
    408
    409class Typedef(Declaration):
    410
    411   def __init__(self, file, line, type, name, alias, constr):
    412      Declaration.__init__(self, file, line, type, name)
    413      self.alias = alias
    414      self.constr = constr
    415
    416   def accept(self, visitor): visitor.visit_typedef(self)
    417
    418
    419class Enumerator(Declaration):
    420   """Enumerator of an Enum. Enumerators represent the individual names and
    421   values in an enum."""
    422
    423   def __init__(self, file, line, name, value):
    424      Declaration.__init__(self, file, line, "enumerator", name)
    425      self.value = value
    426
    427   def accept(self, visitor): visitor.visit_enumerator(self)
    428
    429class Enum(Declaration):
    430   """Enum declaration. The actual names and values are encapsulated by
    431   Enumerator objects."""
    432
    433   def __init__(self, file, line, name, enumerators):
    434
    435      Declaration.__init__(self, file, line, "enum", name)
    436      self.enumerators = enumerators[:]
    437      #FIXME: the Cxx parser will append a Builtin('eos') to the
    438      #list of enumerators which we need to extract here.
    439      self.eos = None
    440      if self.enumerators and isinstance(self.enumerators[-1], Builtin):
    441         self.eos = self.enumerators.pop()
    442
    443   def accept(self, visitor): visitor.visit_enum(self)
    444
    445
    446class Variable(Declaration):
    447   """Variable definition"""
    448
    449   def __init__(self, file, line, type, name, vtype, constr):
    450      Declaration.__init__(self, file, line, type, name)
    451      self.vtype  = vtype
    452      self.constr  = constr
    453
    454   def accept(self, visitor): visitor.visit_variable(self)
    455
    456
    457class Const(Declaration):
    458   """Constant declaration. A constant is a name with a type and value."""
    459
    460   def __init__(self, file, line, type, ctype, name, value):
    461      Declaration.__init__(self, file, line, type, name)
    462      self.ctype  = ctype
    463      self.value = value
    464
    465   def accept(self, visitor): visitor.visit_const(self)
    466
    467
    468class Parameter(object):
    469   """Function Parameter"""
    470
    471   def __init__(self, premod, type, postmod, name='', value=''):
    472      self.premodifier = premod
    473      self.type = type
    474      self.postmodifier = postmod
    475      self.name = name
    476      self.value = value
    477
    478   def accept(self, visitor): visitor.visit_parameter(self)
    479
    480   def __cmp__(self, other):
    481      "Comparison operator"
    482      #print "Parameter.__cmp__"
    483      return cmp(self.type,other.type)
    484   def __str__(self):
    485      return "%s%s%s"%(' '.join(self.premodifier),
    486                       str(self.type),
    487                       ' '.join(self.postmodifier))
    488
    489class Function(Declaration):
    490   """Function declaration.
    491   Note that function names are stored in mangled form to allow overriding.
    492   Formatters should use the real_name to extract the unmangled name."""
    493
    494   def __init__(self, file, line, type, premod, return_type, postmod, name, real_name):
    495      Declaration.__init__(self, file, line, type, name)
    496      self._real_name = real_name
    497      self.premodifier = premod
    498      self.return_type = return_type
    499      self.parameters = []
    500      self.postmodifier = postmod
    501      self.exceptions = []
    502
    503   real_name = property(lambda self: self.name[:-1] + (self._real_name,))
    504
    505   def accept(self, visitor): visitor.visit_function(self)
    506
    507   def __cmp__(self, other):
    508      "Recursively compares the typespec of the function"
    509      return ccmp(self,other) or cmp(self.parameters, other.parameters)
    510
    511
    512class FunctionTemplate(Function):
    513
    514   def __init__(self, file, line, type, premod, return_type, postmod, name, real_name, template = None):
    515      Function.__init__(self, file, line, type, premod, return_type, postmod, name, real_name)
    516      self.template = template
    517
    518   def accept(self, visitor): visitor.visit_function_template(self)
    519
    520
    521class Operation(Function):
    522   """Operation class. An operation is related to a Function and is currently
    523   identical.
    524   """
    525   def __init__(self, file, line, type, premod, return_type, postmod, name, real_name):
    526      Function.__init__(self, file, line, type, premod, return_type, postmod, name, real_name)
    527
    528   def accept(self, visitor): visitor.visit_operation(self)
    529
    530
    531class OperationTemplate(Operation):
    532
    533   def __init__(self, file, line, type, premod, return_type, postmod, name, real_name, template = None):
    534      Operation.__init__(self, file, line, type, premod, return_type, postmod, name, real_name)
    535      self.template = template
    536
    537   def accept(self, visitor): visitor.visit_operation_template(self)
    538
    539
    540class Visitor(object):
    541   """Visitor for ASG nodes"""
    542
    543   def visit_builtin_type_id(self, type): pass
    544   def visit_unknown_type_id(self, type): pass
    545   def visit_declared_type_id(self, type): pass
    546   def visit_modifier_type_id(self, type): pass
    547   def visit_array_type_id(self, type): pass
    548   def visit_template_id(self, type): pass
    549   def visit_parametrized_type_id(self, type): pass
    550   def visit_function_type_id(self, type): pass
    551   def visit_dependent_type_id(self, type): pass
    552
    553   def visit_declaration(self, node): pass
    554   def visit_builtin(self, node):
    555      """Visit a Builtin instance. By default do nothing. Processors who
    556      operate on Builtin nodes have to provide an appropriate implementation."""
    557      pass
    558   def visit_using_directive(self, node): self.visit_builtin(node)
    559   def visit_using_declaration(self, node): self.visit_builtin(node)
    560   def visit_macro(self, node): self.visit_declaration(node)
    561   def visit_forward(self, node): self.visit_declaration(node)
    562   def visit_group(self, node):
    563      self.visit_declaration(node)
    564      for d in node.declarations: d.accept(self)
    565   def visit_scope(self, node):
    566      self.visit_declaration(node)
    567      for d in node.declarations: d.accept(self)
    568   def visit_module(self, node): self.visit_scope(node)
    569   def visit_meta_module(self, node): self.visit_module(node)
    570   def visit_class(self, node): self.visit_scope(node)
    571   def visit_class_template(self, node): self.visit_class(node)
    572   def visit_typedef(self, node): self.visit_declaration(node)
    573   def visit_enumerator(self, node): self.visit_declaration(node)
    574   def visit_enum(self, node):
    575      self.visit_declaration(node)
    576      for e in node.enumerators:
    577         e.accept(self)
    578      if node.eos:
    579         node.eos.accept(self)
    580   def visit_variable(self, node): self.visit_declaration(node)
    581   def visit_const(self, node): self.visit_declaration(node)
    582   def visit_function(self, node):
    583      self.visit_declaration(node)
    584      for parameter in node.parameters: parameter.accept(self)
    585   def visit_function_template(self, node): self.visit_function(node)
    586   def visit_operation(self, node): self.visit_function(node)
    587   def visit_operation_template(self, node): self.visit_operation(node)
    588   def visit_parameter(self, node): pass
    589   def visit_inheritance(self, node): pass
    590
    591class ASG(object):
    592
    593    def __init__(self, declarations = None, types = None):
    594
    595        self.declarations = declarations or []
    596        self.types = types or Dictionary()
    597
    598    def copy(self):
    599
    600        return type(self)(self.declarations[:],
    601                          self.types.copy())
    602
    603    def merge(self, other):
    604
    605        self.declarations.extend(other.declarations)
    606        self.types.merge(other.types)
    607
    608

Generated on Thu Apr 16 16:27:16 2009 by
synopsis (version devel)