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.
5 """Generates a syntax tree from a Mojo IDL file."""
11 # Disable lint check for finding modules:
12 # pylint: disable=F0401
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__)
19 path, tail = os.path.split(path)
25 imp.find_module("ply")
27 sys.path.append(os.path.join(_GetDirAbove("mojo"), "third_party"))
31 from ..error import Error
33 from lexer import Lexer
36 _MAX_ORDINAL_VALUE = 0xffffffff
39 def _ListFromConcat(*items):
40 """Generate list by concatenating inputs (note: only concatenates lists, not
41 tuples or other iterables)."""
46 if type(item) is not type([]):
53 # Disable lint check for exceptions deriving from Exception:
54 # pylint: disable=W0710
55 class ParseError(Error):
56 """Class for errors from the parser."""
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))
63 # We have methods which look like they could be functions:
64 # pylint: disable=R0201
67 def __init__(self, lexer, source, filename):
68 self.tokens = lexer.tokens
70 self.filename = filename
77 p[0] = _ListFromConcat(p[1], p[2])
79 # Generator expects a module. If one wasn't specified insert one with an
81 if p[1][0] != 'MODULE':
82 p[0] = [('MODULE', '', [], p[1])]
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]))
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])
95 def p_definitions(self, p):
96 """definitions : definition definitions
99 p[0] = _ListFromConcat(p[1], p[2])
101 def p_definition(self, p):
102 """definition : struct
107 def p_attribute_section(self, p):
108 """attribute_section : LBRACKET attributes RBRACKET
113 def p_attributes(self, p):
114 """attributes : attribute
115 | attribute COMMA attributes
118 p[0] = _ListFromConcat(p[1])
120 p[0] = _ListFromConcat(p[1], p[3])
122 def p_attribute(self, p):
123 """attribute : NAME EQUALS expression
124 | NAME EQUALS NAME"""
125 p[0] = ('ATTRIBUTE', p[1], p[3])
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])
131 def p_struct_body(self, p):
132 """struct_body : field struct_body
136 p[0] = _ListFromConcat(p[1], p[2])
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])
142 def p_default(self, p):
143 """default : EQUALS expression
144 | EQUALS expression_object
149 def p_interface(self, p):
150 """interface : attribute_section INTERFACE NAME LBRACE interface_body \
152 p[0] = ('INTERFACE', p[3], p[1], p[5])
154 def p_interface_body(self, p):
155 """interface_body : method interface_body
156 | enum interface_body
159 p[0] = _ListFromConcat(p[1], p[2])
161 def p_response(self, p):
162 """response : RESPONSE LPAREN parameters RPAREN
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])
171 def p_parameters(self, p):
172 """parameters : parameter
173 | parameter COMMA parameters
178 p[0] = _ListFromConcat(p[1])
180 p[0] = _ListFromConcat(p[1], p[3])
182 def p_parameter(self, p):
183 """parameter : typename NAME ordinal"""
184 p[0] = ('PARAM', p[1], p[2], p[3])
186 def p_typename(self, p):
187 """typename : basictypename
191 def p_basictypename(self, p):
192 """basictypename : identifier
194 | specializedhandle"""
197 def p_specializedhandle(self, p):
198 """specializedhandle : HANDLE LANGLE specializedhandlename RANGLE"""
199 p[0] = "handle<" + p[3] + ">"
201 def p_specializedhandlename(self, p):
202 """specializedhandlename : DATA_PIPE_CONSUMER
208 def p_array(self, p):
209 """array : typename LBRACKET RBRACKET"""
212 def p_ordinal(self, p):
216 value = int(p[1][1:])
217 if value > _MAX_ORDINAL_VALUE:
218 raise ParseError(self.filename, "Ordinal value %d too large:" % value,
220 snippet=self._GetSnippet(p.lineno(1)))
221 p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
223 p[0] = ast.Ordinal(None)
226 """enum : ENUM NAME LBRACE enum_fields RBRACE SEMI"""
227 p[0] = ('ENUM', p[2], p[4])
229 def p_enum_fields(self, p):
230 """enum_fields : enum_field
231 | enum_field COMMA enum_fields
234 p[0] = _ListFromConcat(p[1])
236 p[0] = _ListFromConcat(p[1], p[3])
238 def p_enum_field(self, p):
240 | NAME EQUALS expression"""
242 p[0] = ('ENUM_FIELD', p[1], None)
244 p[0] = ('ENUM_FIELD', p[1], p[3])
248 def p_expression_object(self, p):
249 """expression_object : expression_array
250 | LBRACE expression_object_elements RBRACE """
254 p[0] = ('OBJECT', p[2])
256 def p_expression_object_elements(self, p):
257 """expression_object_elements : expression_object
258 | expression_object COMMA expression_object_elements
261 p[0] = _ListFromConcat(p[1])
263 p[0] = _ListFromConcat(p[1], p[3])
265 def p_expression_array(self, p):
266 """expression_array : expression
267 | LBRACKET expression_array_elements RBRACKET """
271 p[0] = ('ARRAY', p[2])
273 def p_expression_array_elements(self, p):
274 """expression_array_elements : expression_object
275 | expression_object COMMA expression_array_elements
278 p[0] = _ListFromConcat(p[1])
280 p[0] = _ListFromConcat(p[1], p[3])
282 # TODO(vtl): This is now largely redundant.
283 def p_expression(self, p):
284 """expression : binary_expression"""
285 p[0] = ('EXPRESSION', p[1])
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 \
294 p[0] = _ListFromConcat(*p[1:])
296 def p_binary_operator(self, p):
297 """binary_operator : TIMES
309 def p_unary_expression(self, p):
310 """unary_expression : primary_expression
311 | unary_operator expression"""
312 p[0] = _ListFromConcat(*p[1:])
314 def p_unary_operator(self, p):
315 """unary_operator : PLUS
320 def p_primary_expression(self, p):
321 """primary_expression : constant
323 | LPAREN expression RPAREN"""
324 p[0] = _ListFromConcat(*p[1:])
326 def p_identifier(self, p):
328 | NAME DOT identifier"""
329 p[0] = ''.join(p[1:])
331 def p_constant(self, p):
332 """constant : INT_CONST_DEC
338 p[0] = _ListFromConcat(*p[1:])
340 def p_error(self, e):
343 # TODO(vtl): Can we figure out what's missing?
344 raise ParseError(self.filename, "Unexpected end of file")
346 raise ParseError(self.filename, "Unexpected %r:" % e.value, lineno=e.lineno,
347 snippet=self._GetSnippet(e.lineno))
349 def _GetSnippet(self, lineno):
350 return self.source.split('\n')[lineno - 1]
353 def Parse(source, filename):
354 lexer = Lexer(filename)
355 parser = Parser(lexer, source, filename)
357 lex.lex(object=lexer)
358 yacc.yacc(module=parser, debug=0, write_tables=0)
360 tree = yacc.parse(source)