lib/webidl/parser/idl.treetop
# -*- coding: utf-8 -*-
module WebIDL
module Parser
# http://dev.w3.org/2006/webapi/WebIDL/#idl-grammar
grammar IDL
rule Definitions
ws metadef:(eal:ExtendedAttributeList ws d:Definition ws defs:Definitions)? ws <ParseTree::Definitions>
end
rule Definition
CallbackOrInterface
/ Interface
/ Partial
/ Dictionary
/ Exception
/ Enum
/ TypeDef
/ IncludesStatement
/ ImplementsStatement
end
rule CallbackOrInterface
"callback" ws obj:CallbackRestOrInterface { def build(parent) obj.build(parent) end }
end
rule CallbackRestOrInterface
CallbackRest / Interface
end
rule Interface
"interface" ws (mixin:"mixin" ws)? name:identifier ws inherits:Inheritance ws "{" ws members:InterfaceMembers ws "}" ws ";" <ParseTree::Interface>
end
rule Partial
"partial" ws defn:PartialDefinition { def build(parent) defn.build(parent) end }
end
rule PartialDefinition
PartialInterface / PartialDictionary
end
# like an interface, but no inheritance
rule PartialInterface
"interface" ws name:identifier ws "{" ws members:InterfaceMembers ws "}" ws ";" <ParseTree::PartialInterface>
end
rule Inheritance
(":" ws names:ScopedNameList <ParseTree::Inheritance>)?
end
# extract to a generic Members syntax node?
rule InterfaceMembers
(eal:ExtendedAttributeList ws member:InterfaceMember ws members:InterfaceMembers ws <ParseTree::InterfaceMembers>)?
end
rule InterfaceMember
Const / AttributeOrOperation
end
# Dictionary → "dictionary" identifier Inheritance "{" DictionaryMembers "}" ";"
rule Dictionary
"dictionary" ws name:identifier ws inherits:Inheritance ws "{" ws members:DictionaryMembers ws "}" ws ";" <ParseTree::Dictionary>
end
# Like a dictionary, but no inheritance
rule PartialDictionary
"dictionary" ws name:identifier ws "{" ws members:DictionaryMembers ws "}" ws ";" <ParseTree::PartialDictionary>
end
# [11] DictionaryMembers → ExtendedAttributeList DictionaryMember DictionaryMembers
# | ε
rule DictionaryMembers
(eal:ExtendedAttributeList ws member:DictionaryMember ws members:DictionaryMembers <ParseTree::DictionaryMembers>)?
end
rule Required
"required"
end
rule DictionaryMember
required:Required? ws type:Type ws name:identifier ws default:Default ws ";" <ParseTree::DictionaryMember>
end
rule Default
("=" ws val:DefaultValue { def build() val.build end })?
end
rule DefaultValue
string / ConstValue
end
rule Exception
"exception" ws name:identifier ws inherits:Inheritance ws "{" ws members:ExceptionMembers ws "}" ws ";" <ParseTree::Exception>
end
# extract to a generic Members syntax node?
rule ExceptionMembers
(eal:ExtendedAttributeList ws member:ExceptionMember ws members:ExceptionMembers ws <ParseTree::InterfaceMembers>)?
end
rule CallbackRest
name:identifier ws "=" ws return_type:ReturnType ws "(" ws args:ArgumentList ")" ws ";" <ParseTree::Callback>
end
rule TypeDef
"typedef" ws type:Type ws name:identifier ws ";" <ParseTree::TypeDef>
end
rule ImplementsStatement
implementor:ScopedName ws "implements" ws implementee:ScopedName ws ";" <ParseTree::ImplementsStatement>
end
rule IncludesStatement
includer:ScopedName ws "includes" ws includee:ScopedName ws ";" <ParseTree::IncludesStatement>
end
rule Const
"const" ws type:Type ws name:identifier ws "=" ws const_expr:ConstValue ws ";" <ParseTree::Const>
end
rule ConstValue
"null" { def build() nil end }
/ BooleanLiteral
/ FloatLiteral
/ integer
end
rule BooleanLiteral
("true" / "false") { def build() text_value == "true" end }
end
rule FloatLiteral
float
/ "-" "Infinity" { def build() -1.0/0 end }
/ "Infinity" { def build() 1.0/0 end }
/ "NaN" { def build() Float::NAN end }
end
rule Enum
"enum" ws id:identifier ws "{" ws values:EnumValueList ws "}" ws ";" <ParseTree::Enum>
end
rule EnumValueList
name:string ws
vals:EnumValues
ws ","? # trailing commas actually not allowed, but in use
{
def build()
res = [name.build]
res += vals.build if vals.any?
res
end
}
end
rule EnumValues
("," ws name:string ws vals:EnumValues {
def build()
res = [name.build]
res += vals.build if vals.any?
res
end
})?
end
rule AttributeOrOperation
StringifierAttributeOrOperation / Attribute / Operation
end
rule StringifierAttributeOrOperation
"stringifier" ws a_or_op:(Attribute / OperationRest / ";") <ParseTree::StringifierAttributeOrOperation>
end
rule Attribute
readonly:ReadOnly ws "attribute" ws type:Type ws name:identifier ws getraises:GetRaises ws setraises:SetRaises ws ";" <ParseTree::Attribute>
end
rule ReadOnly
"readonly"?
end
rule GetRaises
("getraises" ws list:ExceptionList)?
end
rule SetRaises
("setraises" ws list:ExceptionList)?
end
rule Operation
static:"static"? specials:(OmittableSpecials / Specials) ws op:OperationRest <ParseTree::Operation>
end
rule OmittableSpecials
omit:"omittable" ws Specials <ParseTree::OmittableSpecials>
end
rule Specials
(first:Special ws rest:Specials <ParseTree::Specials>)?
end
rule Special
"getter"
/ "setter"
/ "creator"
/ "deleter"
/ "legacycaller"
end
rule OperationRest
type:ReturnType ws optional_id:OptionalIdentifier ws "(" ws args:ArgumentList ws ")" ws raises:Raises ws ";" <ParseTree::Operation>
end
rule OptionalIdentifier
identifier?
end
rule Raises
("raises" ExceptionList)?
end
rule ExceptionList
"(" ScopedNameList ")"
end
rule ArgumentList
(arg:Argument ws args:Arguments <ParseTree::ArgumentList>)?
end
rule Arguments
("," ws arg:Argument ws args:Arguments <ParseTree::ArgumentList>)?
end
rule Argument
eal:ExtendedAttributeList ws "in"? ws arg:OptionalOrRequiredArgument <ParseTree::Argument>
end
rule OptionalOrRequiredArgument
optional:"optional" ws type:Type ws name:ArgumentName ws default:Default
/ type:Type ws variadic:Ellipsis ws name:ArgumentName
end
rule ArgumentName
ArgumentNameKeyword { def build() text_value end } / identifier
end
rule ArgumentNameKeyword
"attribute"
/ "callback"
/ "const"
/ "creator"
/ "deleter"
/ "dictionary"
/ "enum"
/ "exception"
/ "getter"
/ "implements"
/ "includes"
/ "inherit"
/ "interface"
/ "legacycaller"
/ "partial"
/ "setter"
/ "static"
/ "stringifier"
/ "typedef"
/ "unrestricted"
end
rule Ellipsis
"..."?
end
rule ExceptionMember
Const / ExceptionField
end
rule ExceptionField
type:Type ws id:identifier ws ";" <ParseTree::ExceptionField>
end
rule ExtendedAttributeList
("[" ws attribute:ExtendedAttribute ws attributes:ExtendedAttributes ws "]" <ParseTree::ExtendedAttributeList>)?
end
rule ExtendedAttributes
("," ws attribute:ExtendedAttribute ws attributes:ExtendedAttributes <ParseTree::ExtendedAttributeList>)?
end
#
# avoid infinite recursion trouble with the actual spec by using the "more restricted" ones
#
rule ExtendedAttribute
ExtendedAttributeNamedArgList
/ ExtendedAttributeIdent
/ ExtendedAttributeScopedName
/ ExtendedAttributeArgList
/ ExtendedAttributeIdentList
/ ExtendedAttributeNoArg
end
rule ExtendedAttributeNoArg
identifier {
def build(parent)
Ast::ExtendedAttribute.new(text_value)
end
}
end
rule ExtendedAttributeArgList
name:identifier "(" ws args:ArgumentList ws ")" <ParseTree::ExtendedAttributeArgList>
end
rule ExtendedAttributeScopedName
key:identifier "=" scoped_name:ScopedName <ParseTree::ExtendedAttributeScopedName>
end
rule ExtendedAttributeIdent
key:identifier "=" value:identifier !"::" <ParseTree::ExtendedAttributeIdent>
end
rule ExtendedAttributeNamedArgList
key:identifier "=" value:(name:identifier "(" ws args:ArgumentList ws ")" <ParseTree::ExtendedAttributeArgList>) <ParseTree::ExtendedAttributeNamedArgList>
end
rule ExtendedAttributeIdentList
key:identifier "=" "(" list:IdentifierList ")" <ParseTree::ExtendedAttributeIdentList>
end
rule IdentifierList
identifier Identifiers
end
rule Identifiers
("," ws IdentifierList)?
end
# rule ExtendedAttribute
# "(" ws ExtendedAttributeInner ws ")" ws ExtendedAttributeRest
# / "[" ws ExtendedAttributeInner ws "]" ws ExtendedAttributeRest
# / "{" ws ExtendedAttributeInner ws "}" ws ExtendedAttributeRest
# / Other ws ExtendedAttributeRest
# end
#
# rule ExtendedAttributeRest
# ExtendedAttribute?
# end
#
# rule ExtendedAttributeInner
# ( "(" ws ExtendedAttributeInner ws ")" ws ExtendedAttributeInner
# / "[" ws ExtendedAttributeInner ws "]" ws ExtendedAttributeInner
# / "{" ws ExtendedAttributeInner ws "}" ws ExtendedAttributeInner
# / OtherOrComma ExtendedAttributeInner)?
# end
#
rule Other
integer
/ float
/ identifier
/ string
/ other
/ "..."
/ ":"
/ "::"
/ ";"
/ "<"
/ "="
/ ">"
/ "?"
/ "false"
/ "object"
/ "true"
/ "any"
/ "attribute"
/ "boolean"
/ "caller"
/ "const"
/ "creator"
/ "deleter"
/ "double"
/ "exception"
/ "float"
/ "getraises"
/ "getter"
/ "implements"
/ "includes"
/ "in"
/ "interface"
/ "long"
/ "module"
/ "octet"
/ "omittable"
/ "optional"
/ "raises"
/ "sequence"
/ "setraises"
/ "setter"
/ "short"
/ "DOMString"
/ "stringifier"
/ "typedef"
/ "unsigned"
/ "void"
end
rule OtherOrComma
Other / ","
end
rule Type
SingleType
/ type:UnionType suffix:TypeSuffix <ParseTree::Type>
end
rule SingleType
NonAnyType
/ type:"any" suffix:TypeSuffixStartingWithArray <ParseTree::Type>
end
rule UnionType
"(" ws UnionMemberType ws "or" ws UnionMemberType ws UnionMemberTypes ws ")"
end
rule UnionMemberType
NonAnyType
/ type:UnionType suffix:TypeSuffix <ParseTree::Type>
/ type:"any" suffix:TypeSuffixStartingWithArray <ParseTree::Type>
end
rule UnionMemberTypes
("or" ws UnionMemberType ws UnionMemberTypes)?
end
rule NonAnyType
type:PrimitiveType suffix:TypeSuffix <ParseTree::Type>
# added: cannot be followed by a NonSpace character, since e.g. DOMStringMap, DOMStringList or other identifiers would break parsing
/ type:PromiseType Null { def build(parent); type.build(parent); end }
/ type:"DOMString" suffix:TypeSuffix !NonSpace <ParseTree::Type>
/ "sequence" ws "<" ws type:Type ws ">" null:Null <ParseTree::SequenceType>
/ type:"object" suffix:TypeSuffix <ParseTree::Type>
/ type:"Date" suffix:TypeSuffix <ParseTree::Type>
/ type:identifier suffix:TypeSuffix <ParseTree::Type>
end
rule PromiseType
"Promise" ws "<" ws return_type:ReturnType ws ">" {
def build(parent)
Ast::PromiseType.new(return_type.text_value)
end
}
end
rule ConstType
PrimitiveType Null
/ identifier Null
end
# added: cannot be followed by a NonSpace character, since e.g. DOMStringMap, DOMStringList or other identifiers would break parsing
rule PrimitiveType
(UnsignedIntegerType
/ UnrestrictedFloatType
/ "boolean" !NonSpace
/ "byte" !NonSpace
/ "octet" !NonSpace) {
def build(parent)
Ast::Type.new(parent, text_value)
end
}
end
rule Null
"?"?
end
rule TypeSuffix
(
array:("[" ws "]") suffix:TypeSuffix <ParseTree::TypeSuffix>
/ null:"?" suffix:TypeSuffixStartingWithArray <ParseTree::TypeSuffix>
)?
end
rule TypeSuffixStartingWithArray
(array:("[" ws "]") ws suffix:TypeSuffix <ParseTree::TypeSuffix>)?
end
rule UnsignedIntegerType
"unsigned" ws IntegerType / IntegerType
end
rule UnrestrictedFloatType
"unrestricted" ws FloatType
/ FloatType
end
rule FloatType
"float" / "double"
end
rule IntegerType
("short" / "long" ws OptionalLong)
end
rule OptionalLong
"long"?
end
rule Array
("[" ws "]")?
end
rule NonSpace
(!' ' .)
end
rule ReturnType
Type / "void" <ParseTree::VoidType>
end
rule ScopedNameList
name:ScopedName ws names:ScopedNames <ParseTree::ScopedNameList>
end
rule ScopedNames
("," ScopedName ws ScopedNames)?
end
rule ScopedName
AbsoluteScopedName / RelativeScopedName
end
rule AbsoluteScopedName
"::" name:identifier parts:ScopedNameParts <ParseTree::AbsoluteScopedName>
end
rule RelativeScopedName
name:identifier parts:ScopedNameParts <ParseTree::RelativeScopedName>
end
rule ScopedNameParts
("::" ws name:identifier parts:ScopedNameParts)?
end
rule integer
(hexint / octint / decint) { def build() Integer(text_value) end} # TODO: check edge cases
end
rule hexint
"-"? "0" [Xx] [0-9A-Fa-f]+
end
rule octint
"-"? "0" [0-7]+
end
rule decint
"-"? [0-9]*
end
rule float
("-"? ([0-9]+ "." [0-9]* / [0-9]* "." [0-9]+) ([Ee] [+-]? [0-9]+)? / [0-9]+ [Ee] [+-]? [0-9]+) { def build() Float(text_value) end} # TODO: check edge cases
end
rule identifier
[A-Z_a-z] [0-9A-Z_a-z]* { def build(parent = nil) text_value[/^_?(.+)/, 1] end }
end
rule string
# spec only allows double quotes, but single quotes are used in the HTML spec
double_quoted_string / single_quoted_string
end
rule double_quoted_string
"\"" data:[^"]* "\"" { def build() data.text_value end }
end
rule single_quoted_string
"'" data:[^']* "'" { def build() data.text_value end }
end
rule ws
([\t\n\r ]* ((line_comment / block_comment) [\t\n\r ]*)+ / [\t\n\r ]+)?
end
rule other
[^\t\n\r 0-9A-Z_a-z]
end
rule line_comment
"//" (![\n\r] . )*
end
rule block_comment
'/*' (!'*/' . )* '*/'
end
end # IDL
end # Parser
end # WebIDL