Home | History | Annotate | Download | only in generators
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Nodes for PPAPI IDL AST."""
      6 
      7 from idl_namespace import IDLNamespace
      8 from idl_node import IDLAttribute, IDLFile, IDLNode
      9 from idl_option import GetOption
     10 from idl_visitor import IDLVisitor
     11 from idl_release import IDLReleaseList, IDLReleaseMap
     12 
     13 #
     14 # IDL Predefined types
     15 #
     16 BuiltIn = set(['int8_t', 'int16_t', 'int32_t', 'int64_t', 'uint8_t',
     17                'uint16_t', 'uint32_t', 'uint64_t', 'double_t', 'float_t',
     18                'handle_t', 'interface_t', 'char', 'mem_t', 'str_t', 'void'])
     19 
     20 
     21 #
     22 # IDLLabelResolver
     23 #
     24 # A specialized visitor which traverses the AST, building a mapping of
     25 # Release names to Versions numbers and calculating a min version.
     26 # The mapping is applied to the File nodes within the AST.
     27 #
     28 class IDLLabelResolver(IDLVisitor):
     29   def Arrive(self, node, ignore):
     30     # If we are entering a File, clear the visitor local mapping
     31     if node.IsA('File'):
     32       self.release_map = None
     33       self.filenode = node
     34     # For any non AST node, the filenode is the last known file
     35     if not node.IsA('AST'):
     36       node.filenode = self.filenode
     37     return ignore
     38 
     39   def Depart(self, node, ignore, childdata):
     40     # Build list of Release=Version
     41     if node.IsA('LabelItem'):
     42       return (node.GetName(), node.GetProperty('VALUE'))
     43 
     44     # On completion of the Label, apply to the parent File if the
     45     # name of the label matches the generation label.
     46     if node.IsA('Label') and node.GetName() == GetOption('label'):
     47       try:
     48         self.release_map = IDLReleaseMap(childdata)
     49         node.parent.release_map = self.release_map
     50       except Exception as err:
     51         node.Error('Unable to build release map: %s' % str(err))
     52 
     53     # For File objects, set the minimum version
     54     if node.IsA('File'):
     55       file_min, file_max = node.release_map.GetReleaseRange()
     56       node.SetMin(file_min)
     57 
     58     return None
     59 
     60 
     61 #
     62 # IDLNamespaceVersionResolver
     63 #
     64 # A specialized visitor which traverses the AST, building a namespace tree
     65 # as it goes.  The namespace tree is mapping from a name to a version list.
     66 # Labels must already be resolved to use.
     67 #
     68 class IDLNamespaceVersionResolver(IDLVisitor):
     69   NamespaceSet = set(['AST', 'Callspec', 'Interface', 'Member', 'Struct'])
     70   #
     71   # When we arrive at a node we must assign it a namespace and if the
     72   # node is named, then place it in the appropriate namespace.
     73   #
     74   def Arrive(self, node, parent_namespace):
     75     # If we are a File, grab the Min version and replease mapping
     76     if node.IsA('File'):
     77       self.rmin = node.GetMinMax()[0]
     78       self.release_map = node.release_map
     79 
     80     # Set the min version on any non Label within the File
     81     if not node.IsA('AST', 'File', 'Label', 'LabelItem'):
     82       my_min, my_max = node.GetMinMax()
     83       if not my_min:
     84         node.SetMin(self.rmin)
     85 
     86     # If this object is not a namespace aware object, use the parent's one
     87     if node.cls not in self.NamespaceSet:
     88       node.namespace = parent_namespace
     89     else:
     90     # otherwise create one.
     91       node.namespace = IDLNamespace(parent_namespace, node.GetName())
     92 
     93     # If this node is named, place it in its parent's namespace
     94     if parent_namespace and node.cls in IDLNode.NamedSet:
     95       # Set version min and max based on properties
     96       if self.release_map:
     97         vmin = node.GetProperty('version')
     98         vmax = node.GetProperty('deprecate')
     99         # If no min is available, the use the parent File's min
    100         if vmin == None:
    101           rmin = self.rmin
    102         else:
    103           rmin = self.release_map.GetRelease(vmin)
    104         rmax = self.release_map.GetRelease(vmax)
    105         node.SetReleaseRange(rmin, rmax)
    106       parent_namespace.AddNode(node)
    107 
    108     # Pass this namespace to each child in case they inherit it
    109     return node.namespace
    110 
    111 
    112 #
    113 # IDLFileTypeRessolver
    114 #
    115 # A specialized visitor which traverses the AST and sets a FILE property
    116 # on all file nodes.  In addition, searches the namespace resolving all
    117 # type references.  The namespace tree must already have been populated
    118 # before this visitor is used.
    119 #
    120 class IDLFileTypeResolver(IDLVisitor):
    121   def VisitFilter(self, node, data):
    122     return not node.IsA('Comment', 'Copyright')
    123 
    124   def Arrive(self, node, filenode):
    125     # Track the file node to update errors
    126     if node.IsA('File'):
    127       node.SetProperty('FILE', node)
    128       filenode = node
    129 
    130     if not node.IsA('AST'):
    131       file_min, file_max = filenode.release_map.GetReleaseRange()
    132       if not file_min:
    133         print 'Resetting min on %s to %s' % (node, file_min)
    134         node.SetMinRange(file_min)
    135 
    136     # If this node has a TYPEREF, resolve it to a version list
    137     typeref = node.property_node.GetPropertyLocal('TYPEREF')
    138     if typeref:
    139       node.typelist = node.parent.namespace.FindList(typeref)
    140       if not node.typelist:
    141         node.Error('Could not resolve %s.' % typeref)
    142     else:
    143       node.typelist = None
    144     return filenode
    145 
    146 #
    147 # IDLReleaseResolver
    148 #
    149 # A specialized visitor which will traverse the AST, and generate a mapping
    150 # from any release to the first release in which that version of the object
    151 # was generated.  Types must already be resolved to use.
    152 #
    153 class IDLReleaseResolver(IDLVisitor):
    154   def Arrive(self, node, releases):
    155     node.BuildReleaseMap(releases)
    156     return releases
    157 
    158 
    159 #
    160 # IDLAst
    161 #
    162 # A specialized version of the IDLNode for containing the whole of the
    163 # AST.  Construction of the AST object will cause resolution of the
    164 # tree including versions, types, etc...  Errors counts will be collected
    165 # both per file, and on the AST itself.
    166 #
    167 class IDLAst(IDLNode):
    168   def __init__(self, children):
    169     IDLNode.__init__(self, 'AST', 'BuiltIn', 1, 0, children)
    170     self.Resolve()
    171 
    172   def Resolve(self):
    173     # Set the appropriate Release=Version mapping for each File
    174     IDLLabelResolver().Visit(self, None)
    175 
    176     # Generate the Namesapce Tree
    177     self.namespace = IDLNamespace(None, 'AST')
    178     IDLNamespaceVersionResolver().Visit(self, self.namespace)
    179 
    180     # Using the namespace, resolve type references
    181     IDLFileTypeResolver().Visit(self, None)
    182 
    183     # Build an ordered list of all releases
    184     releases = set()
    185     for filenode in self.GetListOf('File'):
    186       releases |= set(filenode.release_map.GetReleases())
    187 
    188     # Generate a per node list of releases and release mapping
    189     IDLReleaseResolver().Visit(self, sorted(releases))
    190 
    191     for filenode in self.GetListOf('File'):
    192       self.errors += int(filenode.GetProperty('ERRORS', 0))
    193 
    194 
    195