| Index: Source/bindings/scripts/blink_idl_parser.py
|
| diff --git a/Source/bindings/scripts/blink_idl_parser.py b/Source/bindings/scripts/blink_idl_parser.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3122a25de8eff25b3d492f5eee65ada685e10a7d
|
| --- /dev/null
|
| +++ b/Source/bindings/scripts/blink_idl_parser.py
|
| @@ -0,0 +1,533 @@
|
| +# Copyright (C) 2013 Google Inc. All rights reserved.
|
| +#
|
| +# Redistribution and use in source and binary forms, with or without
|
| +# modification, are permitted provided that the following conditions are
|
| +# met:
|
| +#
|
| +# * Redistributions of source code must retain the above copyright
|
| +# notice, this list of conditions and the following disclaimer.
|
| +# * Redistributions in binary form must reproduce the above
|
| +# copyright notice, this list of conditions and the following disclaimer
|
| +# in the documentation and/or other materials provided with the
|
| +# distribution.
|
| +# * Neither the name of Google Inc. nor the names of its
|
| +# contributors may be used to endorse or promote products derived from
|
| +# this software without specific prior written permission.
|
| +#
|
| +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +"""Parser for Blink IDL
|
| +
|
| +The parser uses the PLY (Python Lex-Yacc) library to build a set of parsing
|
| +rules which understand the Blink dialect of Web IDL.
|
| +It derives from a standard Web IDL parser, overriding the rules where Blink
|
| +IDL differs.
|
| +
|
| +Web IDL:
|
| + http://www.w3.org/TR/WebIDL/
|
| +Web IDL Grammar:
|
| + http://www.w3.org/TR/WebIDL/#idl-grammar
|
| +PLY:
|
| + http://www.dabeaz.com/ply/
|
| +"""
|
| +
|
| +# Disable check for line length and Member as Function due to how grammar rules
|
| +# are defined with PLY
|
| +#
|
| +# pylint: disable=R0201
|
| +# pylint: disable=C0301
|
| +#
|
| +# Disable attribute validation, as lint can't import parent class to check
|
| +# pylint: disable=E1101
|
| +
|
| +import os.path
|
| +import sys
|
| +
|
| +# PLY is in Chromium src/third_party/ply
|
| +module_path, module_name = os.path.split(__file__)
|
| +third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir)
|
| +sys.path.append(third_party)
|
| +from ply import yacc
|
| +
|
| +# Base parser is in Chromium src/tools/idl_parser
|
| +tools_dir = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir, 'tools')
|
| +sys.path.append(tools_dir)
|
| +from idl_parser.idl_parser import IDLParser, ListFromConcat
|
| +
|
| +from blink_idl_lexer import BlinkIDLLexer
|
| +
|
| +
|
| +REMOVED_RULES = ['Comments', # [0.1]
|
| + 'CommentsRest', # [0.2]
|
| + 'AttributeOrOperation', # [30]
|
| + 'StringifierAttributeOrOperation', # [31]
|
| + 'Operation', # [35]
|
| + 'Qualifiers', # [36]
|
| + ]
|
| +
|
| +
|
| +class BlinkIDLParser(IDLParser):
|
| + # Numbering scheme is:
|
| + # [1] for Web IDL spec (or base Pepper IDL)
|
| + # [b1] for Blink IDL (overrides Web IDL or inserts rule)
|
| + # [s1] is for numbering Sakamoto
|
| +
|
| + # [0] Override Pepper definition, since we strip comments
|
| + def p_Top(self, p):
|
| + """Top : Definitions"""
|
| + p[0] = p[1]
|
| +
|
| + # [3] Override Pepper action, since we distinguish callbacks
|
| + def p_CallbackOrInterface(self, p):
|
| + """CallbackOrInterface : CALLBACK CallbackRestOrInterface
|
| + | Interface"""
|
| + if len(p) > 2:
|
| + p[2].AddChildren(self.BuildTrue('Callback'))
|
| + p[0] = p[2]
|
| + else:
|
| + p[0] = p[1]
|
| +
|
| + # [b10]
|
| + def p_InterfaceMember(self, p):
|
| + """InterfaceMember : Const
|
| + | AttributeOrOperationOrIterator"""
|
| + # Standard is (no 'OrIterator'):
|
| + # InterfaceMember : Const
|
| + # | AttributeOrOperation
|
| + p[0] = p[1]
|
| +
|
| + # [b19]
|
| + # List needed for multiple inheritance in SVG
|
| + # FIXME: remove when multiple inheritance (which is deprecated) is removed
|
| + def p_Inheritance(self, p):
|
| + """Inheritance : ':' ScopedNameList
|
| + |"""
|
| + # Standard is (single identifier, not list):
|
| + # """Inheritance : ':' identifier
|
| + # |"""
|
| + if len(p) > 1:
|
| + p[0] = self.BuildProduction('MultipleInherit', p, 2, p[2])
|
| +
|
| + # [b27]
|
| + def p_ConstValue(self, p):
|
| + """ConstValue : BooleanLiteral
|
| + | FloatLiteral
|
| + | IntegerLiteral
|
| + | StringLiteral
|
| + | null"""
|
| + # Standard is (no 'string', fewer 'Literals'):
|
| + # ConstValue : BooleanLiteral
|
| + # | FloatLiteral
|
| + # | integer
|
| + # | NULL
|
| + p[0] = p[1]
|
| +
|
| + # [b27.1]
|
| + def p_IntegerLiteral(self, p):
|
| + """IntegerLiteral : integer"""
|
| + p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'),
|
| + self.BuildAttribute('NAME', p[1]))
|
| +
|
| + # [b27.2]
|
| + def p_StringLiteral(self, p):
|
| + """StringLiteral : string"""
|
| + p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'DOMString'),
|
| + self.BuildAttribute('NAME', p[1]))
|
| +
|
| + # [b30]
|
| + # Replaces [30] AttributeOrOperation
|
| + def p_AttributeOrOperationOrIterator(self, p):
|
| + """AttributeOrOperationOrIterator : Serializer
|
| + | Qualifier AttributeOrOperationRest
|
| + | Attribute
|
| + | OperationOrIterator"""
|
| + # Standard is:
|
| + # AttributeOrOperation : "stringifier" StringifierAttributeOrOperation
|
| + # | Attribute
|
| + # | Operation
|
| + if len(p) > 2:
|
| + p[2].AddChildren(p[1])
|
| + p[0] = p[2]
|
| + else:
|
| + p[0] = p[1]
|
| +
|
| + # Serialization
|
| + # FIXME: can we remove??
|
| + # [s31]
|
| + def p_Serializer(self, p):
|
| + """Serializer : SERIALIZER SerializerRest"""
|
| + p[0] = p[1]
|
| +
|
| + # [s32]
|
| + def p_SerializerRest(self, p):
|
| + """SerializerRest : OperationRest
|
| + | '=' SerializationPattern
|
| + |"""
|
| + if len(p) > 2:
|
| + p[0] = p[2]
|
| + elif len(p) == 2:
|
| + p[0] = p[1]
|
| +
|
| + # [s33]
|
| + def p_SerializationPattern(self, p):
|
| + """SerializationPattern : '{' SerializationPatternMap '}'
|
| + | '[' SerializationPatternList ']'
|
| + | identifier"""
|
| + if len(p) == 4:
|
| + p[0] = p[2]
|
| + else:
|
| + p[0] = p[1]
|
| +
|
| + # [s34]
|
| + def p_SerializationPatternMap(self, p):
|
| + """SerializationPatternMap : GETTER
|
| + | INHERIT Identifiers
|
| + | identifier Identifiers
|
| + |"""
|
| + if len(p) > 1:
|
| + p[0] = p[1]
|
| +
|
| + # [s35]
|
| + def p_SerializationPatternList(self, p):
|
| + """SerializationPatternList : GETTER
|
| + | identifier Identifiers
|
| + |"""
|
| + if len(p) > 1:
|
| + p[0] = p[1]
|
| +
|
| + # [s36]
|
| + def p_Identifiers(self, p):
|
| + """Identifiers : ',' identifier Identifiers
|
| + |"""
|
| + if len(p) > 1:
|
| + p[0] = p[2]
|
| +
|
| + # Iterator and SpecialOperation
|
| + # Follows [35] Operation
|
| + # [b35.1]
|
| + def p_OperationOrIterator(self, p):
|
| + """OperationOrIterator : ReturnType OperationOrIteratorRest
|
| + | SpecialOperation"""
|
| + if len(p) > 2:
|
| + p[0] = self.BuildProduction('OperationOrIterator', p, 2, ListFromConcat(p[1], p[2]))
|
| + else:
|
| + p[0] = p[1]
|
| +
|
| + # [b35.2]
|
| + def p_OperationOrIteratorRest(self, p):
|
| + """OperationOrIteratorRest : IteratorRest
|
| + | OperationRest"""
|
| + p[0] = p[1]
|
| +
|
| + # [b35.3]
|
| + def p_IteratorRest(self, p):
|
| + """IteratorRest : ITERATOR OptionalIteratorInterfaceOrObject ';'"""
|
| + p[0] = p[2]
|
| +
|
| + # [b35.4]
|
| + def p_OptionalIteratorInterfaceOrObject(self, p):
|
| + """OptionalIteratorInterfaceOrObject : OptionalIteratorInterface
|
| + | OBJECT"""
|
| + p[0] = p[1]
|
| +
|
| + # [b35.5]
|
| + def p_OptionalIteratorInterface(self, p):
|
| + """OptionalIteratorInterface : '=' identifier
|
| + |"""
|
| + if len(p) > 2:
|
| + p[0] = p[2]
|
| +
|
| + # [b35.6]
|
| + def p_SpecialOperation(self, p):
|
| + """SpecialOperation : Special Specials ReturnType OperationRest"""
|
| + specials = ListFromConcat(p[1], p[2])
|
| + p[4].AddChildren(p[3])
|
| + p[0] = p[4]
|
| + p[0].AddChildren(specials)
|
| +
|
| + # Follows [36] Qualifiers
|
| + # [b36.1] [s37]
|
| + def p_Qualifier(self, p):
|
| + """Qualifier : STATIC
|
| + | STRINGIFIER"""
|
| + if p[1] == 'static':
|
| + p[0] = self.BuildTrue('STATIC')
|
| + elif p[1] == 'stringifier':
|
| + p[0] = self.BuildTrue('STRINGIFIER')
|
| +
|
| + # [b39]
|
| + def p_OperationRest(self, p):
|
| + """OperationRest : OptionalIdentifier '(' ArgumentList ')' Raises ';'"""
|
| + # Standard is:
|
| + # OperationRest : ReturnType OptionalIdentifier '(' ArgumentList ')' ';'
|
| + arguments = self.BuildProduction('Arguments', p, 2, p[3])
|
| + p[0] = self.BuildNamed('Operation', p, 1, arguments)
|
| +
|
| + # [b39.1]
|
| + def p_Raises(self, p):
|
| + """Raises : RAISES ExceptionList
|
| + |"""
|
| + if len(p) > 2:
|
| + p[0] = p[2]
|
| +
|
| + # [s39.2]
|
| + def p_ExceptionList(self, p):
|
| + """ExceptionList : '(' ScopedNameList ')'"""
|
| + p[0] = p[2]
|
| +
|
| + # [b39.3]
|
| + def p_AttributeOrOperationRest(self, p):
|
| + """AttributeOrOperationRest : AttributeRest
|
| + | ReturnType OperationRest
|
| + | ';'"""
|
| + if len(p) > 2:
|
| + p[2].AddChildren(p[1])
|
| + p[0] = p[2]
|
| + elif len(p) == 2 and p[1] != ';':
|
| + p[0] = p[1]
|
| +
|
| + # [b39.2]
|
| + def p_AttributeRest(self, p):
|
| + """AttributeRest : ReadOnly ATTRIBUTE Type identifier Get ';'"""
|
| + p[0] = self.BuildNamed('Attribute', p, 4, ListFromConcat(p[1], p[3], p[5]))
|
| +
|
| + # [b39.3]
|
| + def p_Get(self, p):
|
| + """Get : InheritsGetter SetRaises
|
| + | SetGetRaises
|
| + |"""
|
| + if len(p) > 2:
|
| + p[0] = p[2]
|
| + elif len(p) == 2:
|
| + p[0] = p[1]
|
| +
|
| + # [s39.4]
|
| + def p_InheritsGetter(self, p):
|
| + """InheritsGetter : INHERITS GETTER"""
|
| + pass
|
| +
|
| + # [b47]
|
| + def p_ExceptionMember(self, p):
|
| + """ExceptionMember : Const
|
| + | ExceptionField
|
| + | Attribute
|
| + | ExceptionFieldToString"""
|
| + # Standard is:
|
| + # ExceptionMember : Const
|
| + # | ExceptionField
|
| + p[0] = p[1]
|
| +
|
| + # [b47.1]
|
| + def p_ExceptionFieldToString(self, p):
|
| + """ExceptionFieldToString : Type identifier '(' ')' ';'"""
|
| + # Needed to handle:
|
| + # // Override in a Mozilla compatible format
|
| + # [NotEnumerable] DOMString toString();
|
| + p[0] = self.BuildNamed('ExceptionFieldToString', p, 2, p[1])
|
| +
|
| + # Extended attributes
|
| + # [b49] Override Pepper: remove comment field, since comments stripped
|
| + # FIXME: Upstream
|
| + def p_ExtendedAttributeList(self, p):
|
| + """ExtendedAttributeList : '[' ExtendedAttribute ExtendedAttributes ']'
|
| + | '[' ']'
|
| + | """
|
| + if len(p) > 3:
|
| + items = ListFromConcat(p[2], p[3])
|
| + attribs = self.BuildProduction('ExtAttributes', p, 1, items)
|
| + p[0] = ListFromConcat(p[0], attribs)
|
| +
|
| + # [b50] Allow optional trailing comma
|
| + def p_ExtendedAttributes(self, p):
|
| + """ExtendedAttributes : ',' ExtendedAttribute ExtendedAttributes
|
| + | ','
|
| + |"""
|
| + if len(p) > 2:
|
| + p[0] = ListFromConcat(p[2], p[3])
|
| +
|
| + # [b51] Add ExtendedAttributeIdentOrIdent and ExtendedAttributeIdentAndIdent
|
| + def p_ExtendedAttribute(self, p):
|
| + """ExtendedAttribute : ExtendedAttributeNoArgs
|
| + | ExtendedAttributeArgList
|
| + | ExtendedAttributeIdent
|
| + | ExtendedAttributeIdentOrIdent
|
| + | ExtendedAttributeIdentAndIdent
|
| + | ExtendedAttributeNamedArgList"""
|
| + p[0] = p[1]
|
| +
|
| + # FIXME: Upstream UnionType
|
| + # [59]
|
| + def p_UnionType(self, p):
|
| + """UnionType : '(' UnionMemberType OR UnionMemberType UnionMemberTypes ')'"""
|
| + members = ListFromConcat(p[2], p[4], p[5])
|
| + p[0] = self.BuildProduction('UnionType', p, 1, members)
|
| +
|
| + # [60]
|
| + def p_UnionMemberType(self, p):
|
| + """UnionMemberType : NonAnyType
|
| + | UnionType TypeSuffix
|
| + | ANY '[' ']' TypeSuffix"""
|
| + if len(p) == 2:
|
| + p[0] = p[1]
|
| + elif len(p) == 3:
|
| + p[0] = ListFromConcat(p[1], p[2])
|
| + else:
|
| + p[0] = ListFromConcat(self.BuildProduction('Any', p, 1), p[4])
|
| +
|
| + # [61]
|
| + def p_UnionMemberTypes(self, p):
|
| + """UnionMemberTypes : OR UnionMemberType UnionMemberTypes
|
| + |"""
|
| + if len(p) > 1:
|
| + p[0] = ListFromConcat(p[2], p[3])
|
| +
|
| + # [70] Override Pepper to remove non-standard sized array
|
| + # FIXME: upstream should remove sized array from base
|
| + def p_TypeSuffix(self, p):
|
| + """TypeSuffix : '[' ']' TypeSuffix
|
| + | '?' TypeSuffixStartingWithArray
|
| + |"""
|
| + if len(p) == 4:
|
| + p[0] = self.BuildProduction('Array', p, 1, p[3])
|
| +
|
| + if len(p) == 3:
|
| + p[0] = ListFromConcat(self.BuildTrue('NULLABLE'), p[2])
|
| +
|
| + # [b76.1]
|
| + def p_ExtendedAttributeIdentOrIdent(self, p):
|
| + """ExtendedAttributeIdentOrIdent : identifier '=' identifier '|' identifier"""
|
| + # Used in a handful of files
|
| + value = self.BuildAttribute('VALUE', p[3] + '|' + p[5])
|
| + p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
|
| +
|
| + # [b76.2]
|
| + def p_ExtendedAttributeIdentAndIdent(self, p):
|
| + """ExtendedAttributeIdentAndIdent : identifier '=' identifier '&' identifier"""
|
| + # FIXME: Used only in NavigatorContentUtils.idl,
|
| + # which doesn't appear to be parsed - remove?
|
| + value = self.BuildAttribute('VALUE', p[3] + '&' + p[5])
|
| + p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
|
| +
|
| + # Exceptions
|
| + # [s25]
|
| + def p_SetGetRaises(self, p):
|
| + """SetGetRaises : SetRaises GetRaises2
|
| + | GetRaises
|
| + | SetGetRaises2"""
|
| + p[0] = p[1]
|
| +
|
| + # [s27]
|
| + def p_GetRaises(self, p):
|
| + """GetRaises : GETTER RAISES ExceptionList"""
|
| + p[0] = p[3]
|
| +
|
| + # [s27.5]
|
| + def p_GetRaises2(self, p):
|
| + """GetRaises2 : ',' GETTER RAISES ExceptionList
|
| + |"""
|
| + p[0] = p[4]
|
| +
|
| + # [s28]
|
| + def p_SetRaises(self, p):
|
| + """SetRaises : SETTER RAISES ExceptionList"""
|
| + p[0] = p[3]
|
| +
|
| + # [s29]
|
| + def p_SetGetRaises2(self, p):
|
| + """SetGetRaises2 : GetRaises3 SetRaises3"""
|
| + # FIXME
|
| + p[0] = p[1]
|
| +
|
| + # [s29a]
|
| + def p_GetRaises3(self, p):
|
| + """GetRaises3 : GETRAISES ExceptionList
|
| + |"""
|
| + p[0] = p[2]
|
| +
|
| + # [s29b]
|
| + def p_SetRaises3(self, p):
|
| + """SetRaises3 : SETRAISES ExceptionList
|
| + |"""
|
| + p[0] = p[2]
|
| +
|
| + # Scoped names
|
| + # FIXME: remove??
|
| + # [s63]
|
| + def p_ScopedNameList(self, p):
|
| + """ScopedNameList : ScopedName ScopedNames"""
|
| + scoped_name = self.BuildNamed('ScopedName', p, 1)
|
| + p[0] = ListFromConcat(scoped_name, p[2])
|
| +
|
| + # [s64]
|
| + def p_ScopedNames(self, p):
|
| + """ScopedNames : ',' ScopedName ScopedNames
|
| + |"""
|
| + if len(p) > 1:
|
| + scoped_name = self.BuildNamed('ScopedName', p, 2)
|
| + p[0] = ListFromConcat(scoped_name, p[3])
|
| +
|
| + # [s65]
|
| + def p_ScopedName(self, p):
|
| + """ScopedName : AbsoluteScopedName
|
| + | RelativeScopedName"""
|
| + p[0] = p[1]
|
| +
|
| + # [s66]
|
| + def p_AbsoluteScopedName(self, p):
|
| + """AbsoluteScopedName : SCOPE_RESOLUTION identifier ScopedNameParts"""
|
| + p[0] = p[2]
|
| +
|
| + # [s67]
|
| + def p_RelativeScopedName(self, p):
|
| + """RelativeScopedName : identifier ScopedNameParts"""
|
| + p[0] = p[1]
|
| +
|
| + # [s68]
|
| + def p_ScopedNameParts(self, p):
|
| + """ScopedNameParts : SCOPE_RESOLUTION identifier ScopedNameParts
|
| + |"""
|
| + # if len(p) > 1:
|
| + # p[0] = p[2]
|
| + pass
|
| +
|
| + def __dir__(self):
|
| + # Remove rules from listing so yacc doesn't parse them
|
| + keys = set(self.__dict__.keys() + dir(self.__class__))
|
| + for rule in REMOVED_RULES:
|
| + keys.remove('p_' + rule)
|
| + return list(keys)
|
| +
|
| + def __init__(self, lexer, verbose=False, debug=False, mute_error=False):
|
| + self.lexer = lexer
|
| + self.tokens = lexer.KnownTokens()
|
| + # SLR yields faster table generation (same output), ok b/c LL(1) grammar
|
| + self.yaccobj = yacc.yacc(module=self, debug=debug, method='SLR')
|
| + # Optimized mode, improves startup time of yacc compiler
|
| + # optimize=1
|
| + # Turn on table generation with:
|
| + # write_tables=1
|
| + # Turn off table generation with:
|
| + # tabmodule=None, write_tables=0
|
| + self.parse_debug = debug
|
| + self.verbose = verbose
|
| + self.mute_error = mute_error
|
| + self._parse_errors = 0
|
| + self._parse_warnings = 0
|
| + self._last_error_msg = None
|
| + self._last_error_lineno = 0
|
| + self._last_error_pos = 0
|
| +
|
| +
|
| +# If run by itself, attempt to build the parser
|
| +if __name__ == '__main__':
|
| + parser = BlinkIDLParser(BlinkIDLLexer())
|
|
|