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