Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1156)

Side by Side Diff: Source/bindings/scripts/blink_idl_parser.py

Issue 15801003: IDL parser rewrite in Python (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: [WIP] Full parser Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 """Parser for Blink IDL
30
31 The parser uses the PLY (Python Lex-Yacc) library to build a set of parsing
32 rules which understand the Blink dialect of Web IDL.
33 It derives from a standard Web IDL parser, overriding the rules where Blink
34 IDL differs.
35
36 Web IDL:
37 http://www.w3.org/TR/WebIDL/
38 Web IDL Grammar:
39 http://www.w3.org/TR/WebIDL/#idl-grammar
40 PLY:
41 http://www.dabeaz.com/ply/
42 """
43
44 # Disable check for line length and Member as Function due to how grammar rules
45 # are defined with PLY
46 #
47 # pylint: disable=R0201
48 # pylint: disable=C0301
49 #
50 # Disable attribute validation, as lint can't import parent class to check
51 # pylint: disable=E1101
52
53 import os.path
54 import sys
55
56 # PLY is in Chromium src/third_party/ply
57 module_path, module_name = os.path.split(__file__)
58 third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pard ir)
59 sys.path.append(third_party)
60 from ply import yacc
61
62 # Base parser is in Chromium src/tools/idl_parser
63 tools_dir = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir , os.pardir, 'tools')
64 sys.path.append(tools_dir)
65 from idl_parser.idl_parser import IDLParser, ListFromConcat
66
67 from blink_idl_lexer import BlinkIDLLexer
68
69
70 REMOVED_RULES = ['Comments', # [0.1]
71 'CommentsRest', # [0.2]
72 'AttributeOrOperation', # [30]
73 'StringifierAttributeOrOperation', # [31]
74 'Operation', # [35]
75 'Qualifiers', # [36]
76 ]
77
78
79 class BlinkIDLParser(IDLParser):
80 # Numbering scheme is:
81 # [1] for Web IDL spec (or base Pepper IDL)
82 # [b1] for Blink IDL (overrides Web IDL or inserts rule)
83 # [s1] is for numbering Sakamoto
84
85 # [0] Override Pepper definition, since we strip comments
86 def p_Top(self, p):
87 """Top : Definitions"""
88 p[0] = p[1]
89
90 # [3] Override Pepper action, since we distinguish callbacks
91 def p_CallbackOrInterface(self, p):
92 """CallbackOrInterface : CALLBACK CallbackRestOrInterface
93 | Interface"""
94 if len(p) > 2:
95 p[2].AddChildren(self.BuildTrue('Callback'))
96 p[0] = p[2]
97 else:
98 p[0] = p[1]
99
100 # [b10]
101 def p_InterfaceMember(self, p):
102 """InterfaceMember : Const
103 | AttributeOrOperationOrIterator"""
104 # Standard is (no 'OrIterator'):
105 # InterfaceMember : Const
106 # | AttributeOrOperation
107 p[0] = p[1]
108
109 # [b19]
110 # List needed for multiple inheritance in SVG
111 # FIXME: remove when multiple inheritance (which is deprecated) is removed
112 def p_Inheritance(self, p):
113 """Inheritance : ':' ScopedNameList
114 |"""
115 # Standard is (single identifier, not list):
116 # """Inheritance : ':' identifier
117 # |"""
118 if len(p) > 1:
119 p[0] = self.BuildProduction('MultipleInherit', p, 2, p[2])
120
121 # [b27]
122 def p_ConstValue(self, p):
123 """ConstValue : BooleanLiteral
124 | FloatLiteral
125 | IntegerLiteral
126 | StringLiteral
127 | null"""
128 # Standard is (no 'string', fewer 'Literals'):
129 # ConstValue : BooleanLiteral
130 # | FloatLiteral
131 # | integer
132 # | NULL
133 p[0] = p[1]
134
135 # [b27.1]
136 def p_IntegerLiteral(self, p):
137 """IntegerLiteral : integer"""
138 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'),
139 self.BuildAttribute('NAME', p[1]))
140
141 # [b27.2]
142 def p_StringLiteral(self, p):
143 """StringLiteral : string"""
144 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'DOMString'),
145 self.BuildAttribute('NAME', p[1]))
146
147 # [b30]
148 # Replaces [30] AttributeOrOperation
149 def p_AttributeOrOperationOrIterator(self, p):
150 """AttributeOrOperationOrIterator : Serializer
151 | Qualifier AttributeOrOperationRest
152 | Attribute
153 | OperationOrIterator"""
154 # Standard is:
155 # AttributeOrOperation : "stringifier" StringifierAttributeOrOperation
156 # | Attribute
157 # | Operation
158 if len(p) > 2:
159 p[2].AddChildren(p[1])
160 p[0] = p[2]
161 else:
162 p[0] = p[1]
163
164 # Serialization
165 # FIXME: can we remove??
166 # [s31]
167 def p_Serializer(self, p):
168 """Serializer : SERIALIZER SerializerRest"""
169 p[0] = p[1]
170
171 # [s32]
172 def p_SerializerRest(self, p):
173 """SerializerRest : OperationRest
174 | '=' SerializationPattern
175 |"""
176 if len(p) > 2:
177 p[0] = p[2]
178 elif len(p) == 2:
179 p[0] = p[1]
180
181 # [s33]
182 def p_SerializationPattern(self, p):
183 """SerializationPattern : '{' SerializationPatternMap '}'
184 | '[' SerializationPatternList ']'
185 | identifier"""
186 if len(p) == 4:
187 p[0] = p[2]
188 else:
189 p[0] = p[1]
190
191 # [s34]
192 def p_SerializationPatternMap(self, p):
193 """SerializationPatternMap : GETTER
194 | INHERIT Identifiers
195 | identifier Identifiers
196 |"""
197 if len(p) > 1:
198 p[0] = p[1]
199
200 # [s35]
201 def p_SerializationPatternList(self, p):
202 """SerializationPatternList : GETTER
203 | identifier Identifiers
204 |"""
205 if len(p) > 1:
206 p[0] = p[1]
207
208 # [s36]
209 def p_Identifiers(self, p):
210 """Identifiers : ',' identifier Identifiers
211 |"""
212 if len(p) > 1:
213 p[0] = p[2]
214
215 # Iterator and SpecialOperation
216 # Follows [35] Operation
217 # [b35.1]
218 def p_OperationOrIterator(self, p):
219 """OperationOrIterator : ReturnType OperationOrIteratorRest
220 | SpecialOperation"""
221 if len(p) > 2:
222 p[0] = self.BuildProduction('OperationOrIterator', p, 2, ListFromCon cat(p[1], p[2]))
223 else:
224 p[0] = p[1]
225
226 # [b35.2]
227 def p_OperationOrIteratorRest(self, p):
228 """OperationOrIteratorRest : IteratorRest
229 | OperationRest"""
230 p[0] = p[1]
231
232 # [b35.3]
233 def p_IteratorRest(self, p):
234 """IteratorRest : ITERATOR OptionalIteratorInterfaceOrObject ';'"""
235 p[0] = p[2]
236
237 # [b35.4]
238 def p_OptionalIteratorInterfaceOrObject(self, p):
239 """OptionalIteratorInterfaceOrObject : OptionalIteratorInterface
240 | OBJECT"""
241 p[0] = p[1]
242
243 # [b35.5]
244 def p_OptionalIteratorInterface(self, p):
245 """OptionalIteratorInterface : '=' identifier
246 |"""
247 if len(p) > 2:
248 p[0] = p[2]
249
250 # [b35.6]
251 def p_SpecialOperation(self, p):
252 """SpecialOperation : Special Specials ReturnType OperationRest"""
253 specials = ListFromConcat(p[1], p[2])
254 p[4].AddChildren(p[3])
255 p[0] = p[4]
256 p[0].AddChildren(specials)
257
258 # Follows [36] Qualifiers
259 # [b36.1] [s37]
260 def p_Qualifier(self, p):
261 """Qualifier : STATIC
262 | STRINGIFIER"""
263 if p[1] == 'static':
264 p[0] = self.BuildTrue('STATIC')
265 elif p[1] == 'stringifier':
266 p[0] = self.BuildTrue('STRINGIFIER')
267
268 # [b39]
269 def p_OperationRest(self, p):
270 """OperationRest : OptionalIdentifier '(' ArgumentList ')' Raises ';'"""
271 # Standard is:
272 # OperationRest : ReturnType OptionalIdentifier '(' ArgumentList ')' ';'
273 arguments = self.BuildProduction('Arguments', p, 2, p[3])
274 p[0] = self.BuildNamed('Operation', p, 1, arguments)
275
276 # [b39.1]
277 def p_Raises(self, p):
278 """Raises : RAISES ExceptionList
279 |"""
280 if len(p) > 2:
281 p[0] = p[2]
282
283 # [s39.2]
284 def p_ExceptionList(self, p):
285 """ExceptionList : '(' ScopedNameList ')'"""
286 p[0] = p[2]
287
288 # [b39.3]
289 def p_AttributeOrOperationRest(self, p):
290 """AttributeOrOperationRest : AttributeRest
291 | ReturnType OperationRest
292 | ';'"""
293 if len(p) > 2:
294 p[2].AddChildren(p[1])
295 p[0] = p[2]
296 elif len(p) == 2 and p[1] != ';':
297 p[0] = p[1]
298
299 # [b39.2]
300 def p_AttributeRest(self, p):
301 """AttributeRest : ReadOnly ATTRIBUTE Type identifier Get ';'"""
302 p[0] = self.BuildNamed('Attribute', p, 4, ListFromConcat(p[1], p[3], p[5]))
303
304 # [b39.3]
305 def p_Get(self, p):
306 """Get : InheritsGetter SetRaises
307 | SetGetRaises
308 |"""
309 if len(p) > 2:
310 p[0] = p[2]
311 elif len(p) == 2:
312 p[0] = p[1]
313
314 # [s39.4]
315 def p_InheritsGetter(self, p):
316 """InheritsGetter : INHERITS GETTER"""
317 pass
318
319 # [b47]
320 def p_ExceptionMember(self, p):
321 """ExceptionMember : Const
322 | ExceptionField
323 | Attribute
324 | ExceptionFieldToString"""
325 # Standard is:
326 # ExceptionMember : Const
327 # | ExceptionField
328 p[0] = p[1]
329
330 # [b47.1]
331 def p_ExceptionFieldToString(self, p):
332 """ExceptionFieldToString : Type identifier '(' ')' ';'"""
333 # Needed to handle:
334 # // Override in a Mozilla compatible format
335 # [NotEnumerable] DOMString toString();
336 p[0] = self.BuildNamed('ExceptionFieldToString', p, 2, p[1])
337
338 # Extended attributes
339 # [b49] Override Pepper: remove comment field, since comments stripped
340 # FIXME: Upstream
341 def p_ExtendedAttributeList(self, p):
342 """ExtendedAttributeList : '[' ExtendedAttribute ExtendedAttributes ']'
343 | '[' ']'
344 | """
345 if len(p) > 3:
346 items = ListFromConcat(p[2], p[3])
347 attribs = self.BuildProduction('ExtAttributes', p, 1, items)
348 p[0] = ListFromConcat(p[0], attribs)
349
350 # [b50] Allow optional trailing comma
351 def p_ExtendedAttributes(self, p):
352 """ExtendedAttributes : ',' ExtendedAttribute ExtendedAttributes
353 | ','
354 |"""
355 if len(p) > 2:
356 p[0] = ListFromConcat(p[2], p[3])
357
358 # [b51] Add ExtendedAttributeIdentOrIdent and ExtendedAttributeIdentAndIdent
359 def p_ExtendedAttribute(self, p):
360 """ExtendedAttribute : ExtendedAttributeNoArgs
361 | ExtendedAttributeArgList
362 | ExtendedAttributeIdent
363 | ExtendedAttributeIdentOrIdent
364 | ExtendedAttributeIdentAndIdent
365 | ExtendedAttributeNamedArgList"""
366 p[0] = p[1]
367
368 # FIXME: Upstream UnionType
369 # [59]
370 def p_UnionType(self, p):
371 """UnionType : '(' UnionMemberType OR UnionMemberType UnionMemberTypes ' )'"""
372 members = ListFromConcat(p[2], p[4], p[5])
373 p[0] = self.BuildProduction('UnionType', p, 1, members)
374
375 # [60]
376 def p_UnionMemberType(self, p):
377 """UnionMemberType : NonAnyType
378 | UnionType TypeSuffix
379 | ANY '[' ']' TypeSuffix"""
380 if len(p) == 2:
381 p[0] = p[1]
382 elif len(p) == 3:
383 p[0] = ListFromConcat(p[1], p[2])
384 else:
385 p[0] = ListFromConcat(self.BuildProduction('Any', p, 1), p[4])
386
387 # [61]
388 def p_UnionMemberTypes(self, p):
389 """UnionMemberTypes : OR UnionMemberType UnionMemberTypes
390 |"""
391 if len(p) > 1:
392 p[0] = ListFromConcat(p[2], p[3])
393
394 # [70] Override Pepper to remove non-standard sized array
395 # FIXME: upstream should remove sized array from base
396 def p_TypeSuffix(self, p):
397 """TypeSuffix : '[' ']' TypeSuffix
398 | '?' TypeSuffixStartingWithArray
399 |"""
400 if len(p) == 4:
401 p[0] = self.BuildProduction('Array', p, 1, p[3])
402
403 if len(p) == 3:
404 p[0] = ListFromConcat(self.BuildTrue('NULLABLE'), p[2])
405
406 # [b76.1]
407 def p_ExtendedAttributeIdentOrIdent(self, p):
408 """ExtendedAttributeIdentOrIdent : identifier '=' identifier '|' identif ier"""
409 # Used in a handful of files
410 value = self.BuildAttribute('VALUE', p[3] + '|' + p[5])
411 p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
412
413 # [b76.2]
414 def p_ExtendedAttributeIdentAndIdent(self, p):
415 """ExtendedAttributeIdentAndIdent : identifier '=' identifier '&' identi fier"""
416 # FIXME: Used only in NavigatorContentUtils.idl,
417 # which doesn't appear to be parsed - remove?
418 value = self.BuildAttribute('VALUE', p[3] + '&' + p[5])
419 p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
420
421 # Exceptions
422 # [s25]
423 def p_SetGetRaises(self, p):
424 """SetGetRaises : SetRaises GetRaises2
425 | GetRaises
426 | SetGetRaises2"""
427 p[0] = p[1]
428
429 # [s27]
430 def p_GetRaises(self, p):
431 """GetRaises : GETTER RAISES ExceptionList"""
432 p[0] = p[3]
433
434 # [s27.5]
435 def p_GetRaises2(self, p):
436 """GetRaises2 : ',' GETTER RAISES ExceptionList
437 |"""
438 p[0] = p[4]
439
440 # [s28]
441 def p_SetRaises(self, p):
442 """SetRaises : SETTER RAISES ExceptionList"""
443 p[0] = p[3]
444
445 # [s29]
446 def p_SetGetRaises2(self, p):
447 """SetGetRaises2 : GetRaises3 SetRaises3"""
448 # FIXME
449 p[0] = p[1]
450
451 # [s29a]
452 def p_GetRaises3(self, p):
453 """GetRaises3 : GETRAISES ExceptionList
454 |"""
455 p[0] = p[2]
456
457 # [s29b]
458 def p_SetRaises3(self, p):
459 """SetRaises3 : SETRAISES ExceptionList
460 |"""
461 p[0] = p[2]
462
463 # Scoped names
464 # FIXME: remove??
465 # [s63]
466 def p_ScopedNameList(self, p):
467 """ScopedNameList : ScopedName ScopedNames"""
468 scoped_name = self.BuildNamed('ScopedName', p, 1)
469 p[0] = ListFromConcat(scoped_name, p[2])
470
471 # [s64]
472 def p_ScopedNames(self, p):
473 """ScopedNames : ',' ScopedName ScopedNames
474 |"""
475 if len(p) > 1:
476 scoped_name = self.BuildNamed('ScopedName', p, 2)
477 p[0] = ListFromConcat(scoped_name, p[3])
478
479 # [s65]
480 def p_ScopedName(self, p):
481 """ScopedName : AbsoluteScopedName
482 | RelativeScopedName"""
483 p[0] = p[1]
484
485 # [s66]
486 def p_AbsoluteScopedName(self, p):
487 """AbsoluteScopedName : SCOPE_RESOLUTION identifier ScopedNameParts"""
488 p[0] = p[2]
489
490 # [s67]
491 def p_RelativeScopedName(self, p):
492 """RelativeScopedName : identifier ScopedNameParts"""
493 p[0] = p[1]
494
495 # [s68]
496 def p_ScopedNameParts(self, p):
497 """ScopedNameParts : SCOPE_RESOLUTION identifier ScopedNameParts
498 |"""
499 # if len(p) > 1:
500 # p[0] = p[2]
501 pass
502
503 def __dir__(self):
504 # Remove rules from listing so yacc doesn't parse them
505 keys = set(self.__dict__.keys() + dir(self.__class__))
506 for rule in REMOVED_RULES:
507 keys.remove('p_' + rule)
508 return list(keys)
509
510 def __init__(self, lexer, verbose=False, debug=False, mute_error=False):
511 self.lexer = lexer
512 self.tokens = lexer.KnownTokens()
513 # SLR yields faster table generation (same output), ok b/c LL(1) grammar
514 self.yaccobj = yacc.yacc(module=self, debug=debug, method='SLR')
515 # Optimized mode, improves startup time of yacc compiler
516 # optimize=1
517 # Turn on table generation with:
518 # write_tables=1
519 # Turn off table generation with:
520 # tabmodule=None, write_tables=0
521 self.parse_debug = debug
522 self.verbose = verbose
523 self.mute_error = mute_error
524 self._parse_errors = 0
525 self._parse_warnings = 0
526 self._last_error_msg = None
527 self._last_error_lineno = 0
528 self._last_error_pos = 0
529
530
531 # If run by itself, attempt to build the parser
532 if __name__ == '__main__':
533 parser = BlinkIDLParser(BlinkIDLLexer())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698