diff options
Diffstat (limited to 'Source/WebCore/bindings/scripts/IDLParser.pm')
-rw-r--r-- | Source/WebCore/bindings/scripts/IDLParser.pm | 1245 |
1 files changed, 736 insertions, 509 deletions
diff --git a/Source/WebCore/bindings/scripts/IDLParser.pm b/Source/WebCore/bindings/scripts/IDLParser.pm index 319f62bae..2107b94a5 100644 --- a/Source/WebCore/bindings/scripts/IDLParser.pm +++ b/Source/WebCore/bindings/scripts/IDLParser.pm @@ -23,6 +23,9 @@ package IDLParser; use strict; +use Carp qw<longmess>; +use Data::Dumper; + use preprocessor; use Class::Struct; @@ -34,68 +37,132 @@ use constant OtherToken => 4; use constant EmptyToken => 5; # Used to represent a parsed IDL document -struct( idlDocument => { - interfaces => '@', # All parsed interfaces - enumerations => '@', # All parsed enumerations - fileName => '$', # file name +struct( IDLDocument => { + interfaces => '@', # List of 'IDLInterface' + enumerations => '@', # List of 'IDLEnum' + dictionaries => '@', # List of 'IDLDictionary' + callbackFunctions => '@', # List of 'IDLCallbackFunction' + fileName => '$', +}); + +# https://heycam.github.io/webidl/#idl-types +struct( IDLType => { + name => '$', # Type identifier + isNullable => '$', # Is the type Nullable (T?) + isUnion => '$', # Is the type a union (T or U) + subtypes => '@', # Array of subtypes, only valid if isUnion or sequence }); # Used to represent 'interface' blocks -struct( domInterface => { - name => '$', # Class identifier - parent => '$', # Parent class identifier - parents => '@', # Parent class identifiers (Kept for compatibility with ObjC bindings) - constants => '@', # List of 'domConstant' - functions => '@', # List of 'domFunction' - anonymousFunctions => '@', # List of 'domFunction' - attributes => '@', # List of 'domAttribute' - extendedAttributes => '$', # Extended attributes - constructors => '@', # Constructors, list of 'domFunction' - customConstructors => '@', # Custom constructors, list of 'domFunction' +struct( IDLInterface => { + type => 'IDLType', + parentType => 'IDLType', + constants => '@', # List of 'IDLConstant' + functions => '@', # List of 'IDLOperation' + anonymousFunctions => '@', # List of 'IDLOperation' + attributes => '@', # List of 'IDLAttribute' + constructors => '@', # Constructors, list of 'IDLOperation' + customConstructors => '@', # Custom constructors, list of 'IDLOperation' isException => '$', # Used for exception interfaces isCallback => '$', # Used for callback interfaces isPartial => '$', # Used for partial interfaces + iterable => '$', # Used for iterable interfaces + serializable => '$', # Used for serializable interfaces + extendedAttributes => '$', }); -# Used to represent domInterface contents (name of method, signature) -struct( domFunction => { +# Used to represent an argument to a IDLOperation. +struct( IDLArgument => { + name => '$', + type => 'IDLType', + isVariadic => '$', + isOptional => '$', + default => '$', + extendedAttributes => '$', +}); + +# https://heycam.github.io/webidl/#idl-operations +struct( IDLOperation => { + name => '$', + type => 'IDLType', # Return type + arguments => '@', # List of 'IDLArgument' isStatic => '$', - signature => '$', # Return type/Object name/extended attributes - parameters => '@', # List of 'domSignature' + specials => '@', + extendedAttributes => '$', }); -# Used to represent domInterface contents (name of attribute, signature) -struct( domAttribute => { - type => '$', # Attribute type (including namespace) + +# https://heycam.github.io/webidl/#idl-attributes +struct( IDLAttribute => { + name => '$', + type => 'IDLType', isStatic => '$', + isStringifier => '$', isReadOnly => '$', - signature => '$', # Attribute signature + extendedAttributes => '$', +}); + +# https://heycam.github.io/webidl/#idl-iterable +struct( IDLIterable => { + isKeyValue => '$', + keyType => 'IDLType', + valueType => 'IDLType', + functions => '@', # Iterable functions (entries, keys, values, [Symbol.Iterator], forEach) + extendedAttributes => '$', +}); + +# https://heycam.github.io/webidl/#idl-serializers +struct( IDLSerializable => { + attributes => '@', # List of attributes to serialize + hasAttribute => '$', # serializer = { attribute } + hasInherit => '$', # serializer = { inherit } + hasGetter => '$', # serializer = { getter } + functions => '@', # toJSON function +}); + +# https://heycam.github.io/webidl/#idl-constants +struct( IDLConstant => { + name => '$', + type => 'IDLType', + value => '$', + extendedAttributes => '$', +}); + +# https://heycam.github.io/webidl/#idl-enums +struct( IDLEnum => { + name => '$', + type => 'IDLType', + values => '@', + extendedAttributes => '$', +}); + +# https://heycam.github.io/webidl/#dfn-dictionary-member +struct( IDLDictionaryMember => { + name => '$', + type => 'IDLType', + isRequired => '$', + default => '$', + extendedAttributes => '$', }); -# Used to represent a map of 'variable name' <-> 'variable type' -struct( domSignature => { - direction => '$', # Variable direction (in or out) - name => '$', # Variable name - type => '$', # Variable type - specials => '@', # Specials - extendedAttributes => '$', # Extended attributes - isNullable => '$', # Is variable type Nullable (T?) - isVariadic => '$', # Is variable variadic (long... numbers) - isOptional => '$', # Is variable optional (optional T) +# https://heycam.github.io/webidl/#idl-dictionaries +struct( IDLDictionary => { + type => 'IDLType', + parentType => 'IDLType', + members => '@', # List of 'IDLDictionaryMember' + extendedAttributes => '$', }); -# Used to represent string constants -struct( domConstant => { - name => '$', # DOM Constant identifier - type => '$', # Type of data - value => '$', # Constant value - extendedAttributes => '$', # Extended attributes +# https://heycam.github.io/webidl/#idl-callback-functions +struct( IDLCallbackFunction => { + type => '$', + operation => 'IDLOperation', + extendedAttributes => '$', }); -# Used to represent 'enum' definitions -struct( domEnum => { - name => '$', # Enumeration identifier - values => '@', # Enumeration values (list of unique strings) +# https://heycam.github.io/webidl/#idl-typedefs +struct( IDLTypedef => { + type => 'IDLType', }); struct( Token => { @@ -103,11 +170,6 @@ struct( Token => { value => '$' # value of token }); -struct( Typedef => { - extendedAttributes => '$', # Extended attributes - type => '$', # Type of data -}); - # Maps 'typedef name' -> Typedef my %typedefs = (); @@ -129,17 +191,28 @@ sub new { return bless $self, $class; } +sub assert +{ + my $message = shift; + + my $mess = longmess(); + print Dumper($mess); + + die $message; +} + 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}; + my $msg = "Next token should be " . $value . ", but " . $token->value() . " on line " . $self->{Line}; if (defined ($line)) { $msg .= " IDLParser.pm:" . $line; } - die $msg unless $token->value() eq $value; + + assert $msg unless $token->value() eq $value; } sub assertTokenType @@ -147,7 +220,8 @@ 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; + + assert "Next token's type should be " . $type . ", but " . $token->type() . " on line " . $self->{Line} unless $token->type() eq $type; } sub assertUnexpectedToken @@ -155,11 +229,12 @@ sub assertUnexpectedToken my $self = shift; my $token = shift; my $line = shift; - my $msg = "Unexpected token " . $token . " at " . $self->{Line}; + my $msg = "Unexpected token " . $token . " on line " . $self->{Line}; if (defined ($line)) { $msg .= " IDLParser.pm:" . $line; } - die $msg; + + assert $msg; } sub assertNoExtendedAttributesInTypedef @@ -168,11 +243,12 @@ sub assertNoExtendedAttributesInTypedef my $name = shift; my $line = shift; my $typedef = $typedefs{$name}; - my $msg = "Unexpected extendedAttributeList in typedef \"$name\" at " . $self->{Line}; + my $msg = "Unexpected extendedAttributeList in typedef \"$name\" on line " . $self->{Line}; if (defined ($line)) { $msg .= " IDLParser.pm:" . $line; } - die $msg if %{$typedef->extendedAttributes}; + + assert $msg if %{$typedef->extendedAttributes}; } sub Parse @@ -196,15 +272,19 @@ sub Parse my $next = $self->nextToken(); $self->assertTokenType($next, EmptyToken); }; - die $@ . " in $fileName" if $@; + assert $@ . " in $fileName" if $@; - my $document = idlDocument->new(); + my $document = IDLDocument->new(); $document->fileName($fileName); foreach my $definition (@definitions) { - if (ref($definition) eq "domInterface") { + if (ref($definition) eq "IDLInterface") { push(@{$document->interfaces}, $definition); - } elsif (ref($definition) eq "domEnum") { + } elsif (ref($definition) eq "IDLEnum") { push(@{$document->enumerations}, $definition); + } elsif (ref($definition) eq "IDLDictionary") { + push(@{$document->dictionaries}, $definition); + } elsif (ref($definition) eq "IDLCallbackFunction") { + push(@{$document->callbackFunctions}, $definition); } else { die "Unrecognized IDL definition kind: \"" . ref($definition) . "\""; } @@ -231,7 +311,7 @@ my $floatTokenPattern = '^(-?(([0-9]+\.[0-9]*|[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])'; +my $otherTokenPattern = '^(\.\.\.|[^\t\n\r 0-9A-Z_a-z])'; sub getTokenInternal { @@ -296,51 +376,75 @@ sub unquoteString die "Failed to parse string (" . $quotedString . ") at " . $self->{Line}; } -sub typeHasNullableSuffix +sub identifierRemoveNullablePrefix { my $type = shift; - return $type =~ /\?$/; + $type =~ s/^_//; + return $type; } -sub typeRemoveNullableSuffix +sub typeDescription { my $type = shift; - $type =~ s/\?//g; + + if (scalar @{$type->subtypes}) { + return $type->name . '<' . join(', ', map { typeDescription($_) } @{$type->subtypes}) . '>' . ($type->isNullable ? "?" : ""); + } + + return $type->name . ($type->isNullable ? "?" : ""); +} + +sub makeSimpleType +{ + my $typeName = shift; + + my $type = IDLType->new(); + $type->name($typeName); + return $type; } -sub identifierRemoveNullablePrefix +sub cloneType { + my $self = shift; my $type = shift; - $type =~ s/^_//; - return $type; + + my $clonedType = IDLType->new(); + $clonedType->name($type->name); + $clonedType->isNullable($type->isNullable); + $clonedType->isUnion($type->isUnion); + foreach my $subtype (@{$type->subtypes}) { + push(@{$clonedType->subtypes}, $self->cloneType($subtype)); + } + + return $clonedType; } my $nextAttribute_1 = '^(attribute|inherit|readonly)$'; my $nextPrimitiveType_1 = '^(int|long|short|unsigned)$'; my $nextPrimitiveType_2 = '^(double|float|unrestricted)$'; -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 $nextInterfaceMember_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 $nextArgumentList_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|double|float|in|long|object|octet|optional|sequence|short|unrestricted|unsigned)$'; +my $nextNonAnyType_1 = '^(boolean|byte|double|float|long|octet|short|unrestricted|unsigned)$'; +my $nextStringType_1 = '^(ByteString|DOMString|USVString)$'; +my $nextInterfaceMember_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$'; +my $nextAttributeOrOperation_1 = '^(static|stringifier)$'; +my $nextAttributeOrOperation_2 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|creator|deleter|double|float|getter|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 $nextExtendedAttributeRest3_1 = '^(\,|\])$'; +my $nextExceptionField_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$'; +my $nextType_1 = '^(ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|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 $nextDefinitions_1 = '^(callback|dictionary|enum|exception|interface|partial|typedef)$'; +my $nextExceptionMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|const|double|float|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 $nextInterfaceMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|const|creator|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$'; +my $nextSingleType_1 = '^(ByteString|DOMString|USVString|Date|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$'; 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 $nextAttributeOrOperationRest_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned|void)$'; +my $nextUnsignedIntegerType_1 = '^(long|short)$'; my $nextDefaultValue_1 = '^(-|Infinity|NaN|false|null|true)$'; @@ -374,59 +478,71 @@ sub applyTypedefs if (!%typedefs) { return; } + + # FIXME: Add support for applying typedefs to IDLIterable. foreach my $definition (@$definitions) { - if (ref($definition) eq "domInterface") { + if (ref($definition) eq "IDLInterface") { foreach my $constant (@{$definition->constants}) { - if (exists $typedefs{$constant->type}) { - my $typedef = $typedefs{$constant->type}; - $self->assertNoExtendedAttributesInTypedef($constant->type, __LINE__); - $constant->type($typedef->type); - } + $constant->type($self->typeByApplyingTypedefs($constant->type)); } foreach my $attribute (@{$definition->attributes}) { - $self->applyTypedefsForSignature($attribute->signature); + $attribute->type($self->typeByApplyingTypedefs($attribute->type)); } - foreach my $function (@{$definition->functions}, @{$definition->anonymousFunctions}, @{$definition->constructors}, @{$definition->customConstructors}) { - $self->applyTypedefsForSignature($function->signature); - foreach my $signature (@{$function->parameters}) { - $self->applyTypedefsForSignature($signature); - } + foreach my $operation (@{$definition->functions}, @{$definition->anonymousFunctions}, @{$definition->constructors}, @{$definition->customConstructors}) { + $self->applyTypedefsToOperation($operation); } + } elsif (ref($definition) eq "IDLDictionary") { + foreach my $member (@{$definition->members}) { + $member->type($self->typeByApplyingTypedefs($member->type)); + } + } elsif (ref($definition) eq "IDLCallbackFunction") { + $self->applyTypedefsToOperation($definition->operation); } } } -sub applyTypedefsForSignature +sub applyTypedefsToOperation { my $self = shift; - my $signature = shift; + my $operation = shift; - if (!defined ($signature->type)) { - return; + if ($operation->type) { + $operation->type($self->typeByApplyingTypedefs($operation->type)); } - my $type = $signature->type; - $type =~ s/[\?\[\]]+$//g; - my $typeSuffix = $signature->type; - $typeSuffix =~ s/^[^\?\[\]]+//g; - if (exists $typedefs{$type}) { - my $typedef = $typedefs{$type}; - $signature->type($typedef->type . $typeSuffix); - copyExtendedAttributes($signature->extendedAttributes, $typedef->extendedAttributes); + foreach my $argument (@{$operation->arguments}) { + $argument->type($self->typeByApplyingTypedefs($argument->type)); } +} - # Handle union types, sequences and etc. - foreach my $name (%typedefs) { - if (!exists $typedefs{$name}) { - next; +sub typeByApplyingTypedefs +{ + my $self = shift; + my $type = shift; + + assert("Missing type") if !$type; + + my $numberOfSubtypes = scalar @{$type->subtypes}; + if ($numberOfSubtypes) { + for my $i (0..$numberOfSubtypes - 1) { + my $subtype = @{$type->subtypes}[$i]; + my $replacementSubtype = $self->typeByApplyingTypedefs($subtype); + @{$type->subtypes}[$i] = $replacementSubtype } - my $typedef = $typedefs{$name}; - my $regex = '\\b' . $name . '\\b'; - my $replacement = $typedef->type; - my $type = $signature->type; - $type =~ s/($regex)/$replacement/g; - $signature->type($type); + + return $type; } + + if (exists $typedefs{$type->name}) { + my $typedef = $typedefs{$type->name}; + + my $clonedType = $self->cloneType($typedef->type); + $clonedType->isNullable($clonedType->isNullable || $type->isNullable); + + return $self->typeByApplyingTypedefs($clonedType); + } + + return $type; } sub parseDefinition @@ -453,7 +569,7 @@ sub parseDefinition if ($next->value() eq "typedef") { return $self->parseTypedef($extendedAttributeList); } - if ($next->type() == IdentifierToken || $next->value() eq "::") { + if ($next->type() == IdentifierToken) { return $self->parseImplementsStatement($extendedAttributeList); } $self->assertUnexpectedToken($next->value(), __LINE__); @@ -499,14 +615,20 @@ sub parseInterface my $next = $self->nextToken(); if ($next->value() eq "interface") { - my $interface = domInterface->new(); + my $interface = IDLInterface->new(); $self->assertTokenValue($self->getToken(), "interface", __LINE__); my $interfaceNameToken = $self->getToken(); $self->assertTokenType($interfaceNameToken, IdentifierToken); - $interface->name(identifierRemoveNullablePrefix($interfaceNameToken->value())); - my $parents = $self->parseInheritance(); - $interface->parents($parents); - $interface->parent($parents->[0]); + + my $name = identifierRemoveNullablePrefix($interfaceNameToken->value()); + $interface->type(makeSimpleType($name)); + + $next = $self->nextToken(); + if ($next->value() eq ":") { + my $parent = $self->parseInheritance(); + $interface->parentType(makeSimpleType($parent)); + } + $self->assertTokenValue($self->getToken(), "{", __LINE__); my $interfaceMembers = $self->parseInterfaceMembers(); $self->assertTokenValue($self->getToken(), "}", __LINE__); @@ -610,14 +732,27 @@ sub parseDictionary my $next = $self->nextToken(); if ($next->value() eq "dictionary") { + my $dictionary = IDLDictionary->new(); + $dictionary->extendedAttributes($extendedAttributeList); $self->assertTokenValue($self->getToken(), "dictionary", __LINE__); - $self->assertTokenType($self->getToken(), IdentifierToken); - $self->parseInheritance(); + + my $nameToken = $self->getToken(); + $self->assertTokenType($nameToken, IdentifierToken); + + my $name = $nameToken->value(); + $dictionary->type(makeSimpleType($name)); + + $next = $self->nextToken(); + if ($next->value() eq ":") { + my $parent = $self->parseInheritance(); + $dictionary->parentType(makeSimpleType($parent)); + } + $self->assertTokenValue($self->getToken(), "{", __LINE__); - $self->parseDictionaryMembers(); + $dictionary->members($self->parseDictionaryMembers()); $self->assertTokenValue($self->getToken(), "}", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); - return; + return $dictionary; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -626,15 +761,19 @@ sub parseDictionaryMembers { my $self = shift; + my @members = (); + while (1) { my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty(); my $next = $self->nextToken(); if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) { - $self->parseDictionaryMember($extendedAttributeList); + push(@members, $self->parseDictionaryMember($extendedAttributeList)); } else { last; } } + + return \@members; } sub parseDictionaryMember @@ -644,11 +783,24 @@ sub parseDictionaryMember my $next = $self->nextToken(); if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) { - $self->parseType(); - $self->assertTokenType($self->getToken(), IdentifierToken); - $self->parseDefault(); + my $member = IDLDictionaryMember->new(); + if ($next->value eq "required") { + $self->assertTokenValue($self->getToken(), "required", __LINE__); + $member->isRequired(1); + } else { + $member->isRequired(0); + } + $member->extendedAttributes($extendedAttributeList); + + my $type = $self->parseType(); + $member->type($type); + + my $nameToken = $self->getToken(); + $self->assertTokenType($nameToken, IdentifierToken); + $member->name($nameToken->value); + $member->default($self->parseDefault()); $self->assertTokenValue($self->getToken(), ";", __LINE__); - return; + return $member; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -677,6 +829,7 @@ sub parseDefault $self->assertTokenValue($self->getToken(), "=", __LINE__); return $self->parseDefaultValue(); } + return undef; } sub parseDefaultValue @@ -689,6 +842,11 @@ sub parseDefaultValue if ($next->type() == StringToken) { return $self->getToken()->value(); } + if ($next->value() eq "[") { + $self->assertTokenValue($self->getToken(), "[", __LINE__); + $self->assertTokenValue($self->getToken(), "]", __LINE__); + return "[]"; + } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -699,15 +857,21 @@ sub parseException my $next = $self->nextToken(); if ($next->value() eq "exception") { - my $interface = domInterface->new(); + my $interface = IDLInterface->new(); $self->assertTokenValue($self->getToken(), "exception", __LINE__); my $exceptionNameToken = $self->getToken(); $self->assertTokenType($exceptionNameToken, IdentifierToken); - $interface->name(identifierRemoveNullablePrefix($exceptionNameToken->value())); + + my $name = identifierRemoveNullablePrefix($exceptionNameToken->value()); + $interface->type(makeSimpleType($name)); $interface->isException(1); - my $parents = $self->parseInheritance(); - $interface->parents($parents); - $interface->parent($parents->[0]); + + $next = $self->nextToken(); + if ($next->value() eq ":") { + my $parent = $self->parseInheritance(); + $interface->parentType(makeSimpleType($parent)); + } + $self->assertTokenValue($self->getToken(), "{", __LINE__); my $exceptionMembers = $self->parseExceptionMembers(); $self->assertTokenValue($self->getToken(), "}", __LINE__); @@ -743,35 +907,34 @@ sub parseExceptionMembers 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 (needed for ObjC bindings). - push(@parent, @{$self->parseIdentifiers()}); + return $self->parseName(); } - return \@parent; + $self->assertUnexpectedToken($next->value(), __LINE__); } sub parseEnum { my $self = shift; - my $extendedAttributeList = shift; # ignored: Extended attributes are not applicable to enumerations + my $extendedAttributeList = shift; my $next = $self->nextToken(); if ($next->value() eq "enum") { - my $enum = domEnum->new(); + my $enum = IDLEnum->new(); $self->assertTokenValue($self->getToken(), "enum", __LINE__); my $enumNameToken = $self->getToken(); $self->assertTokenType($enumNameToken, IdentifierToken); - $enum->name(identifierRemoveNullablePrefix($enumNameToken->value())); + my $name = identifierRemoveNullablePrefix($enumNameToken->value()); + $enum->name($name); + $enum->type(makeSimpleType($name)); $self->assertTokenValue($self->getToken(), "{", __LINE__); push(@{$enum->values}, @{$self->parseEnumValueList()}); $self->assertTokenValue($self->getToken(), "}", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); + $enum->extendedAttributes($extendedAttributeList); return $enum; } $self->assertUnexpectedToken($next->value(), __LINE__); @@ -818,14 +981,30 @@ sub parseCallbackRest my $next = $self->nextToken(); if ($next->type() == IdentifierToken) { - $self->assertTokenType($self->getToken(), IdentifierToken); + my $callback = IDLCallbackFunction->new(); + + my $nameToken = $self->getToken(); + $self->assertTokenType($nameToken, IdentifierToken); + + $callback->type(makeSimpleType($nameToken->value())); + $self->assertTokenValue($self->getToken(), "=", __LINE__); - $self->parseReturnType(); + + my $operation = IDLOperation->new(); + $operation->type($self->parseReturnType()); + $operation->extendedAttributes($extendedAttributeList); + $self->assertTokenValue($self->getToken(), "(", __LINE__); - $self->parseArgumentList(); + + push(@{$operation->arguments}, @{$self->parseArgumentList()}); + $self->assertTokenValue($self->getToken(), ")", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); - return; + + $callback->operation($operation); + $callback->extendedAttributes($extendedAttributeList); + + return $callback; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -839,14 +1018,16 @@ sub parseTypedef my $next = $self->nextToken(); if ($next->value() eq "typedef") { $self->assertTokenValue($self->getToken(), "typedef", __LINE__); - my $typedef = Typedef->new(); - $typedef->extendedAttributes($self->parseExtendedAttributeListAllowEmpty()); - $typedef->type($self->parseType()); + my $typedef = IDLTypedef->new(); + + my $type = $self->parseType(); + $typedef->type($type); + my $nameToken = $self->getToken(); $self->assertTokenType($nameToken, IdentifierToken); $self->assertTokenValue($self->getToken(), ";", __LINE__); my $name = $nameToken->value(); - die "typedef redefinition for " . $name . " at " . $self->{Line} if (exists $typedefs{$name} && $typedef->type ne $typedefs{$name}->type); + die "typedef redefinition for " . $name . " at " . $self->{Line} if (exists $typedefs{$name} && $typedef->type->name ne $typedefs{$name}->type->name); $typedefs{$name} = $typedef; return; } @@ -860,9 +1041,9 @@ sub parseImplementsStatement my $next = $self->nextToken(); if ($next->type() == IdentifierToken) { - $self->parseScopedName(); + $self->parseName(); $self->assertTokenValue($self->getToken(), "implements", __LINE__); - $self->parseScopedName(); + $self->parseName(); $self->assertTokenValue($self->getToken(), ";", __LINE__); return; } @@ -876,9 +1057,10 @@ sub parseConst my $next = $self->nextToken(); if ($next->value() eq "const") { - my $newDataNode = domConstant->new(); + my $newDataNode = IDLConstant->new(); $self->assertTokenValue($self->getToken(), "const", __LINE__); - $newDataNode->type($self->parseConstType()); + my $type = $self->parseConstType(); + $newDataNode->type($type); my $constNameToken = $self->getToken(); $self->assertTokenType($constNameToken, IdentifierToken); $newDataNode->name(identifierRemoveNullablePrefix($constNameToken->value())); @@ -905,10 +1087,6 @@ sub parseConstValue 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(); } @@ -962,18 +1140,19 @@ sub parseAttributeOrOperationOrIterator if ($next->value() eq "serializer") { return $self->parseSerializer($extendedAttributeList); } - if ($next->value() =~ /$nextAttributeOrOperationOrIterator_1/) { + if ($next->value() =~ /$nextAttributeOrOperation_1/) { my $qualifier = $self->parseQualifier(); my $newDataNode = $self->parseAttributeOrOperationRest($extendedAttributeList); - if (defined($newDataNode) && $qualifier eq "static") { - $newDataNode->isStatic(1); + if (defined($newDataNode)) { + $newDataNode->isStatic(1) if $qualifier eq "static"; + $newDataNode->isStringifier(1) if $qualifier eq "stringifier"; } return $newDataNode; } if ($next->value() =~ /$nextAttribute_1/) { return $self->parseAttribute($extendedAttributeList); } - if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationOrIterator_2/) { + if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperation_2/) { return $self->parseOperationOrIterator($extendedAttributeList); } $self->assertUnexpectedToken($next->value(), __LINE__); @@ -987,7 +1166,22 @@ sub parseSerializer my $next = $self->nextToken(); if ($next->value() eq "serializer") { $self->assertTokenValue($self->getToken(), "serializer", __LINE__); - return $self->parseSerializerRest($extendedAttributeList); + my $next = $self->nextToken(); + my $newDataNode; + if ($next->value() ne ";") { + $newDataNode = $self->parseSerializerRest($extendedAttributeList); + my $next = $self->nextToken(); + } else { + $newDataNode = IDLSerializable->new(); + } + + my $toJSONFunction = IDLOperation->new(); + $toJSONFunction->name("toJSON"); + $toJSONFunction->extendedAttributes($extendedAttributeList); + push(@{$newDataNode->functions}, $toJSONFunction); + + $self->assertTokenValue($self->getToken(), ";", __LINE__); + return $newDataNode; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1000,7 +1194,9 @@ sub parseSerializerRest my $next = $self->nextToken(); if ($next->value() eq "=") { $self->assertTokenValue($self->getToken(), "=", __LINE__); - return $self->parseSerializationPattern($extendedAttributeList); + + return $self->parseSerializationPattern(); + } if ($next->type() == IdentifierToken || $next->value() eq "(") { return $self->parseOperationRest($extendedAttributeList); @@ -1010,59 +1206,74 @@ sub parseSerializerRest sub parseSerializationPattern { my $self = shift; - my $extendedAttributeList = shift; my $next = $self->nextToken(); if ($next->value() eq "{") { $self->assertTokenValue($self->getToken(), "{", __LINE__); - $self->parseSerializationPatternMap(); + my $newDataNode = IDLSerializable->new(); + $self->parseSerializationAttributes($newDataNode); $self->assertTokenValue($self->getToken(), "}", __LINE__); - return; + return $newDataNode; } if ($next->value() eq "[") { - $self->assertTokenValue($self->getToken(), "[", __LINE__); - $self->parseSerializationPatternList(); - $self->assertTokenValue($self->getToken(), "]", __LINE__); - return; + die "Serialization of lists pattern is not currently supported."; } if ($next->type() == IdentifierToken) { - $self->assertTokenType($self->getToken(), IdentifierToken); - return; + my @attributes = (); + my $token = $self->getToken(); + $self->assertTokenType($token, IdentifierToken); + push(@attributes, $token->value()); + + my $newDataNode = IDLSerializable->new(); + $newDataNode->attributes(\@attributes); + + return $newDataNode; } $self->assertUnexpectedToken($next->value(), __LINE__); } -sub parseSerializationPatternMap +sub parseSerializationAttributes { 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(); + my $serializable = shift; + + my @attributes = (); + my @identifiers = $self->parseIdentifierList(); + + for my $identifier (@identifiers) { + if ($identifier eq "getter") { + $serializable->hasGetter(1); + die "Serializer getter keyword is not currently supported."; + } + + if ($identifier eq "inherit") { + $serializable->hasInherit(1); + next; + } + + if ($identifier eq "attribute") { + $serializable->hasAttribute(1); + # Attributes will be filled in via applyMemberList() + next; + } + + push(@attributes, $identifier); } + + $serializable->attributes(\@attributes); } -sub parseSerializationPatternList +sub parseIdentifierList { 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(); + + my @identifiers = (); + if ($next->type == IdentifierToken) { + push(@identifiers, $self->getToken()->value()); + push(@identifiers, @{$self->parseIdentifiers()}); } + return @identifiers; } sub parseIdentifiers @@ -1115,11 +1326,11 @@ sub parseAttributeOrOperationRest } if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) { my $returnType = $self->parseReturnType(); - my $interface = $self->parseOperationRest($extendedAttributeList); - if (defined ($interface)) { - $interface->signature->type($returnType); + my $operation = $self->parseOperationRest($extendedAttributeList); + if (defined ($operation)) { + $operation->type($returnType); } - return $interface; + return $operation; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1144,33 +1355,25 @@ sub parseAttributeRest my $next = $self->nextToken(); if ($next->value() =~ /$nextAttributeRest_1/) { - my $newDataNode = domAttribute->new(); - if ($self->parseReadOnly()) { - $newDataNode->type("attribute"); - $newDataNode->isReadOnly(1); - } else { - $newDataNode->type("attribute"); - } + my $newDataNode = IDLAttribute->new(); + $newDataNode->isReadOnly($self->parseReadOnly()); + $self->assertTokenValue($self->getToken(), "attribute", __LINE__); - $newDataNode->signature(domSignature->new()); + my $type = $self->parseType(); - if (typeHasNullableSuffix($type)) { - $newDataNode->signature->isNullable(1); - } else { - $newDataNode->signature->isNullable(0); - } - # Remove all "?" in the type declaration, e.g. "double?" -> "double". - $newDataNode->signature->type(typeRemoveNullableSuffix($type)); + $newDataNode->type($type); + my $token = $self->getToken(); $self->assertTokenType($token, IdentifierToken); - $newDataNode->signature->name(identifierRemoveNullablePrefix($token->value())); + $newDataNode->name(identifierRemoveNullablePrefix($token->value())); $self->assertTokenValue($self->getToken(), ";", __LINE__); + # CustomConstructor may also be used on attributes. if (defined $extendedAttributeList->{"CustomConstructors"}) { delete $extendedAttributeList->{"CustomConstructors"}; $extendedAttributeList->{"CustomConstructor"} = "VALUE_IS_MISSING"; } - $newDataNode->signature->extendedAttributes($extendedAttributeList); + $newDataNode->extendedAttributes($extendedAttributeList); return $newDataNode; } $self->assertUnexpectedToken($next->value(), __LINE__); @@ -1207,13 +1410,17 @@ sub parseOperationOrIterator if ($next->value() =~ /$nextSpecials_1/) { return $self->parseSpecialOperation($extendedAttributeList); } + if ($next->value() eq "iterable") { + return $self->parseIterableRest($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); + my $next = $self->nextToken(); + if ($next->type() == IdentifierToken || $next->value() eq "(") { + my $operation = $self->parseOperationRest($extendedAttributeList); + $operation->type($returnType); + return $operation; } - return $interface; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1228,12 +1435,12 @@ sub parseSpecialOperation my @specials = (); push(@specials, @{$self->parseSpecials()}); my $returnType = $self->parseReturnType(); - my $interface = $self->parseOperationRest($extendedAttributeList); - if (defined ($interface)) { - $interface->signature->type($returnType); - $interface->signature->specials(\@specials); + my $operation = $self->parseOperationRest($extendedAttributeList); + if (defined ($operation)) { + $operation->type($returnType); + $operation->specials(\@specials); } - return $interface; + return $operation; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1281,62 +1488,75 @@ sub parseSpecial $self->assertUnexpectedToken($next->value(), __LINE__); } -sub parseOperationOrIteratorRest +sub parseIterableRest { 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); + if ($next->value() eq "iterable") { + $self->assertTokenValue($self->getToken(), "iterable", __LINE__); + my $iterableNode = $self->parseOptionalIterableInterface($extendedAttributeList); $self->assertTokenValue($self->getToken(), ";", __LINE__); - return; + return $iterableNode; } $self->assertUnexpectedToken($next->value(), __LINE__); } -sub parseOptionalIteratorInterfaceOrObject +sub parseOptionalIterableInterface { 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 $symbolIteratorFunction = IDLOperation->new(); + $symbolIteratorFunction->name("[Symbol.Iterator]"); + $symbolIteratorFunction->extendedAttributes($extendedAttributeList); + + my $entriesFunction = IDLOperation->new(); + $entriesFunction->name("entries"); + $entriesFunction->extendedAttributes($extendedAttributeList); + + my $keysFunction = IDLOperation->new(); + $keysFunction->name("keys"); + $keysFunction->extendedAttributes($extendedAttributeList); + + my $valuesFunction = IDLOperation->new(); + $valuesFunction->name("values"); + $valuesFunction->extendedAttributes($extendedAttributeList); + + my $forEachFunction = IDLOperation->new(); + $forEachFunction->name("forEach"); + $forEachFunction->extendedAttributes($extendedAttributeList); + my $forEachArgument = IDLArgument->new(); + $forEachArgument->name("callback"); + $forEachArgument->type(makeSimpleType("any")); + push(@{$forEachFunction->arguments}, ($forEachArgument)); + + my $newDataNode = IDLIterable->new(); + $newDataNode->extendedAttributes($extendedAttributeList); + push(@{$newDataNode->functions}, $symbolIteratorFunction); + push(@{$newDataNode->functions}, $entriesFunction); + push(@{$newDataNode->functions}, $keysFunction); + push(@{$newDataNode->functions}, $valuesFunction); + push(@{$newDataNode->functions}, $forEachFunction); + + $self->assertTokenValue($self->getToken(), "<", __LINE__); + my $type1 = $self->parseType(); + + if ($self->nextToken()->value() eq ",") { + $self->assertTokenValue($self->getToken(), ",", __LINE__); - my $next = $self->nextToken(); - if ($next->value() eq "=") { - $self->assertTokenValue($self->getToken(), "=", __LINE__); - $self->assertTokenType($self->getToken(), IdentifierToken); + my $type2 = $self->parseType(); + $newDataNode->isKeyValue(1); + $newDataNode->keyType($type1); + $newDataNode->valueType($type2); + } else { + $newDataNode->isKeyValue(0); + $newDataNode->valueType($type1); } + $self->assertTokenValue($self->getToken(), ">", __LINE__); + + return $newDataNode; } sub parseOperationRest @@ -1346,15 +1566,19 @@ sub parseOperationRest my $next = $self->nextToken(); if ($next->type() == IdentifierToken || $next->value() eq "(") { - my $newDataNode = domFunction->new(); - $newDataNode->signature(domSignature->new()); + my $newDataNode = IDLOperation->new(); + my $name = $self->parseOptionalIdentifier(); - $newDataNode->signature->name(identifierRemoveNullablePrefix($name)); + $newDataNode->name(identifierRemoveNullablePrefix($name)); + $self->assertTokenValue($self->getToken(), "(", $name, __LINE__); - push(@{$newDataNode->parameters}, @{$self->parseArgumentList()}); + + push(@{$newDataNode->arguments}, @{$self->parseArgumentList()}); + $self->assertTokenValue($self->getToken(), ")", __LINE__); $self->assertTokenValue($self->getToken(), ";", __LINE__); - $newDataNode->signature->extendedAttributes($extendedAttributeList); + + $newDataNode->extendedAttributes($extendedAttributeList); return $newDataNode; } $self->assertUnexpectedToken($next->value(), __LINE__); @@ -1406,10 +1630,8 @@ 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__); @@ -1420,36 +1642,23 @@ sub parseOptionalOrRequiredArgument my $self = shift; my $extendedAttributeList = shift; - my $paramDataNode = domSignature->new(); + my $paramDataNode = IDLArgument->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 (typeHasNullableSuffix($type)) { - $paramDataNode->isNullable(1); - } else { - $paramDataNode->isNullable(0); - } - # Remove all "?" if exists, e.g. "object?[]?" -> "object[]". - $paramDataNode->type(identifierRemoveNullablePrefix(typeRemoveNullableSuffix($type))); + $paramDataNode->type($type); $paramDataNode->isOptional(1); $paramDataNode->name($self->parseArgumentName()); - $self->parseDefault(); + $paramDataNode->default($self->parseDefault()); return $paramDataNode; } if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) { my $type = $self->parseType(); - # domDataNode can only consider last "?". - if (typeHasNullableSuffix($type)) { - $paramDataNode->isNullable(1); - } else { - $paramDataNode->isNullable(0); - } - # Remove all "?" if exists, e.g. "object?[]?" -> "object[]". - $paramDataNode->type(typeRemoveNullableSuffix($type)); + $paramDataNode->type($type); $paramDataNode->isOptional(0); $paramDataNode->isVariadic($self->parseEllipsis()); $paramDataNode->name($self->parseArgumentName()); @@ -1504,16 +1713,17 @@ sub parseExceptionField my $next = $self->nextToken(); if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) { - my $newDataNode = domAttribute->new(); - $newDataNode->type("attribute"); + my $newDataNode = IDLAttribute->new(); $newDataNode->isReadOnly(1); - $newDataNode->signature(domSignature->new()); - $newDataNode->signature->type($self->parseType()); + + my $type = $self->parseType(); + $newDataNode->type($type); + my $token = $self->getToken(); $self->assertTokenType($token, IdentifierToken); - $newDataNode->signature->name(identifierRemoveNullablePrefix($token->value())); + $newDataNode->name(identifierRemoveNullablePrefix($token->value())); $self->assertTokenValue($self->getToken(), ";", __LINE__); - $newDataNode->signature->extendedAttributes($extendedAttributeList); + $newDataNode->extendedAttributes($extendedAttributeList); return $newDataNode; } $self->assertUnexpectedToken($next->value(), __LINE__); @@ -1594,9 +1804,9 @@ sub parseExtendedAttribute { my $self = shift; my $next = $self->nextToken(); - if ($next->type() == IdentifierToken || $next->value() eq "::") { - my $scopedName = $self->parseScopedName(); - return $self->parseExtendedAttributeRest($scopedName); + if ($next->type() == IdentifierToken) { + my $name = $self->parseName(); + return $self->parseExtendedAttributeRest($name); } # backward compatibility. Spec doesn' allow "[]". But WebKit requires. if ($next->value() eq ']') { @@ -1609,9 +1819,9 @@ sub parseExtendedAttribute2 { my $self = shift; my $next = $self->nextToken(); - if ($next->type() == IdentifierToken || $next->value() eq "::") { - my $scopedName = $self->parseScopedName(); - return $self->parseExtendedAttributeRest($scopedName); + if ($next->type() == IdentifierToken) { + my $name = $self->parseName(); + return $self->parseExtendedAttributeRest($name); } return {}; } @@ -1647,9 +1857,15 @@ 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->value() eq "(") { + $self->assertTokenValue($self->getToken(), "(", __LINE__); + my @arguments = $self->parseIdentifierList(); + $self->assertTokenValue($self->getToken(), ")", __LINE__); + return @arguments; + } + if ($next->type() == IdentifierToken) { + my $name = $self->parseName(); + return $self->parseExtendedAttributeRest3($name); } if ($next->type() == IntegerToken) { my $token = $self->getToken(); @@ -1666,12 +1882,12 @@ sub parseExtendedAttributeRest3 my $next = $self->nextToken(); if ($next->value() eq "&") { $self->assertTokenValue($self->getToken(), "&", __LINE__); - my $rightValue = $self->parseScopedName(); + my $rightValue = $self->parseName(); return $name . "&" . $rightValue; } if ($next->value() eq "|") { $self->assertTokenValue($self->getToken(), "|", __LINE__); - my $rightValue = $self->parseScopedName(); + my $rightValue = $self->parseName(); return $name . "|" . $rightValue; } if ($next->value() eq "(") { @@ -1682,30 +1898,12 @@ sub parseExtendedAttributeRest3 return $attr; } if ($next->type() == IdentifierToken || $next->value() =~ /$nextExtendedAttributeRest3_1/) { - my @names = (); - push(@names, $name); - push(@names, @{$self->parseScopedNameListNoComma()}); - return join(' ', @names); + $self->parseNameNoComma(); + return $name; } $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; @@ -1778,9 +1976,9 @@ sub parseType my $self = shift; my $next = $self->nextToken(); if ($next->value() eq "(") { - $self->parseUnionType(); - $self->parseTypeSuffix(); - return; + my $unionType = $self->parseUnionType(); + $unionType->isNullable($self->parseNull()); + return $unionType; } if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) { return $self->parseSingleType(); @@ -1794,10 +1992,15 @@ sub parseSingleType my $next = $self->nextToken(); if ($next->value() eq "any") { $self->assertTokenValue($self->getToken(), "any", __LINE__); - return "any" . $self->parseTypeSuffixStartingWithArray(); + + my $anyType = IDLType->new(); + $anyType->name("any"); + return $anyType; } if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) { - return $self->parseNonAnyType(); + my $nonAnyType = $self->parseNonAnyType(); + $nonAnyType->isNullable($self->parseNull()); + return $nonAnyType; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1806,14 +2009,20 @@ sub parseUnionType { my $self = shift; my $next = $self->nextToken(); + + my $unionType = IDLType->new(); + $unionType->name("UNION"); + $unionType->isUnion(1); + if ($next->value() eq "(") { $self->assertTokenValue($self->getToken(), "(", __LINE__); - $self->parseUnionMemberType(); - $self->assertTokenValue($self->getToken(), "or", __LINE__); - $self->parseUnionMemberType(); - $self->parseUnionMemberTypes(); + + push(@{$unionType->subtypes}, $self->parseUnionMemberType()); + push(@{$unionType->subtypes}, $self->parseUnionMemberTypes()); + $self->assertTokenValue($self->getToken(), ")", __LINE__); - return; + + return $unionType; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1823,20 +2032,14 @@ 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; + my $unionType = $self->parseUnionType(); + $unionType->isNullable($self->parseNull()); + return $unionType; } if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) { - $self->parseNonAnyType(); - return; + my $nonAnyType = $self->parseNonAnyType(); + $nonAnyType->isNullable($self->parseNull()); + return $nonAnyType; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1845,46 +2048,126 @@ sub parseUnionMemberTypes { my $self = shift; my $next = $self->nextToken(); + + my @subtypes = (); + if ($next->value() eq "or") { $self->assertTokenValue($self->getToken(), "or", __LINE__); - $self->parseUnionMemberType(); - $self->parseUnionMemberTypes(); + push(@subtypes, $self->parseUnionMemberType()); + push(@subtypes, $self->parseUnionMemberTypes()); } + + return @subtypes; } sub parseNonAnyType { my $self = shift; my $next = $self->nextToken(); + + my $type = IDLType->new(); + if ($next->value() =~ /$nextNonAnyType_1/) { - return $self->parsePrimitiveType() . $self->parseTypeSuffix(); + $type->name($self->parsePrimitiveType()); + return $type; } - if ($next->value() eq "ByteString") { - $self->assertTokenValue($self->getToken(), "ByteString", __LINE__); - return "ByteString" . $self->parseTypeSuffix(); + if ($next->value() =~ /$nextStringType_1/) { + $type->name($self->parseStringType()); + return $type; } - if ($next->value() eq "DOMString") { - $self->assertTokenValue($self->getToken(), "DOMString", __LINE__); - return "DOMString" . $self->parseTypeSuffix(); + if ($next->value() eq "object") { + $self->assertTokenValue($self->getToken(), "object", __LINE__); + + $type->name("object"); + return $type; + } + if ($next->value() eq "RegExp") { + $self->assertTokenValue($self->getToken(), "RegExp", __LINE__); + + $type->name("RegExp"); + return $type; + } + if ($next->value() eq "Error") { + $self->assertTokenValue($self->getToken(), "Error", __LINE__); + + $type->name("Error"); + return $type; + } + if ($next->value() eq "DOMException") { + $self->assertTokenValue($self->getToken(), "DOMException", __LINE__); + + $type->name("DOMException"); + return $type; + } + if ($next->value() eq "Date") { + $self->assertTokenValue($self->getToken(), "Date", __LINE__); + + $type->name("Date"); + return $type; } if ($next->value() eq "sequence") { $self->assertTokenValue($self->getToken(), "sequence", __LINE__); $self->assertTokenValue($self->getToken(), "<", __LINE__); - my $type = $self->parseType(); + + my $subtype = $self->parseType(); + $self->assertTokenValue($self->getToken(), ">", __LINE__); - return "sequence<" . $type . ">" . $self->parseNull(); + + $type->name("sequence"); + push(@{$type->subtypes}, $subtype); + + return $type; } - if ($next->value() eq "object") { - $self->assertTokenValue($self->getToken(), "object", __LINE__); - return "object" . $self->parseTypeSuffix(); + if ($next->value() eq "FrozenArray") { + $self->assertTokenValue($self->getToken(), "FrozenArray", __LINE__); + $self->assertTokenValue($self->getToken(), "<", __LINE__); + + my $subtype = $self->parseType(); + + $self->assertTokenValue($self->getToken(), ">", __LINE__); + + $type->name("FrozenArray"); + push(@{$type->subtypes}, $subtype); + + return $type; } - if ($next->value() eq "Date") { - $self->assertTokenValue($self->getToken(), "Date", __LINE__); - return "Date" . $self->parseTypeSuffix(); + if ($next->value() eq "Promise") { + $self->assertTokenValue($self->getToken(), "Promise", __LINE__); + $self->assertTokenValue($self->getToken(), "<", __LINE__); + + my $subtype = $self->parseReturnType(); + + $self->assertTokenValue($self->getToken(), ">", __LINE__); + + $type->name("Promise"); + push(@{$type->subtypes}, $subtype); + + return $type; } - if ($next->type() == IdentifierToken || $next->value() eq "::") { - my $name = identifierRemoveNullablePrefix($self->parseScopedName()); - return $name . $self->parseTypeSuffix(); + if ($next->value() eq "record") { + $self->assertTokenValue($self->getToken(), "record", __LINE__); + $self->assertTokenValue($self->getToken(), "<", __LINE__); + + my $keyType = IDLType->new(); + $keyType->name($self->parseStringType()); + + $self->assertTokenValue($self->getToken(), ",", __LINE__); + + my $valueType = $self->parseType(); + + $self->assertTokenValue($self->getToken(), ">", __LINE__); + + $type->name("record"); + push(@{$type->subtypes}, $keyType); + push(@{$type->subtypes}, $valueType); + + return $type; + } + if ($next->type() == IdentifierToken) { + my $identifier = $self->getToken(); + + $type->name(identifierRemoveNullablePrefix($identifier->value())); + return $type; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -1893,12 +2176,40 @@ sub parseConstType { my $self = shift; my $next = $self->nextToken(); + + my $type = IDLType->new(); + if ($next->value() =~ /$nextNonAnyType_1/) { - return $self->parsePrimitiveType() . $self->parseNull(); + $type->name($self->parsePrimitiveType()); + $type->isNullable($self->parseNull()); + return $type; } if ($next->type() == IdentifierToken) { - my $token = $self->getToken(); - return $token->value() . $self->parseNull(); + my $identifier = $self->getToken(); + + $type->name($identifier->value()); + $type->isNullable($self->parseNull()); + + return $type; + } + $self->assertUnexpectedToken($next->value(), __LINE__); +} + +sub parseStringType +{ + my $self = shift; + my $next = $self->nextToken(); + if ($next->value() eq "ByteString") { + $self->assertTokenValue($self->getToken(), "ByteString", __LINE__); + return "ByteString"; + } + if ($next->value() eq "DOMString") { + $self->assertTokenValue($self->getToken(), "DOMString", __LINE__); + return "DOMString"; + } + if ($next->value() eq "USVString") { + $self->assertTokenValue($self->getToken(), "USVString", __LINE__); + return "USVString"; } $self->assertUnexpectedToken($next->value(), __LINE__); } @@ -2004,43 +2315,15 @@ sub parseOptionalLong 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 1; } - return ""; + return 0; } sub parseReturnType @@ -2049,7 +2332,10 @@ sub parseReturnType my $next = $self->nextToken(); if ($next->value() eq "void") { $self->assertTokenValue($self->getToken(), "void", __LINE__); - return "void"; + + my $voidType = IDLType->new(); + $voidType->name("void"); + return $voidType; } if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) { return $self->parseType(); @@ -2057,17 +2343,6 @@ sub parseReturnType $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; @@ -2077,115 +2352,72 @@ sub parseOptionalSemicolon } } -sub parseScopedName +sub parseNameNoComma { my $self = shift; my $next = $self->nextToken(); - if ($next->value() eq "::") { - return $self->parseAbsoluteScopedName(); - } if ($next->type() == IdentifierToken) { - return $self->parseRelativeScopedName(); + my $identifier = $self->getToken(); + return ($identifier->value()); } - $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()); + return (); } -sub parseRelativeScopedName +sub parseName { my $self = shift; my $next = $self->nextToken(); if ($next->type() == IdentifierToken) { - my $token = $self->getToken(); - return $token->value() . $self->parseScopedNameParts(); + my $identifier = $self->getToken(); + return $identifier->value(); } $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") { + if (ref($item) eq "IDLAttribute") { push(@{$interface->attributes}, $item); next; } - if (ref($item) eq "domConstant") { + if (ref($item) eq "IDLConstant") { push(@{$interface->constants}, $item); next; } - if (ref($item) eq "domFunction") { - if ($item->signature->name eq "") { + if (ref($item) eq "IDLIterable") { + $interface->iterable($item); + next; + } + if (ref($item) eq "IDLOperation") { + if ($item->name eq "") { push(@{$interface->anonymousFunctions}, $item); } else { push(@{$interface->functions}, $item); } next; } + if (ref($item) eq "IDLSerializable") { + $interface->serializable($item); + next; + } + } + + if ($interface->serializable) { + my $numSerializerAttributes = @{$interface->serializable->attributes}; + if ($interface->serializable->hasAttribute) { + foreach my $attribute (@{$interface->attributes}) { + push(@{$interface->serializable->attributes}, $attribute->name); + } + } elsif ($numSerializerAttributes == 0) { + foreach my $attribute (@{$interface->attributes}) { + push(@{$interface->serializable->attributes}, $attribute->name); + } + } } } @@ -2198,25 +2430,22 @@ sub applyExtendedAttributeList 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++; + my $constructor = IDLOperation->new(); + $constructor->name("Constructor"); + $constructor->extendedAttributes($extendedAttributeList); + $constructor->arguments($param); 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 $newDataNode = IDLOperation->new(); + $newDataNode->name("NamedConstructor"); + $newDataNode->extendedAttributes($extendedAttributeList); my %attributes = %{$extendedAttributeList->{"NamedConstructor"}}; my @attributeKeys = keys (%attributes); my $constructorName = $attributeKeys[0]; - push(@{$newDataNode->parameters}, @{$attributes{$constructorName}}); + push(@{$newDataNode->arguments}, @{$attributes{$constructorName}}); $extendedAttributeList->{"NamedConstructor"} = $constructorName; push(@{$interface->constructors}, $newDataNode); } @@ -2224,12 +2453,10 @@ sub applyExtendedAttributeList my @customConstructorParams = @{$extendedAttributeList->{"CustomConstructors"}}; my $index = (@customConstructorParams == 1) ? 0 : 1; foreach my $param (@customConstructorParams) { - my $customConstructor = domFunction->new(); - $customConstructor->signature(domSignature->new()); - $customConstructor->signature->name("CustomConstructor"); - $customConstructor->signature->extendedAttributes($extendedAttributeList); - $customConstructor->parameters($param); - $customConstructor->{overloadedIndex} = $index++; + my $customConstructor = IDLOperation->new(); + $customConstructor->name("CustomConstructor"); + $customConstructor->extendedAttributes($extendedAttributeList); + $customConstructor->arguments($param); push(@{$interface->customConstructors}, $customConstructor); } delete $extendedAttributeList->{"CustomConstructors"}; |