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