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