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