| 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 |