Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / mojo / public / tools / bindings / pylib / mojom / parse / parser.py
1 # Copyright 2014 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 """Generates a syntax tree from a Mojo IDL file."""
6
7 import imp
8 import os.path
9 import sys
10
11 # Disable lint check for finding modules:
12 # pylint: disable=F0401
13
14 def _GetDirAbove(dirname):
15   """Returns the directory "above" this file containing |dirname| (which must
16   also be "above" this file)."""
17   path = os.path.abspath(__file__)
18   while True:
19     path, tail = os.path.split(path)
20     assert tail
21     if tail == dirname:
22       return path
23
24 try:
25   imp.find_module("ply")
26 except ImportError:
27   sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
28 from ply import lex
29 from ply import yacc
30
31 from ..error import Error
32 import ast
33 from lexer import Lexer
34
35
36 _MAX_ORDINAL_VALUE = 0xffffffff
37
38
39 def _ListFromConcat(*items):
40   """Generate list by concatenating inputs (note: only concatenates lists, not
41   tuples or other iterables)."""
42   itemsout = []
43   for item in items:
44     if item is None:
45       continue
46     if type(item) is not type([]):
47       itemsout.append(item)
48     else:
49       itemsout.extend(item)
50   return itemsout
51
52
53 # Disable lint check for exceptions deriving from Exception:
54 # pylint: disable=W0710
55 class ParseError(Error):
56   """Class for errors from the parser."""
57
58   def __init__(self, filename, message, lineno=None, snippet=None):
59     Error.__init__(self, filename, message, lineno=lineno,
60                    addenda=([snippet] if snippet else None))
61
62
63 # We have methods which look like they could be functions:
64 # pylint: disable=R0201
65 class Parser(object):
66
67   def __init__(self, lexer, source, filename):
68     self.tokens = lexer.tokens
69     self.source = source
70     self.filename = filename
71
72   def p_root(self, p):
73     """root : import root
74             | module
75             | definitions"""
76     if len(p) > 2:
77       p[0] = _ListFromConcat(p[1], p[2])
78     else:
79       # Generator expects a module. If one wasn't specified insert one with an
80       # empty name.
81       if p[1][0] != 'MODULE':
82         p[0] = [('MODULE', '', [], p[1])]
83       else:
84         p[0] = [p[1]]
85
86   def p_import(self, p):
87     """import : IMPORT STRING_LITERAL"""
88     # 'eval' the literal to strip the quotes.
89     p[0] = ('IMPORT', eval(p[2]))
90
91   def p_module(self, p):
92     """module : attribute_section MODULE identifier LBRACE definitions RBRACE"""
93     p[0] = ('MODULE', p[3], p[1], p[5])
94
95   def p_definitions(self, p):
96     """definitions : definition definitions
97                    | """
98     if len(p) > 1:
99       p[0] = _ListFromConcat(p[1], p[2])
100
101   def p_definition(self, p):
102     """definition : struct
103                   | interface
104                   | enum"""
105     p[0] = p[1]
106
107   def p_attribute_section(self, p):
108     """attribute_section : LBRACKET attributes RBRACKET
109                          | """
110     if len(p) > 3:
111       p[0] = p[2]
112
113   def p_attributes(self, p):
114     """attributes : attribute
115                   | attribute COMMA attributes
116                   | """
117     if len(p) == 2:
118       p[0] = _ListFromConcat(p[1])
119     elif len(p) > 3:
120       p[0] = _ListFromConcat(p[1], p[3])
121
122   def p_attribute(self, p):
123     """attribute : NAME EQUALS expression
124                  | NAME EQUALS NAME"""
125     p[0] = ('ATTRIBUTE', p[1], p[3])
126
127   def p_struct(self, p):
128     """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI"""
129     p[0] = ('STRUCT', p[3], p[1], p[5])
130
131   def p_struct_body(self, p):
132     """struct_body : field struct_body
133                    | enum struct_body
134                    | """
135     if len(p) > 1:
136       p[0] = _ListFromConcat(p[1], p[2])
137
138   def p_field(self, p):
139     """field : typename NAME default ordinal SEMI"""
140     p[0] = ('FIELD', p[1], p[2], p[4], p[3])
141
142   def p_default(self, p):
143     """default : EQUALS expression
144                | EQUALS expression_object
145                | """
146     if len(p) > 2:
147       p[0] = p[2]
148
149   def p_interface(self, p):
150     """interface : attribute_section INTERFACE NAME LBRACE interface_body \
151                        RBRACE SEMI"""
152     p[0] = ('INTERFACE', p[3], p[1], p[5])
153
154   def p_interface_body(self, p):
155     """interface_body : method interface_body
156                       | enum interface_body
157                       | """
158     if len(p) > 1:
159       p[0] = _ListFromConcat(p[1], p[2])
160
161   def p_response(self, p):
162     """response : RESPONSE LPAREN parameters RPAREN
163                 | """
164     if len(p) > 3:
165       p[0] = p[3]
166
167   def p_method(self, p):
168     """method : NAME ordinal LPAREN parameters RPAREN response SEMI"""
169     p[0] = ('METHOD', p[1], p[4], p[2], p[6])
170
171   def p_parameters(self, p):
172     """parameters : parameter
173                   | parameter COMMA parameters
174                   | """
175     if len(p) == 1:
176       p[0] = []
177     elif len(p) == 2:
178       p[0] = _ListFromConcat(p[1])
179     elif len(p) > 3:
180       p[0] = _ListFromConcat(p[1], p[3])
181
182   def p_parameter(self, p):
183     """parameter : typename NAME ordinal"""
184     p[0] = ('PARAM', p[1], p[2], p[3])
185
186   def p_typename(self, p):
187     """typename : basictypename
188                 | array"""
189     p[0] = p[1]
190
191   def p_basictypename(self, p):
192     """basictypename : identifier
193                      | HANDLE
194                      | specializedhandle"""
195     p[0] = p[1]
196
197   def p_specializedhandle(self, p):
198     """specializedhandle : HANDLE LANGLE specializedhandlename RANGLE"""
199     p[0] = "handle<" + p[3] + ">"
200
201   def p_specializedhandlename(self, p):
202     """specializedhandlename : DATA_PIPE_CONSUMER
203                              | DATA_PIPE_PRODUCER
204                              | MESSAGE_PIPE
205                              | SHARED_BUFFER"""
206     p[0] = p[1]
207
208   def p_array(self, p):
209     """array : typename LBRACKET RBRACKET"""
210     p[0] = p[1] + "[]"
211
212   def p_ordinal(self, p):
213     """ordinal : ORDINAL
214                | """
215     if len(p) > 1:
216       value = int(p[1][1:])
217       if value > _MAX_ORDINAL_VALUE:
218         raise ParseError(self.filename, "Ordinal value %d too large:" % value,
219                          lineno=p.lineno(1),
220                          snippet=self._GetSnippet(p.lineno(1)))
221       p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
222     else:
223       p[0] = ast.Ordinal(None)
224
225   def p_enum(self, p):
226     """enum : ENUM NAME LBRACE enum_fields RBRACE SEMI"""
227     p[0] = ('ENUM', p[2], p[4])
228
229   def p_enum_fields(self, p):
230     """enum_fields : enum_field
231                    | enum_field COMMA enum_fields
232                    | """
233     if len(p) == 2:
234       p[0] = _ListFromConcat(p[1])
235     elif len(p) > 3:
236       p[0] = _ListFromConcat(p[1], p[3])
237
238   def p_enum_field(self, p):
239     """enum_field : NAME
240                   | NAME EQUALS expression"""
241     if len(p) == 2:
242       p[0] = ('ENUM_FIELD', p[1], None)
243     else:
244       p[0] = ('ENUM_FIELD', p[1], p[3])
245
246   ### Expressions ###
247
248   def p_expression_object(self, p):
249     """expression_object : expression_array
250                          | LBRACE expression_object_elements RBRACE """
251     if len(p) < 3:
252       p[0] = p[1]
253     else:
254       p[0] = ('OBJECT', p[2])
255
256   def p_expression_object_elements(self, p):
257     """expression_object_elements : expression_object
258                                   | expression_object COMMA expression_object_elements
259                                   | """
260     if len(p) == 2:
261       p[0] = _ListFromConcat(p[1])
262     elif len(p) > 3:
263       p[0] = _ListFromConcat(p[1], p[3])
264
265   def p_expression_array(self, p):
266     """expression_array : expression
267                         | LBRACKET expression_array_elements RBRACKET """
268     if len(p) < 3:
269       p[0] = p[1]
270     else:
271       p[0] = ('ARRAY', p[2])
272
273   def p_expression_array_elements(self, p):
274     """expression_array_elements : expression_object
275                                  | expression_object COMMA expression_array_elements
276                                  | """
277     if len(p) == 2:
278       p[0] = _ListFromConcat(p[1])
279     elif len(p) > 3:
280       p[0] = _ListFromConcat(p[1], p[3])
281
282   # TODO(vtl): This is now largely redundant.
283   def p_expression(self, p):
284     """expression : binary_expression"""
285     p[0] = ('EXPRESSION', p[1])
286
287   # PLY lets us specify precedence of operators, but since we don't actually
288   # evaluate them, we don't need that here.
289   # TODO(vtl): We're going to need to evaluate them.
290   def p_binary_expression(self, p):
291     """binary_expression : unary_expression
292                          | binary_expression binary_operator \
293                                binary_expression"""
294     p[0] = _ListFromConcat(*p[1:])
295
296   def p_binary_operator(self, p):
297     """binary_operator : TIMES
298                        | DIVIDE
299                        | MOD
300                        | PLUS
301                        | MINUS
302                        | RSHIFT
303                        | LSHIFT
304                        | AND
305                        | OR
306                        | XOR"""
307     p[0] = p[1]
308
309   def p_unary_expression(self, p):
310     """unary_expression : primary_expression
311                         | unary_operator expression"""
312     p[0] = _ListFromConcat(*p[1:])
313
314   def p_unary_operator(self, p):
315     """unary_operator : PLUS
316                       | MINUS
317                       | NOT"""
318     p[0] = p[1]
319
320   def p_primary_expression(self, p):
321     """primary_expression : constant
322                           | identifier
323                           | LPAREN expression RPAREN"""
324     p[0] = _ListFromConcat(*p[1:])
325
326   def p_identifier(self, p):
327     """identifier : NAME
328                   | NAME DOT identifier"""
329     p[0] = ''.join(p[1:])
330
331   def p_constant(self, p):
332     """constant : INT_CONST_DEC
333                 | INT_CONST_OCT
334                 | INT_CONST_HEX
335                 | FLOAT_CONST
336                 | CHAR_CONST
337                 | STRING_LITERAL"""
338     p[0] = _ListFromConcat(*p[1:])
339
340   def p_error(self, e):
341     if e is None:
342       # Unexpected EOF.
343       # TODO(vtl): Can we figure out what's missing?
344       raise ParseError(self.filename, "Unexpected end of file")
345
346     raise ParseError(self.filename, "Unexpected %r:" % e.value, lineno=e.lineno,
347                      snippet=self._GetSnippet(e.lineno))
348
349   def _GetSnippet(self, lineno):
350     return self.source.split('\n')[lineno - 1]
351
352
353 def Parse(source, filename):
354   lexer = Lexer(filename)
355   parser = Parser(lexer, source, filename)
356
357   lex.lex(object=lexer)
358   yacc.yacc(module=parser, debug=0, write_tables=0)
359
360   tree = yacc.parse(source)
361   return tree