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