| Index: mojo/public/tools/bindings/pylib/mojom/parse/parser.py
|
| diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py b/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
|
| deleted file mode 100644
|
| index 4225f0a7f2373e293f385b2ff2384e76ff318229..0000000000000000000000000000000000000000
|
| --- a/mojo/public/tools/bindings/pylib/mojom/parse/parser.py
|
| +++ /dev/null
|
| @@ -1,412 +0,0 @@
|
| -# Copyright 2014 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Generates a syntax tree from a Mojo IDL file."""
|
| -
|
| -import imp
|
| -import os.path
|
| -import sys
|
| -
|
| -def _GetDirAbove(dirname):
|
| - """Returns the directory "above" this file containing |dirname| (which must
|
| - also be "above" this file)."""
|
| - path = os.path.abspath(__file__)
|
| - while True:
|
| - path, tail = os.path.split(path)
|
| - assert tail
|
| - if tail == dirname:
|
| - return path
|
| -
|
| -try:
|
| - imp.find_module("ply")
|
| -except ImportError:
|
| - sys.path.append(os.path.join(_GetDirAbove("public"), "public/third_party"))
|
| -from ply import lex
|
| -from ply import yacc
|
| -
|
| -from ..error import Error
|
| -from . import ast
|
| -from .lexer import Lexer
|
| -
|
| -
|
| -_MAX_ORDINAL_VALUE = 0xffffffff
|
| -_MAX_ARRAY_SIZE = 0xffffffff
|
| -
|
| -
|
| -class ParseError(Error):
|
| - """Class for errors from the parser."""
|
| -
|
| - def __init__(self, filename, message, lineno=None, snippet=None):
|
| - Error.__init__(self, filename, message, lineno=lineno,
|
| - addenda=([snippet] if snippet else None))
|
| -
|
| -
|
| -# We have methods which look like they could be functions:
|
| -# pylint: disable=R0201
|
| -class Parser(object):
|
| -
|
| - def __init__(self, lexer, source, filename):
|
| - self.tokens = lexer.tokens
|
| - self.source = source
|
| - self.filename = filename
|
| -
|
| - # Names of functions
|
| - #
|
| - # In general, we name functions after the left-hand-side of the rule(s) that
|
| - # they handle. E.g., |p_foo_bar| for a rule |foo_bar : ...|.
|
| - #
|
| - # There may be multiple functions handling rules for the same left-hand-side;
|
| - # then we name the functions |p_foo_bar_N| (for left-hand-side |foo_bar|),
|
| - # where N is a number (numbered starting from 1). Note that using multiple
|
| - # functions is actually more efficient than having single functions handle
|
| - # multiple rules (and, e.g., distinguishing them by examining |len(p)|).
|
| - #
|
| - # It's also possible to have a function handling multiple rules with different
|
| - # left-hand-sides. We do not do this.
|
| - #
|
| - # See http://www.dabeaz.com/ply/ply.html#ply_nn25 for more details.
|
| -
|
| - # TODO(vtl): Get rid of the braces in the module "statement". (Consider
|
| - # renaming "module" -> "package".) Then we'll be able to have a single rule
|
| - # for root (by making module "optional").
|
| - def p_root_1(self, p):
|
| - """root : """
|
| - p[0] = ast.Mojom(None, ast.ImportList(), [])
|
| -
|
| - def p_root_2(self, p):
|
| - """root : root module"""
|
| - if p[1].module is not None:
|
| - raise ParseError(self.filename,
|
| - "Multiple \"module\" statements not allowed:",
|
| - p[2].lineno, snippet=self._GetSnippet(p[2].lineno))
|
| - if p[1].import_list.items or p[1].definition_list:
|
| - raise ParseError(
|
| - self.filename,
|
| - "\"module\" statements must precede imports and definitions:",
|
| - p[2].lineno, snippet=self._GetSnippet(p[2].lineno))
|
| - p[0] = p[1]
|
| - p[0].module = p[2]
|
| -
|
| - def p_root_3(self, p):
|
| - """root : root import"""
|
| - if p[1].definition_list:
|
| - raise ParseError(self.filename,
|
| - "\"import\" statements must precede definitions:",
|
| - p[2].lineno, snippet=self._GetSnippet(p[2].lineno))
|
| - p[0] = p[1]
|
| - p[0].import_list.Append(p[2])
|
| -
|
| - def p_root_4(self, p):
|
| - """root : root definition"""
|
| - p[0] = p[1]
|
| - p[0].definition_list.append(p[2])
|
| -
|
| - def p_import(self, p):
|
| - """import : IMPORT STRING_LITERAL SEMI"""
|
| - # 'eval' the literal to strip the quotes.
|
| - # TODO(vtl): This eval is dubious. We should unquote/unescape ourselves.
|
| - p[0] = ast.Import(eval(p[2]), filename=self.filename, lineno=p.lineno(2))
|
| -
|
| - def p_module(self, p):
|
| - """module : attribute_section MODULE identifier_wrapped SEMI"""
|
| - p[0] = ast.Module(p[3], p[1], filename=self.filename, lineno=p.lineno(2))
|
| -
|
| - def p_definition(self, p):
|
| - """definition : struct
|
| - | union
|
| - | interface
|
| - | enum
|
| - | const"""
|
| - p[0] = p[1]
|
| -
|
| - def p_attribute_section_1(self, p):
|
| - """attribute_section : """
|
| - p[0] = None
|
| -
|
| - def p_attribute_section_2(self, p):
|
| - """attribute_section : LBRACKET attribute_list RBRACKET"""
|
| - p[0] = p[2]
|
| -
|
| - def p_attribute_list_1(self, p):
|
| - """attribute_list : """
|
| - p[0] = ast.AttributeList()
|
| -
|
| - def p_attribute_list_2(self, p):
|
| - """attribute_list : nonempty_attribute_list"""
|
| - p[0] = p[1]
|
| -
|
| - def p_nonempty_attribute_list_1(self, p):
|
| - """nonempty_attribute_list : attribute"""
|
| - p[0] = ast.AttributeList(p[1])
|
| -
|
| - def p_nonempty_attribute_list_2(self, p):
|
| - """nonempty_attribute_list : nonempty_attribute_list COMMA attribute"""
|
| - p[0] = p[1]
|
| - p[0].Append(p[3])
|
| -
|
| - def p_attribute(self, p):
|
| - """attribute : NAME EQUALS evaled_literal
|
| - | NAME EQUALS NAME"""
|
| - p[0] = ast.Attribute(p[1], p[3], filename=self.filename, lineno=p.lineno(1))
|
| -
|
| - def p_evaled_literal(self, p):
|
| - """evaled_literal : literal"""
|
| - # 'eval' the literal to strip the quotes.
|
| - p[0] = eval(p[1])
|
| -
|
| - def p_struct(self, p):
|
| - """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI"""
|
| - p[0] = ast.Struct(p[3], p[1], p[5])
|
| -
|
| - def p_struct_body_1(self, p):
|
| - """struct_body : """
|
| - p[0] = ast.StructBody()
|
| -
|
| - def p_struct_body_2(self, p):
|
| - """struct_body : struct_body const
|
| - | struct_body enum
|
| - | struct_body struct_field"""
|
| - p[0] = p[1]
|
| - p[0].Append(p[2])
|
| -
|
| - def p_struct_field(self, p):
|
| - """struct_field : typename NAME ordinal default SEMI"""
|
| - p[0] = ast.StructField(p[2], p[3], p[1], p[4])
|
| -
|
| - def p_union(self, p):
|
| - """union : UNION NAME LBRACE union_body RBRACE SEMI"""
|
| - p[0] = ast.Union(p[2], p[4])
|
| -
|
| - def p_union_body_1(self, p):
|
| - """union_body : """
|
| - p[0] = ast.UnionBody()
|
| -
|
| - def p_union_body_2(self, p):
|
| - """union_body : union_body union_field"""
|
| - p[0] = p[1]
|
| - p[1].Append(p[2])
|
| -
|
| - def p_union_field(self, p):
|
| - """union_field : typename NAME ordinal SEMI"""
|
| - p[0] = ast.UnionField(p[2], p[3], p[1])
|
| -
|
| - def p_default_1(self, p):
|
| - """default : """
|
| - p[0] = None
|
| -
|
| - def p_default_2(self, p):
|
| - """default : EQUALS constant"""
|
| - p[0] = p[2]
|
| -
|
| - def p_interface(self, p):
|
| - """interface : attribute_section INTERFACE NAME LBRACE interface_body \
|
| - RBRACE SEMI"""
|
| - p[0] = ast.Interface(p[3], p[1], p[5])
|
| -
|
| - def p_interface_body_1(self, p):
|
| - """interface_body : """
|
| - p[0] = ast.InterfaceBody()
|
| -
|
| - def p_interface_body_2(self, p):
|
| - """interface_body : interface_body const
|
| - | interface_body enum
|
| - | interface_body method"""
|
| - p[0] = p[1]
|
| - p[0].Append(p[2])
|
| -
|
| - def p_response_1(self, p):
|
| - """response : """
|
| - p[0] = None
|
| -
|
| - def p_response_2(self, p):
|
| - """response : RESPONSE LPAREN parameter_list RPAREN"""
|
| - p[0] = p[3]
|
| -
|
| - def p_method(self, p):
|
| - """method : NAME ordinal LPAREN parameter_list RPAREN response SEMI"""
|
| - p[0] = ast.Method(p[1], p[2], p[4], p[6])
|
| -
|
| - def p_parameter_list_1(self, p):
|
| - """parameter_list : """
|
| - p[0] = ast.ParameterList()
|
| -
|
| - def p_parameter_list_2(self, p):
|
| - """parameter_list : nonempty_parameter_list"""
|
| - p[0] = p[1]
|
| -
|
| - def p_nonempty_parameter_list_1(self, p):
|
| - """nonempty_parameter_list : parameter"""
|
| - p[0] = ast.ParameterList(p[1])
|
| -
|
| - def p_nonempty_parameter_list_2(self, p):
|
| - """nonempty_parameter_list : nonempty_parameter_list COMMA parameter"""
|
| - p[0] = p[1]
|
| - p[0].Append(p[3])
|
| -
|
| - def p_parameter(self, p):
|
| - """parameter : typename NAME ordinal"""
|
| - p[0] = ast.Parameter(p[2], p[3], p[1],
|
| - filename=self.filename, lineno=p.lineno(2))
|
| -
|
| - def p_typename(self, p):
|
| - """typename : nonnullable_typename QSTN
|
| - | nonnullable_typename"""
|
| - if len(p) == 2:
|
| - p[0] = p[1]
|
| - else:
|
| - p[0] = p[1] + "?"
|
| -
|
| - def p_nonnullable_typename(self, p):
|
| - """nonnullable_typename : basictypename
|
| - | array
|
| - | fixed_array
|
| - | associative_array
|
| - | interfacerequest"""
|
| - p[0] = p[1]
|
| -
|
| - def p_basictypename(self, p):
|
| - """basictypename : identifier
|
| - | handletype"""
|
| - p[0] = p[1]
|
| -
|
| - def p_handletype(self, p):
|
| - """handletype : HANDLE
|
| - | HANDLE LANGLE NAME RANGLE"""
|
| - if len(p) == 2:
|
| - p[0] = p[1]
|
| - else:
|
| - if p[3] not in ('data_pipe_consumer',
|
| - 'data_pipe_producer',
|
| - 'message_pipe',
|
| - 'shared_buffer'):
|
| - # Note: We don't enable tracking of line numbers for everything, so we
|
| - # can't use |p.lineno(3)|.
|
| - raise ParseError(self.filename, "Invalid handle type %r:" % p[3],
|
| - lineno=p.lineno(1),
|
| - snippet=self._GetSnippet(p.lineno(1)))
|
| - p[0] = "handle<" + p[3] + ">"
|
| -
|
| - def p_array(self, p):
|
| - """array : ARRAY LANGLE typename RANGLE"""
|
| - p[0] = p[3] + "[]"
|
| -
|
| - def p_fixed_array(self, p):
|
| - """fixed_array : ARRAY LANGLE typename COMMA INT_CONST_DEC RANGLE"""
|
| - value = int(p[5])
|
| - if value == 0 or value > _MAX_ARRAY_SIZE:
|
| - raise ParseError(self.filename, "Fixed array size %d invalid:" % value,
|
| - lineno=p.lineno(5),
|
| - snippet=self._GetSnippet(p.lineno(5)))
|
| - p[0] = p[3] + "[" + p[5] + "]"
|
| -
|
| - def p_associative_array(self, p):
|
| - """associative_array : MAP LANGLE identifier COMMA typename RANGLE"""
|
| - p[0] = p[5] + "{" + p[3] + "}"
|
| -
|
| - def p_interfacerequest(self, p):
|
| - """interfacerequest : identifier AMP"""
|
| - p[0] = p[1] + "&"
|
| -
|
| - def p_ordinal_1(self, p):
|
| - """ordinal : """
|
| - p[0] = None
|
| -
|
| - def p_ordinal_2(self, p):
|
| - """ordinal : ORDINAL"""
|
| - value = int(p[1][1:])
|
| - if value > _MAX_ORDINAL_VALUE:
|
| - raise ParseError(self.filename, "Ordinal value %d too large:" % value,
|
| - lineno=p.lineno(1),
|
| - snippet=self._GetSnippet(p.lineno(1)))
|
| - p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
|
| -
|
| - def p_enum(self, p):
|
| - """enum : ENUM NAME LBRACE nonempty_enum_value_list RBRACE SEMI
|
| - | ENUM NAME LBRACE nonempty_enum_value_list COMMA RBRACE SEMI"""
|
| - p[0] = ast.Enum(p[2], p[4], filename=self.filename, lineno=p.lineno(1))
|
| -
|
| - def p_nonempty_enum_value_list_1(self, p):
|
| - """nonempty_enum_value_list : enum_value"""
|
| - p[0] = ast.EnumValueList(p[1])
|
| -
|
| - def p_nonempty_enum_value_list_2(self, p):
|
| - """nonempty_enum_value_list : nonempty_enum_value_list COMMA enum_value"""
|
| - p[0] = p[1]
|
| - p[0].Append(p[3])
|
| -
|
| - def p_enum_value(self, p):
|
| - """enum_value : NAME
|
| - | NAME EQUALS int
|
| - | NAME EQUALS identifier_wrapped"""
|
| - p[0] = ast.EnumValue(p[1], p[3] if len(p) == 4 else None,
|
| - filename=self.filename, lineno=p.lineno(1))
|
| -
|
| - def p_const(self, p):
|
| - """const : CONST typename NAME EQUALS constant SEMI"""
|
| - p[0] = ast.Const(p[3], p[2], p[5])
|
| -
|
| - def p_constant(self, p):
|
| - """constant : literal
|
| - | identifier_wrapped"""
|
| - p[0] = p[1]
|
| -
|
| - def p_identifier_wrapped(self, p):
|
| - """identifier_wrapped : identifier"""
|
| - p[0] = ('IDENTIFIER', p[1])
|
| -
|
| - # TODO(vtl): Make this produce a "wrapped" identifier (probably as an
|
| - # |ast.Identifier|, to be added) and get rid of identifier_wrapped.
|
| - def p_identifier(self, p):
|
| - """identifier : NAME
|
| - | NAME DOT identifier"""
|
| - p[0] = ''.join(p[1:])
|
| -
|
| - def p_literal(self, p):
|
| - """literal : int
|
| - | float
|
| - | TRUE
|
| - | FALSE
|
| - | DEFAULT
|
| - | STRING_LITERAL"""
|
| - p[0] = p[1]
|
| -
|
| - def p_int(self, p):
|
| - """int : int_const
|
| - | PLUS int_const
|
| - | MINUS int_const"""
|
| - p[0] = ''.join(p[1:])
|
| -
|
| - def p_int_const(self, p):
|
| - """int_const : INT_CONST_DEC
|
| - | INT_CONST_HEX"""
|
| - p[0] = p[1]
|
| -
|
| - def p_float(self, p):
|
| - """float : FLOAT_CONST
|
| - | PLUS FLOAT_CONST
|
| - | MINUS FLOAT_CONST"""
|
| - p[0] = ''.join(p[1:])
|
| -
|
| - def p_error(self, e):
|
| - if e is None:
|
| - # Unexpected EOF.
|
| - # TODO(vtl): Can we figure out what's missing?
|
| - raise ParseError(self.filename, "Unexpected end of file")
|
| -
|
| - raise ParseError(self.filename, "Unexpected %r:" % e.value, lineno=e.lineno,
|
| - snippet=self._GetSnippet(e.lineno))
|
| -
|
| - def _GetSnippet(self, lineno):
|
| - return self.source.split('\n')[lineno - 1]
|
| -
|
| -
|
| -def Parse(source, filename):
|
| - lexer = Lexer(filename)
|
| - parser = Parser(lexer, source, filename)
|
| -
|
| - lex.lex(object=lexer)
|
| - yacc.yacc(module=parser, debug=0, write_tables=0)
|
| -
|
| - tree = yacc.parse(source)
|
| - return tree
|
|
|