blob: 19fb6495c31b1fb56d7e6a9f150db95982c74712 [file] [log] [blame]
#
# KDOM IDL parser
#
# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this library; see the file COPYING.LIB. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
#
package IDLParser;
use Class::Struct;
use strict;
use IPC::Open2;
use IDLStructure;
use preprocessor;
use constant StringToken => 0;
use constant IntegerToken => 1;
use constant FloatToken => 2;
use constant IdentifierToken => 3;
use constant OtherToken => 4;
use constant EmptyToken => 5;
struct( Token => {
type => '$', # type of token
value => '$' # value of token
});
sub new {
my $class = shift;
my $emptyToken = Token->new();
$emptyToken->type(EmptyToken);
$emptyToken->value("empty");
my $self = {
DocumentContent => "",
EmptyToken => $emptyToken,
NextToken => $emptyToken,
Token => $emptyToken,
Line => "",
LineNumber => 1
};
return bless $self, $class;
}
sub assertTokenValue
{
my $self = shift;
my $token = shift;
my $value = shift;
my $line = shift;
my $msg = "Next token should be " . $value . ", but " . $token->value() . " at " . $self->{Line};
if (defined ($line)) {
$msg .= " IDLParser.pm:" . $line;
}
die $msg unless $token->value() eq $value;
}
sub assertTokenType
{
my $self = shift;
my $token = shift;
my $type = shift;
die "Next token's type should be " . $type . ", but " . $token->type() . " at " . $self->{Line} unless $token->type() eq $type;
}
sub assertUnexpectedToken
{
my $self = shift;
my $token = shift;
my $line = shift;
my $msg = "Unexpected token " . $token . " at " . $self->{Line};
if (defined ($line)) {
$msg .= " IDLParser.pm:" . $line;
}
die $msg;
}
sub Parse
{
my $self = shift;
my $fileName = shift;
my $defines = shift;
my $preprocessor = shift;
my @definitions = ();
my @lines = applyPreprocessor($fileName, $defines, $preprocessor);
$self->{Line} = $lines[0];
$self->{DocumentContent} = join(' ', @lines);
$self->getToken();
eval {
my $result = $self->parseDefinitions();
push(@definitions, @{$result});
my $next = $self->nextToken();
$self->assertTokenType($next, EmptyToken);
};
die $@ . " in $fileName" if $@;
die "No document found" unless @definitions;
my $document;
if ($#definitions == 0 && ref($definitions[0]) eq "idlDocument") {
$document = $definitions[0];
} else {
$document = new idlDocument();
$document->module("");
push(@{$document->classes}, @definitions);
}
$document->fileName($fileName);
return $document;
}
sub nextToken
{
my $self = shift;
return $self->{NextToken};
}
sub getToken
{
my $self = shift;
$self->{Token} = $self->{NextToken};
$self->{NextToken} = $self->getTokenInternal();
return $self->{Token};
}
my $whitespaceTokenPattern = '^[\t\n\r ]*[\n\r]';
my $floatTokenPattern = '^(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+))';
my $integerTokenPattern = '^(-?[1-9][0-9]*|-?0[Xx][0-9A-Fa-f]+|-?0[0-7]*)';
my $stringTokenPattern = '^(\"[^\"]*\")';
my $identifierTokenPattern = '^([A-Z_a-z][0-9A-Z_a-z]*)';
my $otherTokenPattern = '^(::|\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
sub getTokenInternal
{
my $self = shift;
if ($self->{DocumentContent} =~ /$whitespaceTokenPattern/) {
$self->{DocumentContent} =~ s/($whitespaceTokenPattern)//;
my $skipped = $1;
$self->{LineNumber}++ while ($skipped =~ /\n/g);
if ($self->{DocumentContent} =~ /^([^\n\r]+)/) {
$self->{Line} = $self->{LineNumber} . ":" . $1;
} else {
$self->{Line} = "Unknown";
}
}
$self->{DocumentContent} =~ s/^([\t\n\r ]+)//;
if ($self->{DocumentContent} eq "") {
return $self->{EmptyToken};
}
my $token = Token->new();
if ($self->{DocumentContent} =~ /$floatTokenPattern/) {
$token->type(FloatToken);
$token->value($1);
$self->{DocumentContent} =~ s/$floatTokenPattern//;
return $token;
}
if ($self->{DocumentContent} =~ /$integerTokenPattern/) {
$token->type(IntegerToken);
$token->value($1);
$self->{DocumentContent} =~ s/$integerTokenPattern//;
return $token;
}
if ($self->{DocumentContent} =~ /$stringTokenPattern/) {
$token->type(StringToken);
$token->value($1);
$self->{DocumentContent} =~ s/$stringTokenPattern//;
return $token;
}
if ($self->{DocumentContent} =~ /$identifierTokenPattern/) {
$token->type(IdentifierToken);
$token->value($1);
$self->{DocumentContent} =~ s/$identifierTokenPattern//;
return $token;
}
if ($self->{DocumentContent} =~ /$otherTokenPattern/) {
$token->type(OtherToken);
$token->value($1);
$self->{DocumentContent} =~ s/$otherTokenPattern//;
return $token;
}
die "Failed in tokenizing at " . $self->{Line};
}
my $nextAttributeOld_1 = '^(attribute|inherit|readonly)$';
my $nextPrimitiveType_1 = '^(int|long|short|unsigned)$';
my $nextPrimitiveType_2 = '^(double|float|unrestricted)$';
my $nextSetGetRaises2_1 = '^(;|getraises|setraises)$';
my $nextArgumentList_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|double|float|in|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
my $nextNonAnyType_1 = '^(boolean|byte|double|float|int|long|octet|short|unrestricted|unsigned)$';
my $nextInterfaceMemberOld_1 = '^(\(|::|ByteString|DOMString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|int|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
my $nextOptionalIteratorInterfaceOrObject_1 = '^(;|=)$';
my $nextAttributeOrOperationOrIterator_1 = '^(static|stringifier)$';
my $nextAttributeOrOperationOrIterator_2 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|creator|deleter|double|float|getter|int|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
my $nextUnrestrictedFloatType_1 = '^(double|float)$';
my $nextExtendedAttributeRest3_1 = '^(\,|::|\])$';
my $nextExceptionField_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
my $nextType_1 = '^(::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
my $nextSpecials_1 = '^(creator|deleter|getter|legacycaller|setter)$';
my $nextDefinitions_1 = '^(::|callback|dictionary|enum|exception|interface|partial|typedef)$';
my $nextExceptionMembers_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|const|double|float|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
my $nextAttributeRest_1 = '^(attribute|readonly)$';
my $nextInterfaceMembers_1 = '^(\(|::|ByteString|DOMString|Date|any|attribute|boolean|byte|const|creator|deleter|double|float|getter|inherit|int|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
my $nextSingleType_1 = '^(::|ByteString|DOMString|Date|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
my $nextGet_1 = '^(;|getraises|getter|setraises|setter)$';
my $nextArgumentName_1 = '^(attribute|callback|const|creator|deleter|dictionary|enum|exception|getter|implements|inherit|interface|legacycaller|partial|serializer|setter|static|stringifier|typedef|unrestricted)$';
my $nextConstValue_1 = '^(false|true)$';
my $nextConstValue_2 = '^(-|Infinity|NaN)$';
my $nextDefinition_1 = '^(callback|interface)$';
my $nextAttributeOrOperationRest_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
my $nextUnsignedIntegerType_1 = '^(int|long|short)$';
my $nextDefaultValue_1 = '^(-|Infinity|NaN|false|null|true)$';
sub parseDefinitions
{
my $self = shift;
my @definitions = ();
while (1) {
my $next = $self->nextToken();
my $definition;
if ($next->value() eq "[") {
my $extendedAttributeList = $self->parseExtendedAttributeList();
$definition = $self->parseDefinition($extendedAttributeList);
} elsif ($next->type() == IdentifierToken || $next->value() =~ /$nextDefinitions_1/) {
$definition = $self->parseDefinitionOld();
} else {
last;
}
if (defined ($definition)) {
push(@definitions, $definition);
}
}
return \@definitions;
}
sub parseDefinition
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextDefinition_1/) {
return $self->parseCallbackOrInterface($extendedAttributeList);
}
if ($next->value() eq "partial") {
return $self->parsePartial($extendedAttributeList);
}
if ($next->value() eq "dictionary") {
return $self->parseDictionary($extendedAttributeList);
}
if ($next->value() eq "exception") {
return $self->parseException($extendedAttributeList);
}
if ($next->value() eq "enum") {
return $self->parseEnum($extendedAttributeList);
}
if ($next->value() eq "typedef") {
return $self->parseTypedef($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() eq "::") {
return $self->parseImplementsStatement($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseCallbackOrInterface
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "callback") {
$self->assertTokenValue($self->getToken(), "callback", __LINE__);
return $self->parseCallbackRestOrInterface($extendedAttributeList);
}
if ($next->value() eq "interface") {
return $self->parseInterface($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseCallbackRestOrInterface
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "interface") {
return $self->parseInterface($extendedAttributeList);
}
if ($next->type() == IdentifierToken) {
return $self->parseCallbackRest($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseInterface
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "interface") {
my $dataNode = new domClass();
$self->assertTokenValue($self->getToken(), "interface", __LINE__);
my $interfaceNameToken = $self->getToken();
$self->assertTokenType($interfaceNameToken, IdentifierToken);
$dataNode->name($interfaceNameToken->value());
push(@{$dataNode->parents}, @{$self->parseInheritance()});
$self->assertTokenValue($self->getToken(), "{", __LINE__);
my $interfaceMembers = $self->parseInterfaceMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
applyMemberList($dataNode, $interfaceMembers);
applyExtendedAttributeList($dataNode, $extendedAttributeList);
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parsePartial
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "partial") {
$self->assertTokenValue($self->getToken(), "partial", __LINE__);
return $self->parsePartialDefinition($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parsePartialDefinition
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "interface") {
return $self->parsePartialInterface($extendedAttributeList);
}
if ($next->value() eq "dictionary") {
return $self->parsePartialDictionary($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parsePartialInterface
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "interface") {
$self->assertTokenValue($self->getToken(), "interface", __LINE__);
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseInterfaceMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseInterfaceMembers
{
my $self = shift;
my @interfaceMembers = ();
while (1) {
my $next = $self->nextToken();
my $interfaceMember;
if ($next->value() eq "[") {
my $extendedAttributeList = $self->parseExtendedAttributeList();
$interfaceMember = $self->parseInterfaceMember($extendedAttributeList);
} elsif ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMembers_1/) {
$interfaceMember = $self->parseInterfaceMemberOld();
} else {
last;
}
if (defined $interfaceMember) {
push(@interfaceMembers, $interfaceMember);
}
}
return \@interfaceMembers;
}
sub parseInterfaceMember
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "const") {
return $self->parseConst($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMemberOld_1/) {
return $self->parseAttributeOrOperationOrIterator($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseDictionary
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "dictionary") {
$self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->parseInheritance();
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseDictionaryMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseDictionaryMembers
{
my $self = shift;
while (1) {
my $next = $self->nextToken();
if ($next->value() eq "[") {
my $extendedAttributeList = $self->parseExtendedAttributeList();
$self->parseDictionaryMember($extendedAttributeList);
} elsif ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
$self->parseDictionaryMemberOld();
} else {
last;
}
}
}
sub parseDictionaryMember
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
$self->parseType();
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->parseDefault();
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parsePartialDictionary
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "dictionary") {
$self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseDictionaryMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseDefault
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "=") {
$self->assertTokenValue($self->getToken(), "=", __LINE__);
return $self->parseDefaultValue();
}
}
sub parseDefaultValue
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == FloatToken || $next->type() == IntegerToken || $next->value() =~ /$nextDefaultValue_1/) {
return $self->parseConstValue();
}
if ($next->type() == StringToken) {
return $self->getToken()->value();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseException
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "exception") {
my $dataNode = new domClass();
$self->assertTokenValue($self->getToken(), "exception", __LINE__);
my $exceptionNameToken = $self->getToken();
$self->assertTokenType($exceptionNameToken, IdentifierToken);
$dataNode->name($exceptionNameToken->value());
$dataNode->isException(1);
push(@{$dataNode->parents}, @{$self->parseInheritance()});
$self->assertTokenValue($self->getToken(), "{", __LINE__);
my $exceptionMembers = $self->parseExceptionMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
applyMemberList($dataNode, $exceptionMembers);
applyExtendedAttributeList($dataNode, $extendedAttributeList);
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExceptionMembers
{
my $self = shift;
my @members = ();
while (1) {
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionMembers_1/) {
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
#my $member = $self->parseExceptionMember($extendedAttributeList);
my $member = $self->parseInterfaceMember($extendedAttributeList);
if (defined ($member)) {
push(@members, $member);
}
} else {
last;
}
}
return \@members;
}
sub parseInheritance
{
my $self = shift;
my @parent = ();
my $next = $self->nextToken();
if ($next->value() eq ":") {
$self->assertTokenValue($self->getToken(), ":", __LINE__);
my $scopedName = $self->parseScopedName();
push(@parent, $scopedName);
# Multiple inheritance?
push(@parent, @{$self->parseIdentifiers()});
}
return \@parent;
}
sub parseEnum
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "enum") {
$self->assertTokenValue($self->getToken(), "enum", __LINE__);
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseEnumValueList();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseEnumValueList
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == StringToken) {
$self->assertTokenType($self->getToken(), StringToken);
$self->parseEnumValues();
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseEnumValues
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq ",") {
$self->assertTokenValue($self->getToken(), ",", __LINE__);
$self->assertTokenType($self->getToken(), StringToken);
$self->parseEnumValues();
}
}
sub parseCallbackRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->assertTokenValue($self->getToken(), "=", __LINE__);
$self->parseReturnType();
$self->assertTokenValue($self->getToken(), "(", __LINE__);
$self->parseArgumentList();
$self->assertTokenValue($self->getToken(), ")", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseTypedef
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "typedef") {
$self->assertTokenValue($self->getToken(), "typedef", __LINE__);
$self->parseExtendedAttributeList();
$self->parseType();
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseImplementsStatement
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
$self->parseScopedName();
$self->assertTokenValue($self->getToken(), "implements", __LINE__);
$self->parseScopedName();
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseConst
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "const") {
my $newDataNode = new domConstant();
$self->assertTokenValue($self->getToken(), "const", __LINE__);
$newDataNode->type($self->parseConstType());
my $constNameToken = $self->getToken();
$self->assertTokenType($constNameToken, IdentifierToken);
$newDataNode->name($constNameToken->value());
$self->assertTokenValue($self->getToken(), "=", __LINE__);
$newDataNode->value($self->parseConstValue());
$self->assertTokenValue($self->getToken(), ";", __LINE__);
$newDataNode->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseConstValue
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextConstValue_1/) {
return $self->parseBooleanLiteral();
}
if ($next->value() eq "null") {
$self->assertTokenValue($self->getToken(), "null", __LINE__);
return "null";
}
if ($next->type() == FloatToken || $next->value() =~ /$nextConstValue_2/) {
return $self->parseFloatLiteral();
}
# backward compatibility
if ($next->type() == StringToken) {
return $self->getToken()->value();
}
if ($next->type() == IntegerToken) {
return $self->getToken()->value();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseBooleanLiteral
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "true") {
$self->assertTokenValue($self->getToken(), "true", __LINE__);
return "true";
}
if ($next->value() eq "false") {
$self->assertTokenValue($self->getToken(), "false", __LINE__);
return "false";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseFloatLiteral
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "-") {
$self->assertTokenValue($self->getToken(), "-", __LINE__);
$self->assertTokenValue($self->getToken(), "Infinity", __LINE__);
return "-Infinity";
}
if ($next->value() eq "Infinity") {
$self->assertTokenValue($self->getToken(), "Infinity", __LINE__);
return "Infinity";
}
if ($next->value() eq "NaN") {
$self->assertTokenValue($self->getToken(), "NaN", __LINE__);
return "NaN";
}
if ($next->type() == FloatToken) {
return $self->getToken()->value();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeOrOperationOrIterator
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "serializer") {
return $self->parseSerializer($extendedAttributeList);
}
if ($next->value() =~ /$nextAttributeOrOperationOrIterator_1/) {
my $qualifier = $self->parseQualifier();
my $newDataNode = $self->parseAttributeOrOperationRest($extendedAttributeList);
if (defined($newDataNode) && $qualifier eq "static") {
$newDataNode->isStatic(1);
}
return $newDataNode;
}
if ($next->value() =~ /$nextAttributeOld_1/) {
return $self->parseAttribute($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationOrIterator_2/) {
return $self->parseOperationOrIterator($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSerializer
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "serializer") {
$self->assertTokenValue($self->getToken(), "serializer", __LINE__);
return $self->parseSerializerRest($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSerializerRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "=") {
$self->assertTokenValue($self->getToken(), "=", __LINE__);
return $self->parseSerializationPattern($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() eq "(") {
return $self->parseOperationRest($extendedAttributeList);
}
}
sub parseSerializationPattern
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "{") {
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseSerializationPatternMap();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
return;
}
if ($next->value() eq "[") {
$self->assertTokenValue($self->getToken(), "[", __LINE__);
$self->parseSerializationPatternList();
$self->assertTokenValue($self->getToken(), "]", __LINE__);
return;
}
if ($next->type() == IdentifierToken) {
$self->assertTokenType($self->getToken(), IdentifierToken);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSerializationPatternMap
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "getter") {
$self->assertTokenValue($self->getToken(), "getter", __LINE__);
return;
}
if ($next->value() eq "inherit") {
$self->assertTokenValue($self->getToken(), "inherit", __LINE__);
$self->parseIdentifiers();
return;
}
if ($next->type() == IdentifierToken) {
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->parseIdentifiers();
}
}
sub parseSerializationPatternList
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "getter") {
$self->assertTokenValue($self->getToken(), "getter", __LINE__);
return;
}
if ($next->type() == IdentifierToken) {
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->parseIdentifiers();
}
}
sub parseIdentifiers
{
my $self = shift;
my @idents = ();
while (1) {
my $next = $self->nextToken();
if ($next->value() eq ",") {
$self->assertTokenValue($self->getToken(), ",", __LINE__);
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
push(@idents, $token->value());
} else {
last;
}
}
return \@idents;
}
sub parseQualifier
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "static") {
$self->assertTokenValue($self->getToken(), "static", __LINE__);
return "static";
}
if ($next->value() eq "stringifier") {
$self->assertTokenValue($self->getToken(), "stringifier", __LINE__);
return "stringifier";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeOrOperationRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeRest_1/) {
return $self->parseAttributeRest($extendedAttributeList);
}
if ($next->value() eq ";") {
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
my $returnType = $self->parseReturnType();
my $dataNode = $self->parseOperationRest($extendedAttributeList);
if (defined ($dataNode)) {
$dataNode->signature->type($returnType);
}
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttribute
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeOld_1/) {
$self->parseInherit();
return $self->parseAttributeRest($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeRest_1/) {
my $newDataNode = new domAttribute();
if ($self->parseReadOnly()) {
$newDataNode->type("readonly attribute");
} else {
$newDataNode->type("attribute");
}
$self->assertTokenValue($self->getToken(), "attribute", __LINE__);
$newDataNode->signature(new domSignature());
$newDataNode->signature->type($self->parseType());
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
$newDataNode->signature->name($token->value());
my $getRef = $self->parseGet();
if (defined $getRef) {
push(@{$newDataNode->getterExceptions}, @{$getRef->{"getraises"}});
push(@{$newDataNode->setterExceptions}, @{$getRef->{"setraises"}});
}
$self->assertTokenValue($self->getToken(), ";", __LINE__);
$newDataNode->signature->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseInherit
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "inherit") {
$self->assertTokenValue($self->getToken(), "inherit", __LINE__);
return 1;
}
return 0;
}
sub parseReadOnly
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "readonly") {
$self->assertTokenValue($self->getToken(), "readonly", __LINE__);
return 1;
}
return 0;
}
sub parseOperationOrIterator
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextSpecials_1/) {
return $self->parseSpecialOperation($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
my $returnType = $self->parseReturnType();
my $dataNode = $self->parseOperationOrIteratorRest($extendedAttributeList);
if (defined ($dataNode)) {
$dataNode->signature->type($returnType);
}
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSpecialOperation
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextSpecials_1/) {
$self->parseSpecial();
$self->parseSpecials();
my $returnType = $self->parseReturnType();
my $dataNode = $self->parseOperationRest($extendedAttributeList);
if (defined ($dataNode)) {
$dataNode->signature->type($returnType);
}
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSpecials
{
my $self = shift;
while (1) {
my $next = $self->nextToken();
if ($next->value() =~ /$nextSpecials_1/) {
$self->parseSpecial();
} else {
last;
}
}
return [];
}
sub parseSpecial
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "getter") {
$self->assertTokenValue($self->getToken(), "getter", __LINE__);
return "getter";
}
if ($next->value() eq "setter") {
$self->assertTokenValue($self->getToken(), "setter", __LINE__);
return "setter";
}
if ($next->value() eq "creator") {
$self->assertTokenValue($self->getToken(), "creator", __LINE__);
return "creator";
}
if ($next->value() eq "deleter") {
$self->assertTokenValue($self->getToken(), "deleter", __LINE__);
return "deleter";
}
if ($next->value() eq "legacycaller") {
$self->assertTokenValue($self->getToken(), "legacycaller", __LINE__);
return "legacycaller";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseOperationOrIteratorRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "iterator") {
return $self->parseIteratorRest($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() eq "(") {
return $self->parseOperationRest($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseIteratorRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "iterator") {
$self->assertTokenValue($self->getToken(), "iterator", __LINE__);
$self->parseOptionalIteratorInterfaceOrObject($extendedAttributeList);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseOptionalIteratorInterfaceOrObject
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextOptionalIteratorInterfaceOrObject_1/) {
return $self->parseOptionalIteratorInterface($extendedAttributeList);
}
if ($next->value() eq "object") {
$self->assertTokenValue($self->getToken(), "object", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseOptionalIteratorInterface
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "=") {
$self->assertTokenValue($self->getToken(), "=", __LINE__);
$self->assertTokenType($self->getToken(), IdentifierToken);
}
}
sub parseOperationRest
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "(") {
my $newDataNode = new domFunction();
$newDataNode->signature(new domSignature());
my $name = $self->parseOptionalIdentifier();
$newDataNode->signature->name($name);
$self->assertTokenValue($self->getToken(), "(", $name, __LINE__);
push(@{$newDataNode->parameters}, @{$self->parseArgumentList()});
$self->assertTokenValue($self->getToken(), ")", __LINE__);
push(@{$newDataNode->raisesExceptions}, @{$self->parseRaises()});
$self->assertTokenValue($self->getToken(), ";", __LINE__);
$newDataNode->signature->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseOptionalIdentifier
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
my $token = $self->getToken();
return $token->value();
}
return "";
}
sub parseArgumentList
{
my $self = shift;
my @arguments = ();
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
push(@arguments, $self->parseArgument());
push(@arguments, @{$self->parseArguments()});
}
return \@arguments;
}
sub parseArguments
{
my $self = shift;
my @arguments = ();
while (1) {
my $next = $self->nextToken();
if ($next->value() eq ",") {
$self->assertTokenValue($self->getToken(), ",", __LINE__);
push(@arguments, $self->parseArgument());
} else {
last;
}
}
return \@arguments;
}
sub parseArgument
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
my $in = $self->parseIn();
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
my $argument = $self->parseOptionalOrRequiredArgument($extendedAttributeList);
$argument->direction($self->parseIn());
return $argument;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseOptionalOrRequiredArgument
{
my $self = shift;
my $extendedAttributeList = shift;
my $paramDataNode = new domSignature();
$paramDataNode->extendedAttributes($extendedAttributeList);
my $next = $self->nextToken();
if ($next->value() eq "optional") {
$self->assertTokenValue($self->getToken(), "optional", __LINE__);
my $type = $self->parseType();
# domDataNode can only consider last "?".
if ($type =~ /\?$/) {
$paramDataNode->isNullable(1);
} else {
$paramDataNode->isNullable(0);
}
# Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
$type =~ s/\?//g;
$paramDataNode->type($type);
$paramDataNode->name($self->parseArgumentName());
$self->parseDefault();
return $paramDataNode;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
my $type = $self->parseType();
# domDataNode can only consider last "?".
if ($type =~ /\?$/) {
$paramDataNode->isNullable(1);
} else {
$paramDataNode->isNullable(0);
}
# Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
$type =~ s/\?//g;
$paramDataNode->type($type);
$paramDataNode->isVariadic($self->parseEllipsis());
$paramDataNode->name($self->parseArgumentName());
return $paramDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseArgumentName
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextArgumentName_1/) {
return $self->parseArgumentNameKeyword();
}
if ($next->type() == IdentifierToken) {
return $self->getToken()->value();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseEllipsis
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "...") {
$self->assertTokenValue($self->getToken(), "...", __LINE__);
return 1;
}
return 0;
}
sub parseExceptionMember
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->value() eq "const") {
return $self->parseConst($extendedAttributeList);
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
return $self->parseExceptionField($extendedAttributeList);
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExceptionField
{
my $self = shift;
my $extendedAttributeList = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
my $newDataNode = new domAttribute();
$newDataNode->type("readonly attribute");
$newDataNode->signature(new domSignature());
$newDataNode->signature->type($self->parseType());
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
$newDataNode->signature->name($token->value());
$self->assertTokenValue($self->getToken(), ";", __LINE__);
$newDataNode->signature->extendedAttributes($extendedAttributeList);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExtendedAttributeListAllowEmpty
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "[") {
return $self->parseExtendedAttributeList();
}
return {};
}
sub parseExtendedAttributeList
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "[") {
$self->assertTokenValue($self->getToken(), "[", __LINE__);
my $extendedAttributeList = {};
my $attr = $self->parseExtendedAttribute();
for my $key (keys %{$attr}) {
$extendedAttributeList->{$key} = $attr->{$key};
}
$attr = $self->parseExtendedAttributes();
for my $key (keys %{$attr}) {
$extendedAttributeList->{$key} = $attr->{$key};
}
$self->assertTokenValue($self->getToken(), "]", __LINE__);
return $extendedAttributeList;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExtendedAttributes
{
my $self = shift;
my $extendedAttributeList = {};
while (1) {
my $next = $self->nextToken();
if ($next->value() eq ",") {
$self->assertTokenValue($self->getToken(), ",", __LINE__);
my $attr = $self->parseExtendedAttribute2();
for my $key (keys %{$attr}) {
$extendedAttributeList->{$key} = $attr->{$key};
}
} else {
last;
}
}
return $extendedAttributeList;
}
sub parseExtendedAttribute
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "::") {
my $scopedName = $self->parseScopedName();
return $self->parseExtendedAttributeRest($scopedName);
}
# backward compatibility. Spec doesn' allow "[]". But WebKit requires.
if ($next->value() eq ']') {
return {};
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExtendedAttribute2
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "::") {
my $scopedName = $self->parseScopedName();
return $self->parseExtendedAttributeRest($scopedName);
}
return {};
}
sub parseExtendedAttributeRest
{
my $self = shift;
my $name = shift;
my $attrs = {};
my $next = $self->nextToken();
if ($next->value() eq "(") {
$self->assertTokenValue($self->getToken(), "(", __LINE__);
$attrs->{$name} = $self->parseArgumentList();
$self->assertTokenValue($self->getToken(), ")", __LINE__);
return $attrs;
}
if ($next->value() eq "=") {
$self->assertTokenValue($self->getToken(), "=", __LINE__);
$attrs->{$name} = $self->parseExtendedAttributeRest2();
return $attrs;
}
if ($name eq "Constructor") {
$attrs->{$name} = [];
} else {
$attrs->{$name} = "VALUE_IS_MISSING";
}
return $attrs;
}
sub parseExtendedAttributeRest2
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "::") {
my $scopedName = $self->parseScopedName();
return $self->parseExtendedAttributeRest3($scopedName);
}
if ($next->type() == IntegerToken) {
my $token = $self->getToken();
return $token->value();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExtendedAttributeRest3
{
my $self = shift;
my $name = shift;
my $next = $self->nextToken();
if ($next->value() eq "&") {
$self->assertTokenValue($self->getToken(), "&", __LINE__);
my $rightValue = $self->parseScopedName();
return $name . "&" . $rightValue;
}
if ($next->value() eq "|") {
$self->assertTokenValue($self->getToken(), "|", __LINE__);
my $rightValue = $self->parseScopedName();
return $name . "|" . $rightValue;
}
if ($next->value() eq "(") {
my $attr = {};
$self->assertTokenValue($self->getToken(), "(", __LINE__);
$attr->{$name} = $self->parseArgumentList();
$self->assertTokenValue($self->getToken(), ")", __LINE__);
return $attr;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExtendedAttributeRest3_1/) {
my @names = ();
push(@names, $name);
push(@names, @{$self->parseScopedNameListNoComma()});
return join(' ', @names);
}
$self->assertUnexpectedToken($next->value());
}
sub parseScopedNameListNoComma
{
my $self = shift;
my @names = ();
while (1) {
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "::") {
push(@names, $self->parseScopedName());
} else {
last;
}
}
return \@names;
}
sub parseArgumentNameKeyword
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "attribute") {
return $self->getToken()->value();
}
if ($next->value() eq "callback") {
return $self->getToken()->value();
}
if ($next->value() eq "const") {
return $self->getToken()->value();
}
if ($next->value() eq "creator") {
return $self->getToken()->value();
}
if ($next->value() eq "deleter") {
return $self->getToken()->value();
}
if ($next->value() eq "dictionary") {
return $self->getToken()->value();
}
if ($next->value() eq "enum") {
return $self->getToken()->value();
}
if ($next->value() eq "exception") {
return $self->getToken()->value();
}
if ($next->value() eq "getter") {
return $self->getToken()->value();
}
if ($next->value() eq "implements") {
return $self->getToken()->value();
}
if ($next->value() eq "inherit") {
return $self->getToken()->value();
}
if ($next->value() eq "interface") {
return $self->getToken()->value();
}
if ($next->value() eq "legacycaller") {
return $self->getToken()->value();
}
if ($next->value() eq "partial") {
return $self->getToken()->value();
}
if ($next->value() eq "serializer") {
return $self->getToken()->value();
}
if ($next->value() eq "setter") {
return $self->getToken()->value();
}
if ($next->value() eq "static") {
return $self->getToken()->value();
}
if ($next->value() eq "stringifier") {
return $self->getToken()->value();
}
if ($next->value() eq "typedef") {
return $self->getToken()->value();
}
if ($next->value() eq "unrestricted") {
return $self->getToken()->value();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "(") {
$self->parseUnionType();
$self->parseTypeSuffix();
return;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) {
return $self->parseSingleType();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSingleType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "any") {
$self->assertTokenValue($self->getToken(), "any", __LINE__);
return "any" . $self->parseTypeSuffixStartingWithArray();
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
return $self->parseNonAnyType();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseUnionType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "(") {
$self->assertTokenValue($self->getToken(), "(", __LINE__);
$self->parseUnionMemberType();
$self->assertTokenValue($self->getToken(), "or", __LINE__);
$self->parseUnionMemberType();
$self->parseUnionMemberTypes();
$self->assertTokenValue($self->getToken(), ")", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseUnionMemberType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "(") {
$self->parseUnionType();
$self->parseTypeSuffix();
return;
}
if ($next->value() eq "any") {
$self->assertTokenValue($self->getToken(), "any", __LINE__);
$self->assertTokenValue($self->getToken(), "[", __LINE__);
$self->assertTokenValue($self->getToken(), "]", __LINE__);
$self->parseTypeSuffix();
return;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
$self->parseNonAnyType();
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseUnionMemberTypes
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "or") {
$self->assertTokenValue($self->getToken(), "or", __LINE__);
$self->parseUnionMemberType();
$self->parseUnionMemberTypes();
}
}
sub parseNonAnyType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextNonAnyType_1/) {
return $self->parsePrimitiveType() . $self->parseTypeSuffix();
}
if ($next->value() eq "ByteString") {
$self->assertTokenValue($self->getToken(), "ByteString", __LINE__);
return "ByteString" . $self->parseTypeSuffix();
}
if ($next->value() eq "DOMString") {
$self->assertTokenValue($self->getToken(), "DOMString", __LINE__);
return "DOMString" . $self->parseTypeSuffix();
}
if ($next->value() eq "sequence") {
$self->assertTokenValue($self->getToken(), "sequence", __LINE__);
$self->assertTokenValue($self->getToken(), "<", __LINE__);
my $type = $self->parseType();
$self->assertTokenValue($self->getToken(), ">", __LINE__);
return "sequence<" . $type . ">" . $self->parseNull();
}
if ($next->value() eq "object") {
$self->assertTokenValue($self->getToken(), "object", __LINE__);
return "object" . $self->parseTypeSuffix();
}
if ($next->value() eq "Date") {
$self->assertTokenValue($self->getToken(), "Date", __LINE__);
return "Date" . $self->parseTypeSuffix();
}
if ($next->type() == IdentifierToken || $next->value() eq "::") {
my $name = $self->parseScopedName();
return $name . $self->parseTypeSuffix();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseConstType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextNonAnyType_1/) {
return $self->parsePrimitiveType() . $self->parseNull();
}
if ($next->type() == IdentifierToken) {
my $token = $self->getToken();
return $token->value() . $self->parseNull();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parsePrimitiveType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextPrimitiveType_1/) {
return $self->parseUnsignedIntegerType();
}
if ($next->value() =~ /$nextPrimitiveType_2/) {
return $self->parseUnrestrictedFloatType();
}
if ($next->value() eq "boolean") {
$self->assertTokenValue($self->getToken(), "boolean", __LINE__);
return "boolean";
}
if ($next->value() eq "byte") {
$self->assertTokenValue($self->getToken(), "byte", __LINE__);
return "byte";
}
if ($next->value() eq "octet") {
$self->assertTokenValue($self->getToken(), "octet", __LINE__);
return "octet";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseUnrestrictedFloatType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "unrestricted") {
$self->assertTokenValue($self->getToken(), "unrestricted", __LINE__);
return "unrestricted" . $self->parseFloatType();
}
if ($next->value() =~ /$nextUnrestrictedFloatType_1/) {
return $self->parseFloatType();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseFloatType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "float") {
$self->assertTokenValue($self->getToken(), "float", __LINE__);
return "float";
}
if ($next->value() eq "double") {
$self->assertTokenValue($self->getToken(), "double", __LINE__);
return "double";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseUnsignedIntegerType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "unsigned") {
$self->assertTokenValue($self->getToken(), "unsigned", __LINE__);
return "unsigned " . $self->parseIntegerType();
}
if ($next->value() =~ /$nextUnsignedIntegerType_1/) {
return $self->parseIntegerType();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseIntegerType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "short") {
$self->assertTokenValue($self->getToken(), "short", __LINE__);
return "short";
}
if ($next->value() eq "int") {
$self->assertTokenValue($self->getToken(), "int", __LINE__);
return "int";
}
if ($next->value() eq "long") {
$self->assertTokenValue($self->getToken(), "long", __LINE__);
if ($self->parseOptionalLong()) {
return "long long";
}
return "long";
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseOptionalLong
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "long") {
$self->assertTokenValue($self->getToken(), "long", __LINE__);
return 1;
}
return 0;
}
sub parseTypeSuffix
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "[") {
$self->assertTokenValue($self->getToken(), "[", __LINE__);
$self->assertTokenValue($self->getToken(), "]", __LINE__);
return "[]" . $self->parseTypeSuffix();
}
if ($next->value() eq "?") {
$self->assertTokenValue($self->getToken(), "?", __LINE__);
return "?" . $self->parseTypeSuffixStartingWithArray();
}
return "";
}
sub parseTypeSuffixStartingWithArray
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "[") {
$self->assertTokenValue($self->getToken(), "[", __LINE__);
$self->assertTokenValue($self->getToken(), "]", __LINE__);
return "[]" . $self->parseTypeSuffix();
}
return "";
}
sub parseNull
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "?") {
$self->assertTokenValue($self->getToken(), "?", __LINE__);
return "?";
}
return "";
}
sub parseReturnType
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "void") {
$self->assertTokenValue($self->getToken(), "void", __LINE__);
return "void";
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
return $self->parseType();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseGet
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "inherits") {
my $attr = {};
$self->parseInheritsGetter();
$attr->{"inherits"} = 1;
$attr->{"getraises"} = [];
$attr->{"setraises"} = $self->parseSetRaises();
return $attr;
}
if ($next->value() =~ /$nextGet_1/) {
return $self->parseSetGetRaises();
}
}
sub parseInheritsGetter
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "inherits") {
$self->assertTokenValue($self->getToken(), "inherits", __LINE__);
$self->assertTokenValue($self->getToken(), "getter", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSetGetRaises
{
my $self = shift;
my $attr = {};
$attr->{"inherits"} = 0;
my $next = $self->nextToken();
if ($next->value() eq "setter") {
$attr->{"setraises"} = $self->parseSetRaises();
$attr->{"getraises"} = $self->parseGetRaises2();
return $attr;
}
if ($next->value() eq "getter") {
$attr->{"setraises"} = [];
$attr->{"getraises"} = $self->parseGetRaises();
return $attr;
}
if ($next->value() =~ /$nextSetGetRaises2_1/) {
return $self->parseSetGetRaises2();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseGetRaises
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "getter") {
$self->assertTokenValue($self->getToken(), "getter", __LINE__);
$self->assertTokenValue($self->getToken(), "raises", __LINE__);
return $self->parseExceptionList();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseGetRaises2
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq ",") {
$self->assertTokenValue($self->getToken(), ",", __LINE__);
$self->assertTokenValue($self->getToken(), "getter", __LINE__);
$self->assertTokenValue($self->getToken(), "raises", __LINE__);
return $self->parseExceptionList();
}
return [];
}
sub parseSetRaises
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "setter") {
$self->assertTokenValue($self->getToken(), "setter", __LINE__);
$self->assertTokenValue($self->getToken(), "raises", __LINE__);
return $self->parseExceptionList();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseSetGetRaises2
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextSetGetRaises2_1/) {
my $attr = {};
$attr->{"inherits"} = 0;
$attr->{"getraises"} = $self->parseGetRaises3();
$attr->{"setraises"} = $self->parseSetRaises3();
return $attr;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseGetRaises3
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "getraises") {
$self->assertTokenValue($self->getToken(), "getraises", __LINE__);
return $self->parseExceptionList();
}
return [];
}
sub parseSetRaises3
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "setraises") {
$self->assertTokenValue($self->getToken(), "setraises", __LINE__);
return $self->parseExceptionList();
}
return [];
}
sub parseExceptionList
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "(") {
my @exceptions = ();
$self->assertTokenValue($self->getToken(), "(", __LINE__);
push(@exceptions, @{$self->parseScopedNameList()});
$self->assertTokenValue($self->getToken(), ")", __LINE__);
return \@exceptions;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseRaises
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "raises") {
$self->assertTokenValue($self->getToken(), "raises", __LINE__);
return $self->parseExceptionList();
}
return [];
}
sub parseDefinitionOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextDefinition_1/) {
return $self->parseCallbackOrInterfaceOld();
}
if ($next->value() eq "partial") {
return $self->parsePartial({});
}
if ($next->value() eq "dictionary") {
return $self->parseDictionaryOld();
}
if ($next->value() eq "exception") {
return $self->parseExceptionOld();
}
if ($next->value() eq "enum") {
return $self->parseEnumOld();
}
if ($next->value() eq "typedef") {
return $self->parseTypedef({});
}
if ($next->value() eq "module") {
return $self->parseModule();
}
if ($next->type() == IdentifierToken || $next->value() eq "::") {
return $self->parseImplementsStatement({});
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseModule
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "module") {
my $document = new idlDocument();
$self->assertTokenValue($self->getToken(), "module", __LINE__);
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$document->module($token->value());
my $definitions = $self->parseDefinitions();
push(@{$document->classes}, @{$definitions});
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->parseOptionalSemicolon();
return $document;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseCallbackOrInterfaceOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "callback") {
$self->assertTokenValue($self->getToken(), "callback", __LINE__);
return $self->parseCallbackRestOrInterface({});
}
if ($next->value() eq "interface") {
return $self->parseInterfaceOld();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseInterfaceOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "interface") {
my $dataNode = new domClass();
$self->assertTokenValue($self->getToken(), "interface", __LINE__);
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
$dataNode->name($token->value());
$dataNode->isException(0);
push(@{$dataNode->parents}, @{$self->parseInheritance()});
$self->assertTokenValue($self->getToken(), "{", __LINE__);
my $interfaceMembers = $self->parseInterfaceMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
applyMemberList($dataNode, $interfaceMembers);
applyExtendedAttributeList($dataNode, $extendedAttributeList);
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseInterfaceMemberOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "const") {
return $self->parseConst({});
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMemberOld_1/) {
return $self->parseAttributeOrOperationOrIteratorOld();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseDictionaryOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "dictionary") {
$self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
$self->parseExtendedAttributeListAllowEmpty();
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->parseInheritance();
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseDictionaryMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseDictionaryMemberOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
$self->parseType();
$self->parseExtendedAttributeListAllowEmpty();
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->parseDefault();
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseExceptionOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "exception") {
my $dataNode = new domClass();
$self->assertTokenValue($self->getToken(), "exception", __LINE__);
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
$dataNode->name($token->value());
$dataNode->isException(1);
push(@{$dataNode->parents}, @{$self->parseInheritance()});
$self->assertTokenValue($self->getToken(), "{", __LINE__);
my $exceptionMembers = $self->parseInterfaceMembers();
#$self->parseExceptionMembers();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
applyMemberList($dataNode, $exceptionMembers);
applyExtendedAttributeList($dataNode, $extendedAttributeList);
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseEnumOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "enum") {
$self->assertTokenValue($self->getToken(), "enum", __LINE__);
$self->parseExtendedAttributeListAllowEmpty();
$self->assertTokenType($self->getToken(), IdentifierToken);
$self->assertTokenValue($self->getToken(), "{", __LINE__);
$self->parseEnumValueList();
$self->assertTokenValue($self->getToken(), "}", __LINE__);
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeOrOperationOrIteratorOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "serializer") {
return $self->parseSerializer({});
}
if ($next->value() =~ /$nextAttributeOrOperationOrIterator_1/) {
my $qualifier = $self->parseQualifier();
my $dataNode = $self->parseAttributeOrOperationRestOld();
if (defined ($dataNode) && $qualifier eq "static") {
$dataNode->isStatic(1);
}
return $dataNode;
}
if ($next->value() =~ /$nextAttributeOld_1/) {
return $self->parseAttributeOld();
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationOrIterator_2/) {
return $self->parseOperationOrIterator({});
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeOrOperationRestOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeRest_1/) {
return $self->parseAttributeRestOld();
}
if ($next->value() eq ";") {
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return;
}
if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
my $returnType = $self->parseReturnType();
my $dataNode = $self->parseOperationRest({});
if (defined ($dataNode)) {
$dataNode->signature->type($returnType);
}
return $dataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeOld_1/) {
$self->parseInherit();
return $self->parseAttributeRestOld();
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseAttributeRestOld
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() =~ /$nextAttributeRest_1/) {
my $newDataNode = new domAttribute();
if ($self->parseReadOnly()) {
$newDataNode->type("readonly attribute");
} else {
$newDataNode->type("attribute");
}
$self->assertTokenValue($self->getToken(), "attribute", __LINE__);
my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
$newDataNode->signature(new domSignature());
$newDataNode->signature->type($self->parseType());
$newDataNode->signature->extendedAttributes($extendedAttributeList);
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
$newDataNode->signature->name($token->value());
my $getRef = $self->parseGet();
if (defined $getRef) {
push(@{$newDataNode->getterExceptions}, @{$getRef->{"getraises"}});
push(@{$newDataNode->setterExceptions}, @{$getRef->{"setraises"}});
}
$self->assertTokenValue($self->getToken(), ";", __LINE__);
return $newDataNode;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseIn
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "in") {
$self->assertTokenValue($self->getToken(), "in", __LINE__);
return "in";
}
return "";
}
sub parseOptionalSemicolon
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq ";") {
$self->assertTokenValue($self->getToken(), ";", __LINE__);
}
}
sub parseScopedName
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "::") {
return $self->parseAbsoluteScopedName();
}
if ($next->type() == IdentifierToken) {
return $self->parseRelativeScopedName();
}
$self->assertUnexpectedToken($next->value());
}
sub parseAbsoluteScopedName
{
my $self = shift;
my $next = $self->nextToken();
if ($next->value() eq "::") {
$self->assertTokenValue($self->getToken(), "::");
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
return "::" . $token->value() . $self->parseScopedNameParts();
}
$self->assertUnexpectedToken($next->value());
}
sub parseRelativeScopedName
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken) {
my $token = $self->getToken();
return $token->value() . $self->parseScopedNameParts();
}
$self->assertUnexpectedToken($next->value());
}
sub parseScopedNameParts
{
my $self = shift;
my @names = ();
while (1) {
my $next = $self->nextToken();
if ($next->value() eq "::") {
$self->assertTokenValue($self->getToken(), "::");
push(@names, "::");
my $token = $self->getToken();
$self->assertTokenType($token, IdentifierToken);
push(@names, $token->value());
} else {
last;
}
}
return join("", @names);
}
sub parseScopedNameList
{
my $self = shift;
my $next = $self->nextToken();
if ($next->type() == IdentifierToken || $next->value() eq "::") {
my @names = ();
push(@names, $self->parseScopedName());
push(@names, @{$self->parseScopedNames()});
return \@names;
}
$self->assertUnexpectedToken($next->value(), __LINE__);
}
sub parseScopedNames
{
my $self = shift;
my @names = ();
while (1) {
my $next = $self->nextToken();
if ($next->value() eq ",") {
$self->assertTokenValue($self->getToken(), ",");
push(@names, $self->parseScopedName());
} else {
last;
}
}
return \@names;
}
sub applyMemberList
{
my $dataNode = shift;
my $members = shift;
for my $item (@{$members}) {
if (ref($item) eq "domAttribute") {
push(@{$dataNode->attributes}, $item);
next;
}
if (ref($item) eq "domConstant") {
push(@{$dataNode->constants}, $item);
next;
}
if (ref($item) eq "domFunction") {
push(@{$dataNode->functions}, $item);
next;
}
}
}
sub applyExtendedAttributeList
{
my $dataNode = shift;
my $extendedAttributeList = shift;
if (defined $extendedAttributeList->{"Constructor"}) {
my $newDataNode = new domFunction();
$newDataNode->signature(new domSignature());
$newDataNode->signature->name("Constructor");
$newDataNode->signature->extendedAttributes($extendedAttributeList);
push(@{$newDataNode->parameters}, @{$extendedAttributeList->{"Constructor"}});
$extendedAttributeList->{"Constructor"} = "VALUE_IS_MISSING";
$dataNode->constructor($newDataNode);
} elsif (defined $extendedAttributeList->{"NamedConstructor"}) {
my $newDataNode = new domFunction();
$newDataNode->signature(new domSignature());
$newDataNode->signature->name("NamedConstructor");
$newDataNode->signature->extendedAttributes($extendedAttributeList);
my %attributes = %{$extendedAttributeList->{"NamedConstructor"}};
my @attributeKeys = keys (%attributes);
my $constructorName = $attributeKeys[0];
push(@{$newDataNode->parameters}, @{$attributes{$constructorName}});
$extendedAttributeList->{"NamedConstructor"} = $constructorName;
$dataNode->constructor($newDataNode);
}
$dataNode->extendedAttributes($extendedAttributeList);
}
1;