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