blob: 8914c841997070902a33d98cac259485ad47187f [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001#!/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://heycam.github.io/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://heycam.github.io/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
James Robinson646469d2014-10-03 15:33:28 -0700127 def p_Typedef(self, p):
128 """Typedef : TYPEDEF ExtendedAttributeListNoComments Type identifier ';'"""
129 p[0] = self.BuildNamed('Typedef', p, 4, ListFromConcat(p[2], p[3]))
130
James Robinson646469d2014-10-03 15:33:28 -0700131 def p_TypedefFunc(self, p):
132 """Typedef : TYPEDEF ExtendedAttributeListNoComments ReturnType identifier '(' ArgumentList ')' ';'"""
133 args = self.BuildProduction('Arguments', p, 5, p[6])
134 p[0] = self.BuildNamed('Callback', p, 4, ListFromConcat(p[2], p[3], args))
135
James Robinson646469d2014-10-03 15:33:28 -0700136 def p_ConstValue(self, p):
137 """ConstValue : integer
138 | integer LSHIFT integer
139 | integer RSHIFT integer"""
140 val = str(p[1])
141 if len(p) > 2:
142 val = "%s %s %s" % (p[1], p[2], p[3])
143 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'),
144 self.BuildAttribute('VALUE', val))
145
146 def p_ConstValueStr(self, p):
147 """ConstValue : string"""
148 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'string'),
149 self.BuildAttribute('VALUE', p[1]))
150
151 # Boolean & Float Literals area already BuildAttributes
152 def p_ConstValueLiteral(self, p):
153 """ConstValue : FloatLiteral
154 | BooleanLiteral """
155 p[0] = p[1]
156
James Robinson646469d2014-10-03 15:33:28 -0700157 def p_EnumValueList(self, p):
158 """EnumValueList : EnumValue EnumValues"""
159 p[0] = ListFromConcat(p[1], p[2])
160
James Robinson646469d2014-10-03 15:33:28 -0700161 def p_EnumValues(self, p):
162 """EnumValues : ',' EnumValue EnumValues
163 |"""
164 if len(p) > 1:
165 p[0] = ListFromConcat(p[2], p[3])
166
167 def p_EnumValue(self, p):
168 """EnumValue : ExtendedAttributeList identifier
169 | ExtendedAttributeList identifier '=' ConstValue"""
170 p[0] = self.BuildNamed('EnumItem', p, 2, p[1])
171 if len(p) > 3:
172 p[0].AddChildren(p[4])
173
James Robinson24218d72014-10-20 16:18:41 -0700174 # Omit PromiseType, as it is a JS type.
175 def p_NonAnyType(self, p):
176 """NonAnyType : PrimitiveType TypeSuffix
177 | identifier TypeSuffix
178 | SEQUENCE '<' Type '>' Null"""
179 IDLParser.p_NonAnyType(self, p)
180
James Robinson646469d2014-10-03 15:33:28 -0700181 def p_PrimitiveType(self, p):
182 """PrimitiveType : IntegerType
183 | UnsignedIntegerType
184 | FloatType
185 | HandleType
186 | PointerType"""
187 if type(p[1]) == str:
188 p[0] = self.BuildNamed('PrimitiveType', p, 1)
189 else:
190 p[0] = p[1]
191
192 def p_PointerType(self, p):
193 """PointerType : STR_T
194 | MEM_T
195 | CSTR_T
196 | INTERFACE_T
197 | NULL"""
198 p[0] = p[1]
199
200 def p_HandleType(self, p):
201 """HandleType : HANDLE_T
202 | PP_FILEHANDLE"""
203 p[0] = p[1]
204
James Robinson646469d2014-10-03 15:33:28 -0700205 def p_FloatType(self, p):
206 """FloatType : FLOAT_T
207 | DOUBLE_T"""
208 p[0] = p[1]
209
James Robinson646469d2014-10-03 15:33:28 -0700210 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
James Robinson646469d2014-10-03 15:33:28 -0700218 def p_IntegerType(self, p):
219 """IntegerType : CHAR
220 | INT8_T
221 | INT16_T
222 | INT32_T
223 | INT64_T"""
224 p[0] = p[1]
225
226 # These targets are no longer used
227 def p_OptionalLong(self, p):
228 """ """
229 pass
230
231 def p_UnrestrictedFloatType(self, p):
232 """ """
233 pass
234
235 def p_null(self, p):
236 """ """
237 pass
238
James Robinson24218d72014-10-20 16:18:41 -0700239 def p_PromiseType(self, p):
240 """ """
241 pass
242
Etienne Membrives175837a2014-12-19 15:45:38 +0100243 def p_EnumValueListComma(self, p):
244 """ """
245 pass
246
247 def p_EnumValueListString(self, p):
248 """ """
249 pass
250
James Robinson646469d2014-10-03 15:33:28 -0700251 # We only support:
252 # [ identifier ]
253 # [ identifier ( ArgumentList )]
254 # [ identifier ( ValueList )]
255 # [ identifier = identifier ]
256 # [ identifier = ( IdentifierList )]
257 # [ identifier = ConstValue ]
258 # [ identifier = identifier ( ArgumentList )]
259 # [51] map directly to 74-77
260 # [52-54, 56] are unsupported
261 def p_ExtendedAttribute(self, p):
262 """ExtendedAttribute : ExtendedAttributeNoArgs
263 | ExtendedAttributeArgList
264 | ExtendedAttributeValList
265 | ExtendedAttributeIdent
266 | ExtendedAttributeIdentList
267 | ExtendedAttributeIdentConst
268 | ExtendedAttributeNamedArgList"""
269 p[0] = p[1]
270
271 def p_ExtendedAttributeValList(self, p):
272 """ExtendedAttributeValList : identifier '(' ValueList ')'"""
273 arguments = self.BuildProduction('Values', p, 2, p[3])
274 p[0] = self.BuildNamed('ExtAttribute', p, 1, arguments)
275
276 def p_ValueList(self, p):
277 """ValueList : ConstValue ValueListCont"""
278 p[0] = ListFromConcat(p[1], p[2])
279
280 def p_ValueListCont(self, p):
281 """ValueListCont : ValueList
282 |"""
283 if len(p) > 1:
284 p[0] = p[1]
285
James Robinson646469d2014-10-03 15:33:28 -0700286 def p_ExtendedAttributeIdentConst(self, p):
287 """ExtendedAttributeIdentConst : identifier '=' ConstValue"""
288 p[0] = self.BuildNamed('ExtAttribute', p, 1, p[3])
289
290
291 def __init__(self, lexer, verbose=False, debug=False, mute_error=False):
292 IDLParser.__init__(self, lexer, verbose, debug, mute_error)
293
294
295def main(argv):
296 nodes = []
297 parser = IDLPPAPIParser(IDLPPAPILexer())
298 errors = 0
299
300 for filename in argv:
301 filenode = ParseFile(parser, filename)
302 if filenode:
303 errors += filenode.GetProperty('ERRORS')
304 nodes.append(filenode)
305
306 ast = IDLNode('AST', '__AST__', 0, 0, nodes)
307
308 print '\n'.join(ast.Tree(accept_props=['PROD', 'TYPE', 'VALUE']))
309 if errors:
310 print '\nFound %d errors.\n' % errors
311
312
313 return errors
314
315
316if __name__ == '__main__':
317 sys.exit(main(sys.argv[1:]))