1#!/usr/bin/env python 2# Copyright (c) 2013 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6""" Parser for PPAPI IDL """ 7 8# 9# IDL Parser 10# 11# The parser is uses the PLY yacc library to build a set of parsing rules based 12# on WebIDL. 13# 14# WebIDL, and WebIDL grammar can be found at: 15# http://dev.w3.org/2006/webapi/WebIDL/ 16# PLY can be found at: 17# http://www.dabeaz.com/ply/ 18# 19# The parser generates a tree by recursively matching sets of items against 20# defined patterns. When a match is made, that set of items is reduced 21# to a new item. The new item can provide a match for parent patterns. 22# In this way an AST is built (reduced) depth first. 23# 24 25# 26# Disable check for line length and Member as Function due to how grammar rules 27# are defined with PLY 28# 29# pylint: disable=R0201 30# pylint: disable=C0301 31 32import sys 33 34from idl_ppapi_lexer import IDLPPAPILexer 35from idl_parser import IDLParser, ListFromConcat, ParseFile 36from idl_node import IDLNode 37 38class IDLPPAPIParser(IDLParser): 39# 40# We force all input files to start with two comments. The first comment is a 41# Copyright notice followed by a file comment and finally by file level 42# productions. 43# 44 # [0] Insert a TOP definition for Copyright and Comments 45 def p_Top(self, p): 46 """Top : COMMENT COMMENT Definitions""" 47 Copyright = self.BuildComment('Copyright', p, 1) 48 Filedoc = self.BuildComment('Comment', p, 2) 49 p[0] = ListFromConcat(Copyright, Filedoc, p[3]) 50 51# 52#The parser is based on the WebIDL standard. See: 53# http://www.w3.org/TR/WebIDL/#idl-grammar 54# 55 # [1] 56 def p_Definitions(self, p): 57 """Definitions : ExtendedAttributeList Definition Definitions 58 | """ 59 if len(p) > 1: 60 p[2].AddChildren(p[1]) 61 p[0] = ListFromConcat(p[2], p[3]) 62 63 # [2] Add INLINE definition 64 def p_Definition(self, p): 65 """Definition : CallbackOrInterface 66 | Struct 67 | Partial 68 | Dictionary 69 | Exception 70 | Enum 71 | Typedef 72 | ImplementsStatement 73 | Label 74 | Inline""" 75 p[0] = p[1] 76 77 def p_Inline(self, p): 78 """Inline : INLINE""" 79 words = p[1].split() 80 name = self.BuildAttribute('NAME', words[1]) 81 lines = p[1].split('\n') 82 value = self.BuildAttribute('VALUE', '\n'.join(lines[1:-1]) + '\n') 83 children = ListFromConcat(name, value) 84 p[0] = self.BuildProduction('Inline', p, 1, children) 85 86# 87# Label 88# 89# A label is a special kind of enumeration which allows us to go from a 90# set of version numbrs to releases 91# 92 def p_Label(self, p): 93 """Label : LABEL identifier '{' LabelList '}' ';'""" 94 p[0] = self.BuildNamed('Label', p, 2, p[4]) 95 96 def p_LabelList(self, p): 97 """LabelList : identifier '=' float LabelCont""" 98 val = self.BuildAttribute('VALUE', p[3]) 99 label = self.BuildNamed('LabelItem', p, 1, val) 100 p[0] = ListFromConcat(label, p[4]) 101 102 def p_LabelCont(self, p): 103 """LabelCont : ',' LabelList 104 |""" 105 if len(p) > 1: 106 p[0] = p[2] 107 108 def p_LabelContError(self, p): 109 """LabelCont : error LabelCont""" 110 p[0] = p[2] 111 112 # [5.1] Add "struct" style interface 113 def p_Struct(self, p): 114 """Struct : STRUCT identifier Inheritance '{' StructMembers '}' ';'""" 115 p[0] = self.BuildNamed('Struct', p, 2, ListFromConcat(p[3], p[5])) 116 117 def p_StructMembers(self, p): 118 """StructMembers : StructMember StructMembers 119 |""" 120 if len(p) > 1: 121 p[0] = ListFromConcat(p[1], p[2]) 122 123 def p_StructMember(self, p): 124 """StructMember : ExtendedAttributeList Type identifier ';'""" 125 p[0] = self.BuildNamed('Member', p, 3, ListFromConcat(p[1], p[2])) 126 127 # [24] 128 def p_Typedef(self, p): 129 """Typedef : TYPEDEF ExtendedAttributeListNoComments Type identifier ';'""" 130 p[0] = self.BuildNamed('Typedef', p, 4, ListFromConcat(p[2], p[3])) 131 132 # [24.1] 133 def p_TypedefFunc(self, p): 134 """Typedef : TYPEDEF ExtendedAttributeListNoComments ReturnType identifier '(' ArgumentList ')' ';'""" 135 args = self.BuildProduction('Arguments', p, 5, p[6]) 136 p[0] = self.BuildNamed('Callback', p, 4, ListFromConcat(p[2], p[3], args)) 137 138 # [27] 139 def p_ConstValue(self, p): 140 """ConstValue : integer 141 | integer LSHIFT integer 142 | integer RSHIFT integer""" 143 val = str(p[1]) 144 if len(p) > 2: 145 val = "%s %s %s" % (p[1], p[2], p[3]) 146 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'), 147 self.BuildAttribute('VALUE', val)) 148 149 def p_ConstValueStr(self, p): 150 """ConstValue : string""" 151 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'string'), 152 self.BuildAttribute('VALUE', p[1])) 153 154 # Boolean & Float Literals area already BuildAttributes 155 def p_ConstValueLiteral(self, p): 156 """ConstValue : FloatLiteral 157 | BooleanLiteral """ 158 p[0] = p[1] 159 160 # [21] 161 def p_EnumValueList(self, p): 162 """EnumValueList : EnumValue EnumValues""" 163 p[0] = ListFromConcat(p[1], p[2]) 164 165 # [22] 166 def p_EnumValues(self, p): 167 """EnumValues : ',' EnumValue EnumValues 168 |""" 169 if len(p) > 1: 170 p[0] = ListFromConcat(p[2], p[3]) 171 172 def p_EnumValue(self, p): 173 """EnumValue : ExtendedAttributeList identifier 174 | ExtendedAttributeList identifier '=' ConstValue""" 175 p[0] = self.BuildNamed('EnumItem', p, 2, p[1]) 176 if len(p) > 3: 177 p[0].AddChildren(p[4]) 178 179 def p_PrimitiveType(self, p): 180 """PrimitiveType : IntegerType 181 | UnsignedIntegerType 182 | FloatType 183 | HandleType 184 | PointerType""" 185 if type(p[1]) == str: 186 p[0] = self.BuildNamed('PrimitiveType', p, 1) 187 else: 188 p[0] = p[1] 189 190 def p_PointerType(self, p): 191 """PointerType : STR_T 192 | MEM_T 193 | CSTR_T 194 | INTERFACE_T 195 | NULL""" 196 p[0] = p[1] 197 198 def p_HandleType(self, p): 199 """HandleType : HANDLE_T 200 | PP_FILEHANDLE""" 201 p[0] = p[1] 202 203 # [66] 204 def p_FloatType(self, p): 205 """FloatType : FLOAT_T 206 | DOUBLE_T""" 207 p[0] = p[1] 208 209 # [67] 210 def p_UnsignedIntegerType(self, p): 211 """UnsignedIntegerType : UINT8_T 212 | UINT16_T 213 | UINT32_T 214 | UINT64_T""" 215 p[0] = p[1] 216 217 218 # [68] 219 def p_IntegerType(self, p): 220 """IntegerType : CHAR 221 | INT8_T 222 | INT16_T 223 | INT32_T 224 | INT64_T""" 225 p[0] = p[1] 226 227 # These targets are no longer used 228 def p_OptionalLong(self, p): 229 """ """ 230 pass 231 232 def p_UnrestrictedFloatType(self, p): 233 """ """ 234 pass 235 236 def p_null(self, p): 237 """ """ 238 pass 239 240 # We only support: 241 # [ identifier ] 242 # [ identifier = identifier ] 243 # [ identifier ( ArgumentList )] 244 # [ identifier ( ValueList )] 245 # [ identifier = identifier ( ArgumentList )] 246 # [51] map directly to 74-77 247 # [52-54, 56] are unsupported 248 def p_ExtendedAttribute(self, p): 249 """ExtendedAttribute : ExtendedAttributeNoArgs 250 | ExtendedAttributeArgList 251 | ExtendedAttributeValList 252 | ExtendedAttributeIdent 253 | ExtendedAttributeIdentConst 254 | ExtendedAttributeNamedArgList""" 255 p[0] = p[1] 256 257 def p_ExtendedAttributeValList(self, p): 258 """ExtendedAttributeValList : identifier '(' ValueList ')'""" 259 arguments = self.BuildProduction('Values', p, 2, p[3]) 260 p[0] = self.BuildNamed('ExtAttribute', p, 1, arguments) 261 262 def p_ValueList(self, p): 263 """ValueList : ConstValue ValueListCont""" 264 p[0] = ListFromConcat(p[1], p[2]) 265 266 def p_ValueListCont(self, p): 267 """ValueListCont : ValueList 268 |""" 269 if len(p) > 1: 270 p[0] = p[1] 271 272 # [76] 273 def p_ExtendedAttributeIdentConst(self, p): 274 """ExtendedAttributeIdentConst : identifier '=' ConstValue""" 275 p[0] = self.BuildNamed('ExtAttribute', p, 1, p[3]) 276 277 278 def __init__(self, lexer, verbose=False, debug=False, mute_error=False): 279 IDLParser.__init__(self, lexer, verbose, debug, mute_error) 280 281 282def main(argv): 283 nodes = [] 284 parser = IDLPPAPIParser(IDLPPAPILexer()) 285 errors = 0 286 287 for filename in argv: 288 filenode = ParseFile(parser, filename) 289 if filenode: 290 errors += filenode.GetProperty('ERRORS') 291 nodes.append(filenode) 292 293 ast = IDLNode('AST', '__AST__', 0, 0, nodes) 294 295 print '\n'.join(ast.Tree(accept_props=['PROD', 'TYPE', 'VALUE'])) 296 if errors: 297 print '\nFound %d errors.\n' % errors 298 299 300 return errors 301 302 303if __name__ == '__main__': 304 sys.exit(main(sys.argv[1:])) 305