# # KDOM IDL parser # # Copyright (C) 2005 Nikolas Zimmermann # # 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 strict; use preprocessor; use Class::Struct; use Data::Dumper; use constant StringToken => 0; use constant IntegerToken => 1; use constant FloatToken => 2; use constant IdentifierToken => 3; use constant OtherToken => 4; use constant EmptyToken => 5; # Used to represent a parsed IDL document struct( idlDocument => { interfaces => '@', # All parsed interfaces fileName => '$' # file name }); # Used to represent 'interface' blocks struct( domInterface => { name => '$', # Class identifier parents => '@', # List of strings constants => '@', # List of 'domConstant' functions => '@', # List of 'domFunction' attributes => '@', # List of 'domAttribute' extendedAttributes => '$', # Extended attributes constructors => '@', # Constructor isException => '$', # Used for exception interfaces }); # Used to represent domInterface contents (name of method, signature) struct( domFunction => { isStatic => '$', signature => '$', # Return type/Object name/extended attributes parameters => '@', # List of 'domSignature' raisesExceptions => '@', # Possibly raised exceptions. }); # Used to represent domInterface contents (name of attribute, signature) struct( domAttribute => { type => '$', # Attribute type (including namespace) isStatic => '$', signature => '$', # Attribute signature getterExceptions => '@', # Possibly raised exceptions. setterExceptions => '@', # Possibly raised exceptions. }); # Used to represent a map of 'variable name' <-> 'variable type' struct( domSignature => { direction => '$', # Variable direction (in or out) name => '$', # Variable name type => '$', # Variable type extendedAttributes => '$', # Extended attributes isNullable => '$', # Is variable type Nullable (T?) isOptional => '$', # Is variable optional (T?) isVariadic => '$' # Is variable variadic (long... numbers) }); # Used to represent string constants struct( domConstant => { name => '$', # DOM Constant identifier type => '$', # Type of data value => '$', # Constant value extendedAttributes => '$', # Extended attributes }); 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 = idlDocument->new(); push(@{$document->interfaces}, @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 $interface = domInterface->new(); $self->assertTokenValue($self->getToken(), "interface", __LINE__); my $interfaceNameToken = $self->getToken(); $self->assertTokenType($interfaceNameToken, IdentifierToken); $interface->name($interfaceNameToken->value()); push(@{$interface->parents}, @{$self->parseInheritance()}); $self->assertTokenValue($self->getToken(), "{", __LINE__); my $interfaceMembers = $self->parseInterfaceMembers(); $self->assertTokenValue($self->getToken(), "}", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); applyMemberList($interface, $interfaceMembers); applyExtendedAttributeList($interface, $extendedAttributeList); return $interface; } $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 $interface = domInterface->new(); $self->assertTokenValue($self->getToken(), "exception", __LINE__); my $exceptionNameToken = $self->getToken(); $self->assertTokenType($exceptionNameToken, IdentifierToken); $interface->name($exceptionNameToken->value()); $interface->isException(1); push(@{$interface->parents}, @{$self->parseInheritance()}); $self->assertTokenValue($self->getToken(), "{", __LINE__); my $exceptionMembers = $self->parseExceptionMembers(); $self->assertTokenValue($self->getToken(), "}", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); applyMemberList($interface, $exceptionMembers); applyExtendedAttributeList($interface, $extendedAttributeList); return $interface; } $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 = domConstant->new(); $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 $interface = $self->parseOperationRest($extendedAttributeList); if (defined ($interface)) { $interface->signature->type($returnType); } return $interface; } $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 = domAttribute->new(); if ($self->parseReadOnly()) { $newDataNode->type("readonly attribute"); } else { $newDataNode->type("attribute"); } $self->assertTokenValue($self->getToken(), "attribute", __LINE__); $newDataNode->signature(domSignature->new()); $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 $interface = $self->parseOperationOrIteratorRest($extendedAttributeList); if (defined ($interface)) { $interface->signature->type($returnType); } return $interface; } $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 $interface = $self->parseOperationRest($extendedAttributeList); if (defined ($interface)) { $interface->signature->type($returnType); } return $interface; } $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 = domFunction->new(); $newDataNode->signature(domSignature->new()); 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 = domSignature->new(); $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(); $paramDataNode->isOptional(1); # print Dumper($paramDataNode); 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 = domAttribute->new(); $newDataNode->type("readonly attribute"); $newDataNode->signature(domSignature->new()); $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 copyExtendedAttributes { my $extendedAttributeList = shift; my $attr = shift; for my $key (keys %{$attr}) { if ($key eq "Constructor") { push(@{$extendedAttributeList->{"Constructors"}}, $attr->{$key}); } elsif ($key eq "Constructors") { my @constructors = @{$attr->{$key}}; foreach my $constructor (@constructors) { push(@{$extendedAttributeList->{"Constructors"}}, $constructor); } } else { $extendedAttributeList->{$key} = $attr->{$key}; } } } sub parseExtendedAttributeList { my $self = shift; my $next = $self->nextToken(); if ($next->value() eq "[") { $self->assertTokenValue($self->getToken(), "[", __LINE__); my $extendedAttributeList = {}; my $attr = $self->parseExtendedAttribute(); copyExtendedAttributes($extendedAttributeList, $attr); $attr = $self->parseExtendedAttributes(); copyExtendedAttributes($extendedAttributeList, $attr); $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(); copyExtendedAttributes($extendedAttributeList, $attr); } 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->type() == IdentifierToken || $next->value() eq "::") { return $self->parseImplementsStatement({}); } $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 $interface = domInterface->new(); $self->assertTokenValue($self->getToken(), "interface", __LINE__); my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty(); my $token = $self->getToken(); $self->assertTokenType($token, IdentifierToken); $interface->name($token->value()); $interface->isException(0); push(@{$interface->parents}, @{$self->parseInheritance()}); $self->assertTokenValue($self->getToken(), "{", __LINE__); my $interfaceMembers = $self->parseInterfaceMembers(); $self->assertTokenValue($self->getToken(), "}", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); applyMemberList($interface, $interfaceMembers); applyExtendedAttributeList($interface, $extendedAttributeList); return $interface; } $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 $interface = domInterface->new(); $self->assertTokenValue($self->getToken(), "exception", __LINE__); my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty(); my $token = $self->getToken(); $self->assertTokenType($token, IdentifierToken); $interface->name($token->value()); $interface->isException(1); push(@{$interface->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($interface, $exceptionMembers); applyExtendedAttributeList($interface, $extendedAttributeList); return $interface; } $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 $interface = $self->parseAttributeOrOperationRestOld(); if (defined ($interface) && $qualifier eq "static") { $interface->isStatic(1); } return $interface; } 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 $interface = $self->parseOperationRest({}); if (defined ($interface)) { $interface->signature->type($returnType); } return $interface; } $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 = domAttribute->new(); if ($self->parseReadOnly()) { $newDataNode->type("readonly attribute"); } else { $newDataNode->type("attribute"); } $self->assertTokenValue($self->getToken(), "attribute", __LINE__); my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty(); $newDataNode->signature(domSignature->new()); $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 $interface = shift; my $members = shift; for my $item (@{$members}) { if (ref($item) eq "domAttribute") { push(@{$interface->attributes}, $item); next; } if (ref($item) eq "domConstant") { push(@{$interface->constants}, $item); next; } if (ref($item) eq "domFunction") { push(@{$interface->functions}, $item); next; } } } sub applyExtendedAttributeList { my $interface = shift; my $extendedAttributeList = shift; if (defined $extendedAttributeList->{"Constructors"}) { my @constructorParams = @{$extendedAttributeList->{"Constructors"}}; my $index = (@constructorParams == 1) ? 0 : 1; foreach my $param (@constructorParams) { my $constructor = domFunction->new(); $constructor->signature(domSignature->new()); $constructor->signature->name("Constructor"); $constructor->signature->extendedAttributes($extendedAttributeList); $constructor->parameters($param); $constructor->{overloadedIndex} = $index++; push(@{$interface->constructors}, $constructor); } # delete $extendedAttributeList->{"Constructors"}; # $extendedAttributeList->{"Constructor"} = "VALUE_IS_MISSING"; } elsif (defined $extendedAttributeList->{"NamedConstructor"}) { my $newDataNode = domFunction->new(); $newDataNode->signature(domSignature->new()); $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; push(@{$interface->constructors}, $newDataNode); } $interface->extendedAttributes($extendedAttributeList); } 1;