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