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

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

Issue 181513006: IDL compiler: delete Perl compiler, remove unstable/ directory (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 9 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 rules where Blink IDL
34 differs syntactically or semantically from the base parser, or where the base
35 parser diverges from the Web IDL standard.
36
37 Web IDL:
38 http://www.w3.org/TR/WebIDL/
39 Web IDL Grammar:
40 http://www.w3.org/TR/WebIDL/#idl-grammar
41 PLY:
42 http://www.dabeaz.com/ply/
43 """
44
45 # Disable check for line length and Member as Function due to how grammar rules
46 # are defined with PLY
47 #
48 # pylint: disable=R0201
49 # pylint: disable=C0301
50 #
51 # Disable attribute validation, as lint can't import parent class to check
52 # pylint: disable=E1101
53
54 import os.path
55 import sys
56
57 # PLY is in Chromium src/third_party/ply
58 module_path, module_name = os.path.split(__file__)
59 third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pard ir, os.pardir)
60 # Insert at front to override system libraries, and after path[0] == script dir
61 sys.path.insert(1, third_party)
62 from ply import yacc
63
64 # Base parser is in Chromium src/tools/idl_parser
65 tools_dir = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir , os.pardir, os.pardir, 'tools')
66 sys.path.append(tools_dir)
67 from idl_parser.idl_parser import IDLParser, ListFromConcat
68 from idl_parser.idl_parser import ParseFile as parse_file
69
70 from blink_idl_lexer import BlinkIDLLexer
71
72
73 # Explicitly set starting symbol to rule defined only in base parser.
74 # BEWARE that the starting symbol should NOT be defined in both the base parser
75 # and the derived one, as otherwise which is used depends on which line number
76 # is lower, which is fragile. Instead, either use one in base parser or
77 # create a new symbol, so that this is unambiguous.
78 # FIXME: unfortunately, this doesn't work in PLY 3.4, so need to duplicate the
79 # rule below.
80 STARTING_SYMBOL = 'Definitions'
81
82 # We ignore comments (and hence don't need 'Top') but base parser preserves them
83 # FIXME: Upstream: comments should be removed in base parser
84 REMOVED_RULES = ['Top', # [0]
85 'Comments', # [0.1]
86 'CommentsRest', # [0.2]
87 ]
88
89
90 class BlinkIDLParser(IDLParser):
91 # [1]
92 # FIXME: Need to duplicate rule for starting symbol here, with line number
93 # *lower* than in the base parser (idl_parser.py).
94 # This is a bug in PLY: it determines starting symbol by lowest line number.
95 # This can be overridden by the 'start' parameter, but as of PLY 3.4 this
96 # doesn't work correctly.
97 def p_Definitions(self, p):
98 """Definitions : ExtendedAttributeList Definition Definitions
99 | """
100 if len(p) > 1:
101 p[2].AddChildren(p[1])
102 p[0] = ListFromConcat(p[2], p[3])
103
104 # Below are grammar rules used by yacc, given by functions named p_<RULE>.
105 # * The docstring is the production rule in BNF (grammar).
106 # * The body is the yacc action (semantics).
107 #
108 # The PLY framework builds the actual low-level parser by introspecting this
109 # parser object, selecting all attributes named p_<RULE> as grammar rules.
110 # It extracts the docstrings and uses them as the production rules, building
111 # the table of a LALR parser, and uses the body of the functions as actions.
112 #
113 # Reference:
114 # http://www.dabeaz.com/ply/ply.html#ply_nn23
115 #
116 # Review of yacc:
117 # Yacc parses a token stream, internally producing a Concrete Syntax Tree
118 # (CST), where each node corresponds to a production rule in the grammar.
119 # At each node, it runs an action, which is usually "produce a node in the
120 # Abstract Syntax Tree (AST)" or "ignore this node" (for nodes in the CST
121 # that aren't included in the AST, since only needed for parsing).
122 #
123 # The rules use pseudo-variables; in PLY syntax:
124 # p[0] is the left side: assign return value to p[0] instead of returning,
125 # p[1] ... p[n] are the right side: the values can be accessed, and they
126 # can be modified.
127 # (In yacc these are $$ and $1 ... $n.)
128 #
129 # The rules can look cryptic at first, but there are a few standard
130 # transforms from the CST to AST. With these in mind, the actions should
131 # be reasonably legible.
132 #
133 # * Ignore production
134 # Discard this branch. Primarily used when one alternative is empty.
135 #
136 # Sample code:
137 # if len(p) > 1:
138 # p[0] = ...
139 # # Note no assignment if len(p) == 1
140 #
141 # * Eliminate singleton production
142 # Discard this node in the CST, pass the next level down up the tree.
143 # Used to ignore productions only necessary for parsing, but not needed
144 # in the AST.
145 #
146 # Sample code:
147 # p[0] = p[1]
148 #
149 # * Build node
150 # The key type of rule. In this parser, produces object of class IDLNode.
151 # There are several helper functions:
152 # * BuildProduction: actually builds an IDLNode, based on a production.
153 # * BuildAttribute: builds an IDLAttribute, which is a temporary
154 # object to hold a name-value pair, which is then
155 # set as a Property of the IDLNode when the IDLNode
156 # is built.
157 # * BuildNamed: Same as BuildProduction, and sets the 'NAME' property.
158 # * BuildTrue: BuildAttribute with value True, for flags.
159 # See base idl_parser.py for definitions and more examples of use.
160 #
161 # Sample code:
162 # # Build node of type NodeType, with value p[1], and children.
163 # p[0] = self.BuildProduction('NodeType', p, 1, children)
164 #
165 # # Build named node of type NodeType, with name and value p[1].
166 # # (children optional)
167 # p[0] = self.BuildNamed('NodeType', p, 1)
168 #
169 # # Make a list
170 # # Used if one node has several children.
171 # children = ListFromConcat(p[2], p[3])
172 # p[0] = self.BuildProduction('NodeType', p, 1, children)
173 #
174 # # Also used to collapse the right-associative tree
175 # # produced by parsing a list back into a single list.
176 # """Foos : Foo Foos
177 # |"""
178 # if len(p) > 1:
179 # p[0] = ListFromConcat(p[1], p[2])
180 #
181 # # Add children.
182 # # Primarily used to add attributes, produced via BuildTrue.
183 # # p_StaticAttribute
184 # """StaticAttribute : STATIC Attribute"""
185 # p[2].AddChildren(self.BuildTrue('STATIC'))
186 # p[0] = p[2]
187 #
188 # Numbering scheme for the rules is:
189 # [1] for Web IDL spec (or additions in base parser)
190 # These should all be upstreamed to the base parser.
191 # [b1] for Blink IDL changes (overrides Web IDL)
192 # [b1.1] for Blink IDL additions, auxiliary rules for [b1]
193 # Numbers are as per Candidate Recommendation 19 April 2012:
194 # http://www.w3.org/TR/2012/CR-WebIDL-20120419/
195
196 # [3] Override action, since we distinguish callbacks
197 # FIXME: Upstream
198 def p_CallbackOrInterface(self, p):
199 """CallbackOrInterface : CALLBACK CallbackRestOrInterface
200 | Interface"""
201 if len(p) > 2:
202 p[2].AddChildren(self.BuildTrue('CALLBACK'))
203 p[0] = p[2]
204 else:
205 p[0] = p[1]
206
207 # [b27] Add strings, more 'Literal' productions
208 # 'Literal's needed because integers and strings are both internally strings
209 def p_ConstValue(self, p):
210 """ConstValue : BooleanLiteral
211 | FloatLiteral
212 | IntegerLiteral
213 | StringLiteral
214 | null"""
215 # Standard is (no 'string', fewer 'Literal's):
216 # ConstValue : BooleanLiteral
217 # | FloatLiteral
218 # | integer
219 # | NULL
220 p[0] = p[1]
221
222 # [b27.1]
223 def p_IntegerLiteral(self, p):
224 """IntegerLiteral : integer"""
225 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'),
226 self.BuildAttribute('NAME', p[1]))
227
228 # [b27.2]
229 def p_StringLiteral(self, p):
230 """StringLiteral : string"""
231 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'DOMString'),
232 self.BuildAttribute('NAME', p[1]))
233
234 # [b30] Add StaticAttribute
235 def p_AttributeOrOperation(self, p):
236 """AttributeOrOperation : STRINGIFIER StringifierAttributeOrOperation
237 | Attribute
238 | StaticAttribute
239 | Operation"""
240 # Standard is (no StaticAttribute):
241 # AttributeOrOperation : STRINGIFIER StringifierAttributeOrOperation
242 # | Attribute
243 # | Operation
244 if len(p) > 2:
245 # FIXME: Clearer to add stringifier property here, as:
246 # p[2].AddChildren(self.BuildTrue('STRINGIFIER'))
247 # Fix when actually implementing stringifiers.
248 p[0] = p[2]
249 else:
250 p[0] = p[1]
251
252 # [b30.1]
253 def p_StaticAttribute(self, p):
254 """StaticAttribute : STATIC Attribute"""
255 p[2].AddChildren(self.BuildTrue('STATIC'))
256 p[0] = p[2]
257
258 # [b47]
259 def p_ExceptionMember(self, p):
260 """ExceptionMember : Const
261 | ExceptionField
262 | Attribute
263 | ExceptionOperation"""
264 # Standard is (no Attribute, no ExceptionOperation):
265 # ExceptionMember : Const
266 # | ExceptionField
267 # FIXME: In DOMException.idl, Attributes should be changed to
268 # ExceptionFields, and Attribute removed from this rule.
269 p[0] = p[1]
270
271 # [b47.1]
272 def p_ExceptionOperation(self, p):
273 """ExceptionOperation : Type identifier '(' ')' ';'"""
274 # Needed to handle one case in DOMException.idl:
275 # // Override in a Mozilla compatible format
276 # [NotEnumerable] DOMString toString();
277 # Limited form of Operation to prevent others from being added.
278 # FIXME: Should be a stringifier instead.
279 p[0] = self.BuildNamed('ExceptionOperation', p, 2, p[1])
280
281 # Extended attributes
282 # [b49] Override base parser: remove comment field, since comments stripped
283 # FIXME: Upstream
284 def p_ExtendedAttributeList(self, p):
285 """ExtendedAttributeList : '[' ExtendedAttribute ExtendedAttributes ']'
286 | '[' ']'
287 | """
288 if len(p) > 3:
289 items = ListFromConcat(p[2], p[3])
290 p[0] = self.BuildProduction('ExtAttributes', p, 1, items)
291
292 # [b50] Allow optional trailing comma
293 # Blink-only, marked as WONTFIX in Web IDL spec:
294 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=22156
295 def p_ExtendedAttributes(self, p):
296 """ExtendedAttributes : ',' ExtendedAttribute ExtendedAttributes
297 | ','
298 |"""
299 if len(p) > 3:
300 p[0] = ListFromConcat(p[2], p[3])
301
302 # [b51] Add ExtendedAttributeIdentAndOrIdent
303 def p_ExtendedAttribute(self, p):
304 """ExtendedAttribute : ExtendedAttributeNoArgs
305 | ExtendedAttributeArgList
306 | ExtendedAttributeIdent
307 | ExtendedAttributeIdentList
308 | ExtendedAttributeStringLiteralList
309 | ExtendedAttributeNamedArgList"""
310 p[0] = p[1]
311
312 # [59]
313 # FIXME: Upstream UnionType
314 def p_UnionType(self, p):
315 """UnionType : '(' UnionMemberType OR UnionMemberType UnionMemberTypes ' )'"""
316 members = ListFromConcat(p[2], p[4], p[5])
317 p[0] = self.BuildProduction('UnionType', p, 1, members)
318
319 # [60]
320 def p_UnionMemberType(self, p):
321 """UnionMemberType : NonAnyType
322 | UnionType TypeSuffix
323 | ANY '[' ']' TypeSuffix"""
324 if len(p) == 2:
325 p[0] = self.BuildProduction('Type', p, 1, p[1])
326 elif len(p) == 3:
327 p[0] = self.BuildProduction('Type', p, 1, ListFromConcat(p[1], p[2]) )
328 else:
329 any_node = ListFromConcat(self.BuildProduction('Any', p, 1), p[4])
330 p[0] = self.BuildProduction('Type', p, 1, any_node)
331
332 # [61]
333 def p_UnionMemberTypes(self, p):
334 """UnionMemberTypes : OR UnionMemberType UnionMemberTypes
335 |"""
336 if len(p) > 2:
337 p[0] = ListFromConcat(p[2], p[3])
338
339 # [70] Override base parser to remove non-standard sized array
340 # FIXME: Upstream
341 def p_TypeSuffix(self, p):
342 """TypeSuffix : '[' ']' TypeSuffix
343 | '?' TypeSuffixStartingWithArray
344 |"""
345 if len(p) == 4:
346 p[0] = self.BuildProduction('Array', p, 1, p[3])
347 elif len(p) == 3:
348 p[0] = ListFromConcat(self.BuildTrue('NULLABLE'), p[2])
349
350 # [b76.1] Add support for compound Extended Attribute values (A&B and A|B)
351 def p_ExtendedAttributeIdentList(self, p):
352 """ExtendedAttributeIdentList : identifier '=' identifier '&' IdentAndLi st
353 | identifier '=' identifier '|' IdentOrLis t"""
354 value = self.BuildAttribute('VALUE', p[3] + p[4] + p[5])
355 p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
356
357 # [b76.2] A&B&C
358 def p_IdentAndList(self, p):
359 """IdentAndList : identifier '&' IdentAndList
360 | identifier"""
361 if len(p) > 3:
362 p[0] = p[1] + p[2] + p[3]
363 else:
364 p[0] = p[1]
365
366 # [b76.3] A|B|C
367 def p_IdentOrList(self, p):
368 """IdentOrList : identifier '|' IdentOrList
369 | identifier"""
370 if len(p) > 3:
371 p[0] = p[1] + p[2] + p[3]
372 else:
373 p[0] = p[1]
374
375 # Blink extension: Add support for compound Extended Attribute values over s tring literals ("A"|"B")
376 def p_ExtendedAttributeStringLiteralList(self, p):
377 """ExtendedAttributeStringLiteralList : identifier '=' StringLiteralOrLi st"""
378 value = self.BuildAttribute('VALUE', p[3])
379 p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
380
381 # Blink extension: one or more string literals. The values aren't propagated as literals,
382 # but their by their value only.
383 def p_StringLiteralOrList(self, p):
384 """StringLiteralOrList : StringLiteral '|' StringLiteralOrList
385 | StringLiteral"""
386 def unwrap_string(ls):
387 """Reach in and grab the string literal's "NAME"."""
388 return ls[1].value
389
390 if len(p) > 3:
391 p[0] = unwrap_string(p[1]) + p[2] + p[3]
392 else:
393 p[0] = unwrap_string(p[1])
394
395 def __dir__(self):
396 # Remove REMOVED_RULES from listing so yacc doesn't parse them
397 # FIXME: Upstream
398 keys = set(self.__dict__.keys() + dir(self.__class__))
399 for rule in REMOVED_RULES:
400 production_name = 'p_' + rule
401 if production_name in keys:
402 keys.remove(production_name)
403 return list(keys)
404
405 def __init__(self, lexer=None, verbose=False, debug=False, mute_error=False, outputdir=''):
406 lexer = lexer or BlinkIDLLexer()
407 self.lexer = lexer
408 self.tokens = lexer.KnownTokens()
409 # Using SLR (instead of LALR) generates the table faster,
410 # but produces the same output. This is ok b/c Web IDL (and Blink IDL)
411 # is an SLR grammar (as is often the case for simple LL(1) grammars).
412 self.yaccobj = yacc.yacc(module=self, start=STARTING_SYMBOL, method='SLR ', debug=debug, outputdir=outputdir)
413 self.parse_debug = debug
414 self.verbose = verbose
415 self.mute_error = mute_error
416 self._parse_errors = 0
417 self._parse_warnings = 0
418 self._last_error_msg = None
419 self._last_error_lineno = 0
420 self._last_error_pos = 0
421
422
423 # If run by itself, attempt to build the parser
424 if __name__ == '__main__':
425 parser = BlinkIDLParser()
OLDNEW
« no previous file with comments | « Source/bindings/scripts/unstable/blink_idl_lexer.py ('k') | Source/bindings/scripts/unstable/code_generator_v8.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698