1#
2# KDOM IDL parser
3#
4# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
5#
6# This library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Library General Public
8# License as published by the Free Software Foundation; either
9# version 2 of the License, or (at your option) any later version.
10#
11# This library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14# Library General Public License for more details.
15#
16# You should have received a copy of the GNU Library General Public License
17# along with this library; see the file COPYING.LIB.  If not, write to
18# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19# Boston, MA 02110-1301, USA.
20#
21
22package deprecated_idl_parser;
23
24use strict;
25
26use preprocessor;
27use Class::Struct;
28
29use constant StringToken => 0;
30use constant IntegerToken => 1;
31use constant FloatToken => 2;
32use constant IdentifierToken => 3;
33use constant OtherToken => 4;
34use constant EmptyToken => 5;
35
36# Used to represent a parsed IDL document
37struct( idlDocument => {
38    fileName => '$', # file name
39    callbackFunctions => '@',
40    enumerations => '@', # All parsed enumerations
41    interfaces => '@', # All parsed interfaces
42});
43
44struct( callbackFunction => {
45    name => '$',
46    type => '$',
47    parameters => '@',
48});
49
50# Used to represent 'interface' blocks
51struct( domInterface => {
52    name => '$',      # Class identifier
53    parent => '$',      # Parent class identifier
54    constants => '@',    # List of 'domConstant'
55    functions => '@',    # List of 'domFunction'
56    attributes => '@',    # List of 'domAttribute'
57    extendedAttributes => '$', # Extended attributes
58    constructors => '@', # Constructors, list of 'domFunction'
59    customConstructors => '@', # Custom constructors, list of 'domFunction'
60    isException => '$', # Used for exception interfaces
61    isCallback => '$', # Used for callback interfaces
62    isPartial => '$', # Used for partial interfaces
63});
64
65# Used to represent domInterface contents
66struct( domFunction => {
67    isStatic => '$',
68    name => '$',
69    type => '$',
70    extendedAttributes => '$', # Extended attributes
71    specials => '@',  # Specials
72    parameters => '@',    # List of 'domParameter'
73    overloadedIndex => '$',
74});
75
76# Used to represent domInterface contents
77struct( domAttribute => {
78    type => '$',              # Attribute type (including namespace) (string or UnionType)
79    name => '$',
80    isNullable => '$', # Is variable type Nullable (T?)
81    isStatic => '$',
82    isReadOnly => '$',
83    getterExceptions => '@',  # Possibly raised exceptions.
84    setterExceptions => '@',  # Possibly raised exceptions.
85    extendedAttributes => '$', # Extended attributes
86});
87
88# Used to represent a map of 'variable name' <-> 'variable type'
89struct( domParameter => {
90    name => '$',      # Variable name
91    type => '$',      # Variable type (string or UnionType)
92    extendedAttributes => '$', # Extended attributes
93    isOptional => '$', # Is variable optional (optional T)
94    isNullable => '$', # Is variable type Nullable (T?)
95    isVariadic => '$' # Is variable variadic (long... numbers)
96});
97
98# Used to represent string constants
99struct( domConstant => {
100    name => '$',      # DOM Constant identifier
101    type => '$',      # Type of data
102    value => '$',      # Constant value
103    extendedAttributes => '$', # Extended attributes
104});
105
106# Used to represent 'enum' definitions
107struct( domEnum => {
108    name => '$', # Enumeration identifier
109    values => '@', # Enumeration values (list of unique strings)
110});
111
112struct( Token => {
113    type => '$', # type of token
114    value => '$' # value of token
115});
116
117struct( Typedef => {
118    extendedAttributes => '$', # Extended attributes
119    type => '$', # Type of data
120});
121
122struct( UnionType => {
123    unionMemberTypes => '@', # (UnionType or string)[]
124});
125
126# Maps 'typedef name' -> Typedef
127my %typedefs = ();
128
129sub new {
130    my $class = shift;
131
132    my $emptyToken = Token->new();
133    $emptyToken->type(EmptyToken);
134    $emptyToken->value("empty");
135
136    my $self = {
137        DocumentContent => "",
138        EmptyToken => $emptyToken,
139        NextToken => $emptyToken,
140        Token => $emptyToken,
141        Line => "",
142        LineNumber => 1
143    };
144    return bless $self, $class;
145}
146
147sub assertTokenValue
148{
149    my $self = shift;
150    my $token = shift;
151    my $value = shift;
152    my $line = shift;
153    my $msg = "Next token should be " . $value . ", but " . $token->value() . " at " . $self->{Line};
154    if (defined ($line)) {
155        $msg .= " deprecated_idl_parser.pm:" . $line;
156    }
157    die $msg unless $token->value() eq $value;
158}
159
160sub assertTokenType
161{
162    my $self = shift;
163    my $token = shift;
164    my $type = shift;
165    die "Next token's type should be " . $type . ", but " . $token->type() . " at " . $self->{Line} unless $token->type() eq $type;
166}
167
168sub assertUnexpectedToken
169{
170    my $self = shift;
171    my $token = shift;
172    my $line = shift;
173    my $msg = "Unexpected token " . $token . " at " . $self->{Line};
174    if (defined ($line)) {
175        $msg .= " deprecated_idl_parser.pm:" . $line;
176    }
177    die $msg;
178}
179
180sub assertNoExtendedAttributesInTypedef
181{
182    my $self = shift;
183    my $name = shift;
184    my $line = shift;
185    my $typedef = $typedefs{$name};
186    my $msg = "Unexpected extendedAttributeList in typedef \"$name\" at " . $self->{Line};
187    if (defined ($line)) {
188        $msg .= " deprecated_idl_parser.pm:" . $line;
189    }
190    die $msg if %{$typedef->extendedAttributes};
191}
192
193sub Parse
194{
195    my $self = shift;
196    my $fileName = shift;
197    my $preprocessor = shift;
198    my $defines = "";
199
200    my @definitions = ();
201
202    my @lines = applyPreprocessor($fileName, $defines, $preprocessor);
203    $self->{Line} = $lines[0];
204    $self->{DocumentContent} = join(' ', @lines);
205
206    $self->getToken();
207    eval {
208        my $result = $self->parseDefinitions();
209        push(@definitions, @{$result});
210
211        my $next = $self->nextToken();
212        $self->assertTokenType($next, EmptyToken);
213    };
214    die $@ . " in $fileName" if $@;
215
216    my $document = idlDocument->new();
217    $document->fileName($fileName);
218    foreach my $definition (@definitions) {
219        if (ref($definition) eq "domInterface") {
220            push(@{$document->interfaces}, $definition);
221        } elsif (ref($definition) eq "domEnum") {
222            push(@{$document->enumerations}, $definition);
223        } elsif (ref($definition) eq "callbackFunction") {
224            push(@{$document->callbackFunctions}, $definition);
225        } else {
226            die "Unrecognized IDL definition kind: \"" . ref($definition) . "\"";
227        }
228    }
229    # Sort so output independent of order in IDL file (e.g., for JSON output)
230    @{$document->callbackFunctions} = sort {$a->name cmp $b->name} @{$document->callbackFunctions};
231    @{$document->enumerations} = sort {$a->name cmp $b->name} @{$document->enumerations};
232    @{$document->interfaces} = sort {$a->name cmp $b->name} @{$document->interfaces};
233    return $document;
234}
235
236sub nextToken
237{
238    my $self = shift;
239    return $self->{NextToken};
240}
241
242sub getToken
243{
244    my $self = shift;
245    $self->{Token} = $self->{NextToken};
246    $self->{NextToken} = $self->getTokenInternal();
247    return $self->{Token};
248}
249
250my $whitespaceTokenPattern = '^[\t\n\r ]*[\n\r]';
251my $floatTokenPattern = '^(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+))';
252my $integerTokenPattern = '^(-?[1-9][0-9]*|-?0[Xx][0-9A-Fa-f]+|-?0[0-7]*)';
253my $stringTokenPattern = '^(\"[^\"]*\")';
254my $identifierTokenPattern = '^([A-Z_a-z][0-9A-Z_a-z]*)';
255my $otherTokenPattern = '^(::|\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
256
257sub getTokenInternal
258{
259    my $self = shift;
260
261    if ($self->{DocumentContent} =~ /$whitespaceTokenPattern/) {
262        $self->{DocumentContent} =~ s/($whitespaceTokenPattern)//;
263        my $skipped = $1;
264        $self->{LineNumber}++ while ($skipped =~ /\n/g);
265        if ($self->{DocumentContent} =~ /^([^\n\r]+)/) {
266            $self->{Line} = $self->{LineNumber} . ":" . $1;
267        } else {
268            $self->{Line} = "Unknown";
269        }
270    }
271    $self->{DocumentContent} =~ s/^([\t\n\r ]+)//;
272    if ($self->{DocumentContent} eq "") {
273        return $self->{EmptyToken};
274    }
275
276    my $token = Token->new();
277    if ($self->{DocumentContent} =~ /$floatTokenPattern/) {
278        $token->type(FloatToken);
279        $token->value($1);
280        $self->{DocumentContent} =~ s/$floatTokenPattern//;
281        return $token;
282    }
283    if ($self->{DocumentContent} =~ /$integerTokenPattern/) {
284        $token->type(IntegerToken);
285        $token->value($1);
286        $self->{DocumentContent} =~ s/$integerTokenPattern//;
287        return $token;
288    }
289    if ($self->{DocumentContent} =~ /$stringTokenPattern/) {
290        $token->type(StringToken);
291        $token->value($1);
292        $self->{DocumentContent} =~ s/$stringTokenPattern//;
293        return $token;
294    }
295    if ($self->{DocumentContent} =~ /$identifierTokenPattern/) {
296        $token->type(IdentifierToken);
297        (my $value = $1) =~ s/^_//;  # strip leading underscore, used to strope reserved words
298        $token->value($value);
299        $self->{DocumentContent} =~ s/$identifierTokenPattern//;
300        return $token;
301    }
302    if ($self->{DocumentContent} =~ /$otherTokenPattern/) {
303        $token->type(OtherToken);
304        $token->value($1);
305        $self->{DocumentContent} =~ s/$otherTokenPattern//;
306        return $token;
307    }
308    die "Failed in tokenizing at " . $self->{Line};
309}
310
311sub unquoteString
312{
313    my $self = shift;
314    my $quotedString = shift;
315    if ($quotedString =~ /^"([^"]*)"$/) {
316        return $1;
317    }
318    die "Failed to parse string (" . $quotedString . ") at " . $self->{Line};
319}
320
321sub typeHasNullableSuffix
322{
323    my $type = shift;
324    return $type =~ /\?$/;
325}
326
327sub typeRemoveNullableSuffix
328{
329    my $type = shift;
330    $type =~ s/\?$//g;
331    return $type;
332}
333
334my $nextAttribute_1 = '^(attribute|inherit|readonly)$';
335my $nextPrimitiveType_1 = '^(int|long|short|unsigned)$';
336my $nextPrimitiveType_2 = '^(double|float|unrestricted)$';
337my $nextArgumentList_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|double|float|in|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
338my $nextNonAnyType_1 = '^(boolean|byte|double|float|int|long|octet|short|unrestricted|unsigned)$';
339my $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)$';
340my $nextOptionalIteratorInterfaceOrObject_1 = '^(;|=)$';
341my $nextAttributeOrOperationOrIterator_1 = '^(static|stringifier)$';
342my $nextAttributeOrOperationOrIterator_2 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|creator|deleter|double|float|getter|int|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
343my $nextUnrestrictedFloatType_1 = '^(double|float)$';
344my $nextExtendedAttributeRest3_1 = '^(\,|::|\])$';
345my $nextExceptionField_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
346my $nextType_1 = '^(::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
347my $nextSpecials_1 = '^(creator|deleter|getter|legacycaller|setter)$';
348my $nextDefinitions_1 = '^(::|callback|dictionary|enum|exception|interface|partial|typedef)$';
349my $nextExceptionMembers_1 = '^(\(|::|ByteString|DOMString|Date|\[|any|boolean|byte|const|double|float|int|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
350my $nextAttributeRest_1 = '^(attribute|readonly)$';
351my $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)$';
352my $nextSingleType_1 = '^(::|ByteString|DOMString|Date|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned)$';
353my $nextArgumentName_1 = '^(attribute|callback|const|creator|deleter|dictionary|enum|exception|getter|implements|inherit|interface|legacycaller|partial|serializer|setter|static|stringifier|typedef|unrestricted)$';
354my $nextConstValue_1 = '^(false|true)$';
355my $nextConstValue_2 = '^(-|Infinity|NaN)$';
356my $nextDefinition_1 = '^(callback|interface)$';
357my $nextAttributeOrOperationRest_1 = '^(\(|::|ByteString|DOMString|Date|any|boolean|byte|double|float|int|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
358my $nextUnsignedIntegerType_1 = '^(int|long|short)$';
359my $nextDefaultValue_1 = '^(-|Infinity|NaN|false|null|true)$';
360
361
362sub parseDefinitions
363{
364    my $self = shift;
365    my @definitions = ();
366
367    while (1) {
368        my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
369        my $next = $self->nextToken();
370        my $definition;
371        if ($next->type() == IdentifierToken || $next->value() =~ /$nextDefinitions_1/) {
372            $definition = $self->parseDefinition($extendedAttributeList);
373        } else {
374            last;
375        }
376        if (defined ($definition)) {
377            push(@definitions, $definition);
378        }
379    }
380    $self->applyTypedefs(\@definitions);
381    return \@definitions;
382}
383
384sub applyTypedefs
385{
386    my $self = shift;
387    my $definitions = shift;
388
389    if (!%typedefs) {
390        return;
391    }
392    foreach my $definition (@$definitions) {
393        if (ref($definition) eq "domInterface") {
394            foreach my $constant (@{$definition->constants}) {
395                if (exists $typedefs{$constant->type}) {
396                    my $typedef = $typedefs{$constant->type};
397                    $self->assertNoExtendedAttributesInTypedef($constant->type, __LINE__);
398                    $constant->type($typedef->type);
399                }
400            }
401            foreach my $attribute (@{$definition->attributes}) {
402                $self->applyTypedefsForTypedObject($attribute);
403            }
404            foreach my $function (@{$definition->functions}, @{$definition->constructors}, @{$definition->customConstructors}) {
405                $self->applyTypedefsForTypedObject($function);
406                foreach my $parameter (@{$function->parameters}) {
407                    $self->applyTypedefsForTypedObject($parameter);
408                }
409            }
410        }
411    }
412}
413
414sub applyTypedefsForTypedObject
415{
416    my $self = shift;
417    my $typedObject = shift;
418
419    if (!defined ($typedObject->type)) {
420        return;
421    }
422
423    my $type = $typedObject->type;
424    $type =~ s/[\?\[\]]+$//g;
425    my $typeSuffix = $typedObject->type;
426    $typeSuffix =~ s/^[^\?\[\]]+//g;
427    if (exists $typedefs{$type}) {
428        my $typedef = $typedefs{$type};
429        $typedObject->type($typedef->type . $typeSuffix);
430        copyExtendedAttributes($typedObject->extendedAttributes, $typedef->extendedAttributes);
431    }
432
433    # Handle union types, sequences and etc.
434    foreach my $name (%typedefs) {
435        if (!exists $typedefs{$name}) {
436            next;
437        }
438        my $typedef = $typedefs{$name};
439        my $regex = '\\b' . $name . '\\b';
440        my $replacement = $typedef->type;
441        my $type = $typedObject->type;
442        $type =~ s/($regex)/$replacement/g;
443        $typedObject->type($type);
444    }
445}
446
447sub parseDefinition
448{
449    my $self = shift;
450    my $extendedAttributeList = shift;
451
452    my $next = $self->nextToken();
453    if ($next->value() =~ /$nextDefinition_1/) {
454        return $self->parseCallbackOrInterface($extendedAttributeList);
455    }
456    if ($next->value() eq "partial") {
457        return $self->parsePartial($extendedAttributeList);
458    }
459    if ($next->value() eq "dictionary") {
460        return $self->parseDictionary($extendedAttributeList);
461    }
462    if ($next->value() eq "exception") {
463        return $self->parseException($extendedAttributeList);
464    }
465    if ($next->value() eq "enum") {
466        return $self->parseEnum($extendedAttributeList);
467    }
468    if ($next->value() eq "typedef") {
469        return $self->parseTypedef($extendedAttributeList);
470    }
471    if ($next->type() == IdentifierToken || $next->value() eq "::") {
472        return $self->parseImplementsStatement($extendedAttributeList);
473    }
474    $self->assertUnexpectedToken($next->value(), __LINE__);
475}
476
477sub parseCallbackOrInterface
478{
479    my $self = shift;
480    my $extendedAttributeList = shift;
481
482    my $next = $self->nextToken();
483    if ($next->value() eq "callback") {
484        $self->assertTokenValue($self->getToken(), "callback", __LINE__);
485        return $self->parseCallbackRestOrInterface($extendedAttributeList);
486    }
487    if ($next->value() eq "interface") {
488        return $self->parseInterface($extendedAttributeList);
489    }
490    $self->assertUnexpectedToken($next->value(), __LINE__);
491}
492
493sub parseCallbackRestOrInterface
494{
495    my $self = shift;
496    my $extendedAttributeList = shift;
497
498    my $next = $self->nextToken();
499    if ($next->value() eq "interface") {
500        my $interface = $self->parseInterface($extendedAttributeList);
501        $interface->isCallback(1);
502        return $interface;
503    }
504    if ($next->type() == IdentifierToken) {
505        return $self->parseCallbackRest($extendedAttributeList);
506    }
507    $self->assertUnexpectedToken($next->value(), __LINE__);
508}
509
510sub parseInterface
511{
512    my $self = shift;
513    my $extendedAttributeList = shift;
514
515    my $next = $self->nextToken();
516    if ($next->value() eq "interface") {
517        my $interface = domInterface->new();
518        $self->assertTokenValue($self->getToken(), "interface", __LINE__);
519        my $interfaceNameToken = $self->getToken();
520        $self->assertTokenType($interfaceNameToken, IdentifierToken);
521        $interface->name($interfaceNameToken->value());
522        $interface->parent($self->parseInheritance());
523        $self->assertTokenValue($self->getToken(), "{", __LINE__);
524        my $interfaceMembers = $self->parseInterfaceMembers();
525        $self->assertTokenValue($self->getToken(), "}", __LINE__);
526        $self->assertTokenValue($self->getToken(), ";", __LINE__);
527        applyMemberList($interface, $interfaceMembers);
528        applyExtendedAttributeList($interface, $extendedAttributeList);
529        return $interface;
530    }
531    $self->assertUnexpectedToken($next->value(), __LINE__);
532}
533
534sub parsePartial
535{
536    my $self = shift;
537    my $extendedAttributeList = shift;
538
539    my $next = $self->nextToken();
540    if ($next->value() eq "partial") {
541        $self->assertTokenValue($self->getToken(), "partial", __LINE__);
542        return $self->parsePartialDefinition($extendedAttributeList);
543    }
544    $self->assertUnexpectedToken($next->value(), __LINE__);
545}
546
547sub parsePartialDefinition
548{
549    my $self = shift;
550    my $extendedAttributeList = shift;
551
552    my $next = $self->nextToken();
553    if ($next->value() eq "interface") {
554        my $interface = $self->parseInterface($extendedAttributeList);
555        $interface->isPartial(1);
556        return $interface;
557    }
558    if ($next->value() eq "dictionary") {
559        return $self->parsePartialDictionary($extendedAttributeList);
560    }
561    $self->assertUnexpectedToken($next->value(), __LINE__);
562}
563
564sub parsePartialInterface
565{
566    my $self = shift;
567    my $extendedAttributeList = shift;
568
569    my $next = $self->nextToken();
570    if ($next->value() eq "interface") {
571        $self->assertTokenValue($self->getToken(), "interface", __LINE__);
572        $self->assertTokenType($self->getToken(), IdentifierToken);
573        $self->assertTokenValue($self->getToken(), "{", __LINE__);
574        $self->parseInterfaceMembers();
575        $self->assertTokenValue($self->getToken(), "}", __LINE__);
576        $self->assertTokenValue($self->getToken(), ";", __LINE__);
577        return;
578    }
579    $self->assertUnexpectedToken($next->value(), __LINE__);
580}
581
582sub parseInterfaceMembers
583{
584    my $self = shift;
585    my @interfaceMembers = ();
586
587    while (1) {
588        my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
589        my $next = $self->nextToken();
590        my $interfaceMember;
591        if ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMembers_1/) {
592            $interfaceMember = $self->parseInterfaceMember($extendedAttributeList);
593        } else {
594            last;
595        }
596        if (defined $interfaceMember) {
597            push(@interfaceMembers, $interfaceMember);
598        }
599    }
600    return \@interfaceMembers;
601}
602
603sub parseInterfaceMember
604{
605    my $self = shift;
606    my $extendedAttributeList = shift;
607
608    my $next = $self->nextToken();
609    if ($next->value() eq "const") {
610        return $self->parseConst($extendedAttributeList);
611    }
612    if ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMember_1/) {
613        return $self->parseAttributeOrOperationOrIterator($extendedAttributeList);
614    }
615    $self->assertUnexpectedToken($next->value(), __LINE__);
616}
617
618sub parseDictionary
619{
620    my $self = shift;
621    my $extendedAttributeList = shift;
622
623    my $next = $self->nextToken();
624    if ($next->value() eq "dictionary") {
625        $self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
626        $self->assertTokenType($self->getToken(), IdentifierToken);
627        $self->parseInheritance();
628        $self->assertTokenValue($self->getToken(), "{", __LINE__);
629        $self->parseDictionaryMembers();
630        $self->assertTokenValue($self->getToken(), "}", __LINE__);
631        $self->assertTokenValue($self->getToken(), ";", __LINE__);
632        return;
633    }
634    $self->assertUnexpectedToken($next->value(), __LINE__);
635}
636
637sub parseDictionaryMembers
638{
639    my $self = shift;
640
641    while (1) {
642        my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
643        my $next = $self->nextToken();
644        if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
645            $self->parseDictionaryMember($extendedAttributeList);
646        } else {
647            last;
648        }
649    }
650}
651
652sub parseDictionaryMember
653{
654    my $self = shift;
655    my $extendedAttributeList = shift;
656
657    my $next = $self->nextToken();
658    if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
659        $self->parseType();
660        $self->assertTokenType($self->getToken(), IdentifierToken);
661        $self->parseDefault();
662        $self->assertTokenValue($self->getToken(), ";", __LINE__);
663        return;
664    }
665    $self->assertUnexpectedToken($next->value(), __LINE__);
666}
667
668sub parsePartialDictionary
669{
670    my $self = shift;
671    my $next = $self->nextToken();
672    if ($next->value() eq "dictionary") {
673        $self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
674        $self->assertTokenType($self->getToken(), IdentifierToken);
675        $self->assertTokenValue($self->getToken(), "{", __LINE__);
676        $self->parseDictionaryMembers();
677        $self->assertTokenValue($self->getToken(), "}", __LINE__);
678        $self->assertTokenValue($self->getToken(), ";", __LINE__);
679        return;
680    }
681    $self->assertUnexpectedToken($next->value(), __LINE__);
682}
683
684sub parseDefault
685{
686    my $self = shift;
687    my $next = $self->nextToken();
688    if ($next->value() eq "=") {
689        $self->assertTokenValue($self->getToken(), "=", __LINE__);
690        return $self->parseDefaultValue();
691    }
692}
693
694sub parseDefaultValue
695{
696    my $self = shift;
697    my $next = $self->nextToken();
698    if ($next->type() == FloatToken || $next->type() == IntegerToken || $next->value() =~ /$nextDefaultValue_1/) {
699        return $self->parseConstValue();
700    }
701    if ($next->type() == StringToken) {
702        return $self->getToken()->value();
703    }
704    $self->assertUnexpectedToken($next->value(), __LINE__);
705}
706
707sub parseException
708{
709    my $self = shift;
710    my $extendedAttributeList = shift;
711
712    my $next = $self->nextToken();
713    if ($next->value() eq "exception") {
714        my $interface = domInterface->new();
715        $self->assertTokenValue($self->getToken(), "exception", __LINE__);
716        my $exceptionNameToken = $self->getToken();
717        $self->assertTokenType($exceptionNameToken, IdentifierToken);
718        $interface->name($exceptionNameToken->value());
719        $interface->isException(1);
720        $interface->parent($self->parseInheritance());
721        $self->assertTokenValue($self->getToken(), "{", __LINE__);
722        my $exceptionMembers = $self->parseExceptionMembers();
723        $self->assertTokenValue($self->getToken(), "}", __LINE__);
724        $self->assertTokenValue($self->getToken(), ";", __LINE__);
725        applyMemberList($interface, $exceptionMembers);
726        applyExtendedAttributeList($interface, $extendedAttributeList);
727        return $interface;
728    }
729    $self->assertUnexpectedToken($next->value(), __LINE__);
730}
731
732sub parseExceptionMembers
733{
734    my $self = shift;
735    my @members = ();
736
737    while (1) {
738        my $next = $self->nextToken();
739        if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionMembers_1/) {
740            my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
741            #my $member = $self->parseExceptionMember($extendedAttributeList);
742            my $member = $self->parseInterfaceMember($extendedAttributeList);
743            if (defined ($member)) {
744                push(@members, $member);
745            }
746        } else {
747            last;
748        }
749    }
750    return \@members;
751}
752
753sub parseInheritance
754{
755    my $self = shift;
756    my $parent;
757
758    my $next = $self->nextToken();
759    if ($next->value() eq ":") {
760        $self->assertTokenValue($self->getToken(), ":", __LINE__);
761        $parent = $self->parseScopedName();
762    }
763    return $parent;
764}
765
766sub parseEnum
767{
768    my $self = shift;
769    my $extendedAttributeList = shift; # ignored: Extended attributes are not applicable to enumerations
770
771    my $next = $self->nextToken();
772    if ($next->value() eq "enum") {
773        my $enum = domEnum->new();
774        $self->assertTokenValue($self->getToken(), "enum", __LINE__);
775        my $enumNameToken = $self->getToken();
776        $self->assertTokenType($enumNameToken, IdentifierToken);
777        $enum->name($enumNameToken->value());
778        $self->assertTokenValue($self->getToken(), "{", __LINE__);
779        push(@{$enum->values}, @{$self->parseEnumValueList()});
780        $self->assertTokenValue($self->getToken(), "}", __LINE__);
781        $self->assertTokenValue($self->getToken(), ";", __LINE__);
782        return $enum;
783    }
784    $self->assertUnexpectedToken($next->value(), __LINE__);
785}
786
787sub parseEnumValueList
788{
789    my $self = shift;
790    my @values = ();
791    my $next = $self->nextToken();
792    if ($next->type() == StringToken) {
793        my $enumValueToken = $self->getToken();
794        $self->assertTokenType($enumValueToken, StringToken);
795        my $enumValue = $self->unquoteString($enumValueToken->value());
796        push(@values, $enumValue);
797        push(@values, @{$self->parseEnumValues()});
798        return \@values;
799    }
800    # value list must be non-empty
801    $self->assertUnexpectedToken($next->value(), __LINE__);
802}
803
804sub parseEnumValues
805{
806    my $self = shift;
807    my @values = ();
808    my $next = $self->nextToken();
809    if ($next->value() eq ",") {
810        $self->assertTokenValue($self->getToken(), ",", __LINE__);
811        my $enumValueToken = $self->getToken();
812        $self->assertTokenType($enumValueToken, StringToken);
813        my $enumValue = $self->unquoteString($enumValueToken->value());
814        push(@values, $enumValue);
815        push(@values, @{$self->parseEnumValues()});
816        return \@values;
817    }
818    return \@values; # empty list (end of enumeration-values)
819}
820
821sub parseCallbackRest
822{
823    my $self = shift;
824    my $extendedAttributeList = shift;
825
826    my $next = $self->nextToken();
827    if ($next->type() == IdentifierToken) {
828        my $callback = callbackFunction->new();
829        my $name = $self->getToken();
830        $self->assertTokenType($name, IdentifierToken);
831        $callback->name($name->value());
832        $self->assertTokenValue($self->getToken(), "=", __LINE__);
833        $callback->type($self->parseReturnType());
834        $self->assertTokenValue($self->getToken(), "(", __LINE__);
835        $callback->parameters($self->parseArgumentList());
836        $self->assertTokenValue($self->getToken(), ")", __LINE__);
837        $self->assertTokenValue($self->getToken(), ";", __LINE__);
838        return $callback;
839    }
840    $self->assertUnexpectedToken($next->value(), __LINE__);
841}
842
843sub parseTypedef
844{
845    my $self = shift;
846    my $extendedAttributeList = shift;
847    die "Extended attributes are not applicable to typedefs themselves: " . $self->{Line} if %{$extendedAttributeList};
848
849    my $next = $self->nextToken();
850    if ($next->value() eq "typedef") {
851        $self->assertTokenValue($self->getToken(), "typedef", __LINE__);
852        my $typedef = Typedef->new();
853        $typedef->extendedAttributes($self->parseExtendedAttributeListAllowEmpty());
854        $typedef->type($self->parseType());
855        my $nameToken = $self->getToken();
856        $self->assertTokenType($nameToken, IdentifierToken);
857        $self->assertTokenValue($self->getToken(), ";", __LINE__);
858        my $name = $nameToken->value();
859        die "typedef redefinition for " . $name . " at " . $self->{Line} if (exists $typedefs{$name} && $typedef->type ne $typedefs{$name}->type);
860        $typedefs{$name} = $typedef;
861        return;
862    }
863    $self->assertUnexpectedToken($next->value(), __LINE__);
864}
865
866sub parseImplementsStatement
867{
868    my $self = shift;
869    my $extendedAttributeList = shift;
870
871    my $next = $self->nextToken();
872    if ($next->type() == IdentifierToken) {
873        $self->parseScopedName();
874        $self->assertTokenValue($self->getToken(), "implements", __LINE__);
875        $self->parseScopedName();
876        $self->assertTokenValue($self->getToken(), ";", __LINE__);
877        return;
878    }
879    $self->assertUnexpectedToken($next->value(), __LINE__);
880}
881
882sub parseConst
883{
884    my $self = shift;
885    my $extendedAttributeList = shift;
886
887    my $next = $self->nextToken();
888    if ($next->value() eq "const") {
889        my $newDataNode = domConstant->new();
890        $self->assertTokenValue($self->getToken(), "const", __LINE__);
891        $newDataNode->type($self->parseConstType());
892        my $constNameToken = $self->getToken();
893        $self->assertTokenType($constNameToken, IdentifierToken);
894        $newDataNode->name($constNameToken->value());
895        $self->assertTokenValue($self->getToken(), "=", __LINE__);
896        $newDataNode->value($self->parseConstValue());
897        $self->assertTokenValue($self->getToken(), ";", __LINE__);
898        $newDataNode->extendedAttributes($extendedAttributeList);
899        return $newDataNode;
900    }
901    $self->assertUnexpectedToken($next->value(), __LINE__);
902}
903
904sub parseConstValue
905{
906    my $self = shift;
907    my $next = $self->nextToken();
908    if ($next->value() =~ /$nextConstValue_1/) {
909        return $self->parseBooleanLiteral();
910    }
911    if ($next->value() eq "null") {
912        $self->assertTokenValue($self->getToken(), "null", __LINE__);
913        return "null";
914    }
915    if ($next->type() == FloatToken || $next->value() =~ /$nextConstValue_2/) {
916        return $self->parseFloatLiteral();
917    }
918    # backward compatibility
919    if ($next->type() == StringToken) {
920        return $self->getToken()->value();
921    }
922    if ($next->type() == IntegerToken) {
923        return $self->getToken()->value();
924    }
925    $self->assertUnexpectedToken($next->value(), __LINE__);
926}
927
928sub parseBooleanLiteral
929{
930    my $self = shift;
931    my $next = $self->nextToken();
932    if ($next->value() eq "true") {
933        $self->assertTokenValue($self->getToken(), "true", __LINE__);
934        return "true";
935    }
936    if ($next->value() eq "false") {
937        $self->assertTokenValue($self->getToken(), "false", __LINE__);
938        return "false";
939    }
940    $self->assertUnexpectedToken($next->value(), __LINE__);
941}
942
943sub parseFloatLiteral
944{
945    my $self = shift;
946    my $next = $self->nextToken();
947    if ($next->value() eq "-") {
948        $self->assertTokenValue($self->getToken(), "-", __LINE__);
949        $self->assertTokenValue($self->getToken(), "Infinity", __LINE__);
950        return "-Infinity";
951    }
952    if ($next->value() eq "Infinity") {
953        $self->assertTokenValue($self->getToken(), "Infinity", __LINE__);
954        return "Infinity";
955    }
956    if ($next->value() eq "NaN") {
957        $self->assertTokenValue($self->getToken(), "NaN", __LINE__);
958        return "NaN";
959    }
960    if ($next->type() == FloatToken) {
961        return $self->getToken()->value();
962    }
963    $self->assertUnexpectedToken($next->value(), __LINE__);
964}
965
966sub parseAttributeOrOperationOrIterator
967{
968    my $self = shift;
969    my $extendedAttributeList = shift;
970
971    my $next = $self->nextToken();
972    if ($next->value() eq "serializer") {
973        return $self->parseSerializer($extendedAttributeList);
974    }
975    if ($next->value() =~ /$nextAttributeOrOperationOrIterator_1/) {
976        my $qualifier = $self->parseQualifier();
977        my $newDataNode = $self->parseAttributeOrOperationRest($extendedAttributeList);
978        if (defined($newDataNode) && $qualifier eq "static") {
979            $newDataNode->isStatic(1);
980        }
981        return $newDataNode;
982    }
983    if ($next->value() =~ /$nextAttribute_1/) {
984        return $self->parseAttribute($extendedAttributeList);
985    }
986    if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationOrIterator_2/) {
987        return $self->parseOperationOrIterator($extendedAttributeList);
988    }
989    $self->assertUnexpectedToken($next->value(), __LINE__);
990}
991
992sub parseSerializer
993{
994    my $self = shift;
995    my $extendedAttributeList = shift;
996
997    my $next = $self->nextToken();
998    if ($next->value() eq "serializer") {
999        $self->assertTokenValue($self->getToken(), "serializer", __LINE__);
1000        return $self->parseSerializerRest($extendedAttributeList);
1001    }
1002    $self->assertUnexpectedToken($next->value(), __LINE__);
1003}
1004
1005sub parseSerializerRest
1006{
1007    my $self = shift;
1008    my $extendedAttributeList = shift;
1009
1010    my $next = $self->nextToken();
1011    if ($next->value() eq "=") {
1012        $self->assertTokenValue($self->getToken(), "=", __LINE__);
1013        return $self->parseSerializationPattern($extendedAttributeList);
1014    }
1015    if ($next->type() == IdentifierToken || $next->value() eq "(") {
1016        return $self->parseOperationRest($extendedAttributeList);
1017    }
1018}
1019
1020sub parseSerializationPattern
1021{
1022    my $self = shift;
1023    my $extendedAttributeList = shift;
1024
1025    my $next = $self->nextToken();
1026    if ($next->value() eq "{") {
1027        $self->assertTokenValue($self->getToken(), "{", __LINE__);
1028        $self->parseSerializationPatternMap();
1029        $self->assertTokenValue($self->getToken(), "}", __LINE__);
1030        return;
1031    }
1032    if ($next->value() eq "[") {
1033        $self->assertTokenValue($self->getToken(), "[", __LINE__);
1034        $self->parseSerializationPatternList();
1035        $self->assertTokenValue($self->getToken(), "]", __LINE__);
1036        return;
1037    }
1038    if ($next->type() == IdentifierToken) {
1039        $self->assertTokenType($self->getToken(), IdentifierToken);
1040        return;
1041    }
1042    $self->assertUnexpectedToken($next->value(), __LINE__);
1043}
1044
1045sub parseSerializationPatternMap
1046{
1047    my $self = shift;
1048    my $next = $self->nextToken();
1049    if ($next->value() eq "getter") {
1050        $self->assertTokenValue($self->getToken(), "getter", __LINE__);
1051        return;
1052    }
1053    if ($next->value() eq "inherit") {
1054        $self->assertTokenValue($self->getToken(), "inherit", __LINE__);
1055        $self->parseIdentifiers();
1056        return;
1057    }
1058    if ($next->type() == IdentifierToken) {
1059        $self->assertTokenType($self->getToken(), IdentifierToken);
1060        $self->parseIdentifiers();
1061    }
1062}
1063
1064sub parseSerializationPatternList
1065{
1066    my $self = shift;
1067    my $next = $self->nextToken();
1068    if ($next->value() eq "getter") {
1069        $self->assertTokenValue($self->getToken(), "getter", __LINE__);
1070        return;
1071    }
1072    if ($next->type() == IdentifierToken) {
1073        $self->assertTokenType($self->getToken(), IdentifierToken);
1074        $self->parseIdentifiers();
1075    }
1076}
1077
1078sub parseIdentifiers
1079{
1080    my $self = shift;
1081    my @idents = ();
1082
1083    while (1) {
1084        my $next = $self->nextToken();
1085        if ($next->value() eq ",") {
1086            $self->assertTokenValue($self->getToken(), ",", __LINE__);
1087            my $token = $self->getToken();
1088            $self->assertTokenType($token, IdentifierToken);
1089            push(@idents, $token->value());
1090        } else {
1091            last;
1092        }
1093    }
1094    return \@idents;
1095}
1096
1097sub parseQualifier
1098{
1099    my $self = shift;
1100
1101    my $next = $self->nextToken();
1102    if ($next->value() eq "static") {
1103        $self->assertTokenValue($self->getToken(), "static", __LINE__);
1104        return "static";
1105    }
1106    if ($next->value() eq "stringifier") {
1107        $self->assertTokenValue($self->getToken(), "stringifier", __LINE__);
1108        return "stringifier";
1109    }
1110    $self->assertUnexpectedToken($next->value(), __LINE__);
1111}
1112
1113sub parseAttributeOrOperationRest
1114{
1115    my $self = shift;
1116    my $extendedAttributeList = shift;
1117
1118    my $next = $self->nextToken();
1119    if ($next->value() =~ /$nextAttributeRest_1/) {
1120        return $self->parseAttributeRest($extendedAttributeList);
1121    }
1122    if ($next->value() eq ";") {
1123        $self->assertTokenValue($self->getToken(), ";", __LINE__);
1124        return;
1125    }
1126    if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
1127        my $returnType = $self->parseReturnType();
1128        my $function = $self->parseOperationRest($extendedAttributeList);
1129        if (defined ($function)) {
1130            $function->type($returnType);
1131        }
1132        return $function;
1133    }
1134    $self->assertUnexpectedToken($next->value(), __LINE__);
1135}
1136
1137sub parseAttribute
1138{
1139    my $self = shift;
1140    my $extendedAttributeList = shift;
1141
1142    my $next = $self->nextToken();
1143    if ($next->value() =~ /$nextAttribute_1/) {
1144        $self->parseInherit();
1145        return $self->parseAttributeRest($extendedAttributeList);
1146    }
1147    $self->assertUnexpectedToken($next->value(), __LINE__);
1148}
1149
1150sub parseAttributeRest
1151{
1152    my $self = shift;
1153    my $extendedAttributeList = shift;
1154
1155    my $next = $self->nextToken();
1156    if ($next->value() =~ /$nextAttributeRest_1/) {
1157        my $newDataNode = domAttribute->new();
1158        if ($self->parseReadOnly()) {
1159            $newDataNode->isReadOnly(1);
1160        }
1161        $self->assertTokenValue($self->getToken(), "attribute", __LINE__);
1162        my $type = $self->parseType();
1163        $newDataNode->isNullable(typeHasNullableSuffix($type));
1164        # Remove all "?" in the type declaration, e.g. "double?" -> "double".
1165        $newDataNode->type(typeRemoveNullableSuffix($type));
1166        my $token = $self->getToken();
1167        $self->assertTokenType($token, IdentifierToken);
1168        $newDataNode->name($token->value());
1169        $self->assertTokenValue($self->getToken(), ";", __LINE__);
1170        # CustomConstructor may also be used on attributes.
1171        if (defined $extendedAttributeList->{"CustomConstructors"}) {
1172            delete $extendedAttributeList->{"CustomConstructors"};
1173            $extendedAttributeList->{"CustomConstructor"} = "VALUE_IS_MISSING";
1174        }
1175        $newDataNode->extendedAttributes($extendedAttributeList);
1176        return $newDataNode;
1177    }
1178    $self->assertUnexpectedToken($next->value(), __LINE__);
1179}
1180
1181sub parseInherit
1182{
1183    my $self = shift;
1184    my $next = $self->nextToken();
1185    if ($next->value() eq "inherit") {
1186        $self->assertTokenValue($self->getToken(), "inherit", __LINE__);
1187        return 1;
1188    }
1189    return 0;
1190}
1191
1192sub parseReadOnly
1193{
1194    my $self = shift;
1195    my $next = $self->nextToken();
1196    if ($next->value() eq "readonly") {
1197        $self->assertTokenValue($self->getToken(), "readonly", __LINE__);
1198        return 1;
1199    }
1200    return 0;
1201}
1202
1203sub parseOperationOrIterator
1204{
1205    my $self = shift;
1206    my $extendedAttributeList = shift;
1207
1208    my $next = $self->nextToken();
1209    if ($next->value() =~ /$nextSpecials_1/) {
1210        return $self->parseSpecialOperation($extendedAttributeList);
1211    }
1212    if ($next->type() == IdentifierToken || $next->value() =~ /$nextAttributeOrOperationRest_1/) {
1213        my $returnType = $self->parseReturnType();
1214        my $interface = $self->parseOperationOrIteratorRest($extendedAttributeList);
1215        if (defined ($interface)) {
1216            $interface->type($returnType);
1217        }
1218        return $interface;
1219    }
1220    $self->assertUnexpectedToken($next->value(), __LINE__);
1221}
1222
1223sub parseSpecialOperation
1224{
1225    my $self = shift;
1226    my $extendedAttributeList = shift;
1227
1228    my $next = $self->nextToken();
1229    if ($next->value() =~ /$nextSpecials_1/) {
1230        my @specials = ();
1231        push(@specials, @{$self->parseSpecials()});
1232        my $returnType = $self->parseReturnType();
1233        my $function = $self->parseOperationRest($extendedAttributeList);
1234        if (defined ($function)) {
1235            $function->type($returnType);
1236            $function->specials(\@specials);
1237        }
1238        return $function;
1239    }
1240    $self->assertUnexpectedToken($next->value(), __LINE__);
1241}
1242
1243sub parseSpecials
1244{
1245    my $self = shift;
1246    my @specials = ();
1247
1248    while (1) {
1249        my $next = $self->nextToken();
1250        if ($next->value() =~ /$nextSpecials_1/) {
1251            push(@specials, $self->parseSpecial());
1252        } else {
1253            last;
1254        }
1255    }
1256    return \@specials;
1257}
1258
1259sub parseSpecial
1260{
1261    my $self = shift;
1262    my $next = $self->nextToken();
1263    if ($next->value() eq "getter") {
1264        $self->assertTokenValue($self->getToken(), "getter", __LINE__);
1265        return "getter";
1266    }
1267    if ($next->value() eq "setter") {
1268        $self->assertTokenValue($self->getToken(), "setter", __LINE__);
1269        return "setter";
1270    }
1271    if ($next->value() eq "creator") {
1272        $self->assertTokenValue($self->getToken(), "creator", __LINE__);
1273        return "creator";
1274    }
1275    if ($next->value() eq "deleter") {
1276        $self->assertTokenValue($self->getToken(), "deleter", __LINE__);
1277        return "deleter";
1278    }
1279    if ($next->value() eq "legacycaller") {
1280        $self->assertTokenValue($self->getToken(), "legacycaller", __LINE__);
1281        return "legacycaller";
1282    }
1283    $self->assertUnexpectedToken($next->value(), __LINE__);
1284}
1285
1286sub parseOperationOrIteratorRest
1287{
1288    my $self = shift;
1289    my $extendedAttributeList = shift;
1290
1291    my $next = $self->nextToken();
1292    if ($next->value() eq "iterator") {
1293        return $self->parseIteratorRest($extendedAttributeList);
1294    }
1295    if ($next->type() == IdentifierToken || $next->value() eq "(") {
1296        return $self->parseOperationRest($extendedAttributeList);
1297    }
1298    $self->assertUnexpectedToken($next->value(), __LINE__);
1299}
1300
1301sub parseIteratorRest
1302{
1303    my $self = shift;
1304    my $extendedAttributeList = shift;
1305
1306    my $next = $self->nextToken();
1307    if ($next->value() eq "iterator") {
1308        $self->assertTokenValue($self->getToken(), "iterator", __LINE__);
1309        $self->parseOptionalIteratorInterfaceOrObject($extendedAttributeList);
1310        $self->assertTokenValue($self->getToken(), ";", __LINE__);
1311        return;
1312    }
1313    $self->assertUnexpectedToken($next->value(), __LINE__);
1314}
1315
1316sub parseOptionalIteratorInterfaceOrObject
1317{
1318    my $self = shift;
1319    my $extendedAttributeList = shift;
1320
1321    my $next = $self->nextToken();
1322    if ($next->value() =~ /$nextOptionalIteratorInterfaceOrObject_1/) {
1323        return $self->parseOptionalIteratorInterface($extendedAttributeList);
1324    }
1325    if ($next->value() eq "object") {
1326        $self->assertTokenValue($self->getToken(), "object", __LINE__);
1327        return;
1328    }
1329    $self->assertUnexpectedToken($next->value(), __LINE__);
1330}
1331
1332sub parseOptionalIteratorInterface
1333{
1334    my $self = shift;
1335    my $extendedAttributeList = shift;
1336
1337    my $next = $self->nextToken();
1338    if ($next->value() eq "=") {
1339        $self->assertTokenValue($self->getToken(), "=", __LINE__);
1340        $self->assertTokenType($self->getToken(), IdentifierToken);
1341    }
1342}
1343
1344sub parseOperationRest
1345{
1346    my $self = shift;
1347    my $extendedAttributeList = shift;
1348
1349    my $next = $self->nextToken();
1350    if ($next->type() == IdentifierToken || $next->value() eq "(") {
1351        my $newDataNode = domFunction->new();
1352        my $name = $self->parseOptionalIdentifier();
1353        $newDataNode->name($name);
1354        $self->assertTokenValue($self->getToken(), "(", __LINE__);
1355        push(@{$newDataNode->parameters}, @{$self->parseArgumentList()});
1356        $self->assertTokenValue($self->getToken(), ")", __LINE__);
1357        $self->assertTokenValue($self->getToken(), ";", __LINE__);
1358        $newDataNode->extendedAttributes($extendedAttributeList);
1359        return $newDataNode;
1360    }
1361    $self->assertUnexpectedToken($next->value(), __LINE__);
1362}
1363
1364sub parseOptionalIdentifier
1365{
1366    my $self = shift;
1367    my $next = $self->nextToken();
1368    if ($next->type() == IdentifierToken) {
1369        my $token = $self->getToken();
1370        return $token->value();
1371    }
1372    return "";
1373}
1374
1375sub parseArgumentList
1376{
1377    my $self = shift;
1378    my @arguments = ();
1379
1380    my $next = $self->nextToken();
1381    if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
1382        push(@arguments, $self->parseArgument());
1383        push(@arguments, @{$self->parseArguments()});
1384    }
1385    return \@arguments;
1386}
1387
1388sub parseArguments
1389{
1390    my $self = shift;
1391    my @arguments = ();
1392
1393    while (1) {
1394        my $next = $self->nextToken();
1395        if ($next->value() eq ",") {
1396            $self->assertTokenValue($self->getToken(), ",", __LINE__);
1397            push(@arguments, $self->parseArgument());
1398        } else {
1399            last;
1400        }
1401    }
1402    return \@arguments;
1403}
1404
1405sub parseArgument
1406{
1407    my $self = shift;
1408    my $next = $self->nextToken();
1409    if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
1410        my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
1411        my $argument = $self->parseOptionalOrRequiredArgument($extendedAttributeList);
1412        return $argument;
1413    }
1414    $self->assertUnexpectedToken($next->value(), __LINE__);
1415}
1416
1417sub parseOptionalOrRequiredArgument
1418{
1419    my $self = shift;
1420    my $extendedAttributeList = shift;
1421
1422    my $paramDataNode = domParameter->new();
1423    $paramDataNode->extendedAttributes($extendedAttributeList);
1424
1425    my $next = $self->nextToken();
1426    if ($next->value() eq "optional") {
1427        $self->assertTokenValue($self->getToken(), "optional", __LINE__);
1428        my $type = $self->parseType();
1429        # domDataNode can only consider last "?".
1430        $paramDataNode->isNullable(typeHasNullableSuffix($type));
1431        # Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
1432        $paramDataNode->type(typeRemoveNullableSuffix($type));
1433        $paramDataNode->isOptional(1);
1434        $paramDataNode->name($self->parseArgumentName());
1435        $self->parseDefault();
1436        return $paramDataNode;
1437    }
1438    if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
1439        my $type = $self->parseType();
1440        # domDataNode can only consider last "?".
1441        $paramDataNode->isNullable(typeHasNullableSuffix($type));
1442        # Remove all "?" if exists, e.g. "object?[]?" -> "object[]".
1443        $paramDataNode->type(typeRemoveNullableSuffix($type));
1444        $paramDataNode->isOptional(0);
1445        $paramDataNode->isVariadic($self->parseEllipsis());
1446        $paramDataNode->name($self->parseArgumentName());
1447        return $paramDataNode;
1448    }
1449    $self->assertUnexpectedToken($next->value(), __LINE__);
1450}
1451
1452sub parseArgumentName
1453{
1454    my $self = shift;
1455    my $next = $self->nextToken();
1456    if ($next->value() =~ /$nextArgumentName_1/) {
1457        return $self->parseArgumentNameKeyword();
1458    }
1459    if ($next->type() == IdentifierToken) {
1460        return $self->getToken()->value();
1461    }
1462    $self->assertUnexpectedToken($next->value(), __LINE__);
1463}
1464
1465sub parseEllipsis
1466{
1467    my $self = shift;
1468    my $next = $self->nextToken();
1469    if ($next->value() eq "...") {
1470        $self->assertTokenValue($self->getToken(), "...", __LINE__);
1471        return 1;
1472    }
1473    return 0;
1474}
1475
1476sub parseExceptionMember
1477{
1478    my $self = shift;
1479    my $extendedAttributeList = shift;
1480
1481    my $next = $self->nextToken();
1482    if ($next->value() eq "const") {
1483        return $self->parseConst($extendedAttributeList);
1484    }
1485    if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
1486        return $self->parseExceptionField($extendedAttributeList);
1487    }
1488    $self->assertUnexpectedToken($next->value(), __LINE__);
1489}
1490
1491sub parseExceptionField
1492{
1493    my $self = shift;
1494    my $extendedAttributeList = shift;
1495
1496    my $next = $self->nextToken();
1497    if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
1498        my $newDataNode = domAttribute->new();
1499        $newDataNode->type("attribute");
1500        $newDataNode->isReadOnly(1);
1501        $newDataNode->type($self->parseType());
1502        my $token = $self->getToken();
1503        $self->assertTokenType($token, IdentifierToken);
1504        $newDataNode->name($token->value());
1505        $self->assertTokenValue($self->getToken(), ";", __LINE__);
1506        $newDataNode->extendedAttributes($extendedAttributeList);
1507        return $newDataNode;
1508    }
1509    $self->assertUnexpectedToken($next->value(), __LINE__);
1510}
1511
1512sub parseExtendedAttributeListAllowEmpty
1513{
1514    my $self = shift;
1515    my $next = $self->nextToken();
1516    if ($next->value() eq "[") {
1517        return $self->parseExtendedAttributeList();
1518    }
1519    return {};
1520}
1521
1522sub copyExtendedAttributes
1523{
1524    my $extendedAttributeList = shift;
1525    my $attr = shift;
1526
1527    for my $key (keys %{$attr}) {
1528        if ($key eq "Constructor") {
1529            push(@{$extendedAttributeList->{"Constructors"}}, $attr->{$key});
1530        } elsif ($key eq "Constructors") {
1531            my @constructors = @{$attr->{$key}};
1532            foreach my $constructor (@constructors) {
1533                push(@{$extendedAttributeList->{"Constructors"}}, $constructor);
1534            }
1535        } elsif ($key eq "CustomConstructor") {
1536            push(@{$extendedAttributeList->{"CustomConstructors"}}, $attr->{$key});
1537        } elsif ($key eq "CustomConstructors") {
1538           my @customConstructors = @{$attr->{$key}};
1539            foreach my $customConstructor (@customConstructors) {
1540                push(@{$extendedAttributeList->{"CustomConstructors"}}, $customConstructor);
1541            }
1542        } else {
1543            $extendedAttributeList->{$key} = $attr->{$key};
1544        }
1545    }
1546}
1547
1548sub parseExtendedAttributeList
1549{
1550    my $self = shift;
1551    my $next = $self->nextToken();
1552    if ($next->value() eq "[") {
1553        $self->assertTokenValue($self->getToken(), "[", __LINE__);
1554        my $extendedAttributeList = {};
1555        my $attr = $self->parseExtendedAttribute();
1556        copyExtendedAttributes($extendedAttributeList, $attr);
1557        $attr = $self->parseExtendedAttributes();
1558        copyExtendedAttributes($extendedAttributeList, $attr);
1559        $self->assertTokenValue($self->getToken(), "]", __LINE__);
1560        return $extendedAttributeList;
1561    }
1562    $self->assertUnexpectedToken($next->value(), __LINE__);
1563}
1564
1565sub parseExtendedAttributes
1566{
1567    my $self = shift;
1568    my $extendedAttributeList = {};
1569
1570    while (1) {
1571        my $next = $self->nextToken();
1572        if ($next->value() eq ",") {
1573            $self->assertTokenValue($self->getToken(), ",", __LINE__);
1574            my $attr = $self->parseExtendedAttribute2();
1575            copyExtendedAttributes($extendedAttributeList, $attr);
1576        } else {
1577            last;
1578        }
1579    }
1580    return $extendedAttributeList;
1581}
1582
1583sub parseExtendedAttribute
1584{
1585    my $self = shift;
1586    my $next = $self->nextToken();
1587    if ($next->type() == IdentifierToken || $next->value() eq "::") {
1588        my $scopedName = $self->parseScopedName();
1589        return $self->parseExtendedAttributeRest($scopedName);
1590    }
1591    # backward compatibility. Spec doesn' allow "[]". But WebKit requires.
1592    if ($next->value() eq ']') {
1593        return {};
1594    }
1595    $self->assertUnexpectedToken($next->value(), __LINE__);
1596}
1597
1598sub parseExtendedAttribute2
1599{
1600    my $self = shift;
1601    my $next = $self->nextToken();
1602    if ($next->type() == IdentifierToken || $next->value() eq "::") {
1603        my $scopedName = $self->parseScopedName();
1604        return $self->parseExtendedAttributeRest($scopedName);
1605    }
1606    return {};
1607}
1608
1609sub parseExtendedAttributeRest
1610{
1611    my $self = shift;
1612    my $name = shift;
1613    my $attrs = {};
1614
1615    my $next = $self->nextToken();
1616    if ($next->value() eq "(") {
1617        $self->assertTokenValue($self->getToken(), "(", __LINE__);
1618        $attrs->{$name} = $self->parseArgumentList();
1619        $self->assertTokenValue($self->getToken(), ")", __LINE__);
1620        return $attrs;
1621    }
1622    if ($next->value() eq "=") {
1623        $self->assertTokenValue($self->getToken(), "=", __LINE__);
1624        $attrs->{$name} = $self->parseExtendedAttributeRest2();
1625        return $attrs;
1626    }
1627
1628    if ($name eq "Constructor" || $name eq "CustomConstructor") {
1629        $attrs->{$name} = [];
1630    } else {
1631        $attrs->{$name} = "VALUE_IS_MISSING";
1632    }
1633    return $attrs;
1634}
1635
1636sub parseExtendedAttributeRest2
1637{
1638    my $self = shift;
1639    my $next = $self->nextToken();
1640    if ($next->type() == IdentifierToken || $next->value() eq "::") {
1641        my $scopedName = $self->parseScopedName();
1642        return $self->parseExtendedAttributeRest3($scopedName);
1643    }
1644    if ($next->type() == IntegerToken) {
1645        my $token = $self->getToken();
1646        return $token->value();
1647    }
1648    $self->assertUnexpectedToken($next->value(), __LINE__);
1649}
1650
1651sub parseExtendedAttributeRest3
1652{
1653    my $self = shift;
1654    my $name = shift;
1655
1656    my $next = $self->nextToken();
1657    if ($next->value() eq "&") {
1658        $self->assertTokenValue($self->getToken(), "&", __LINE__);
1659        my $rightValue = $self->parseScopedName();
1660        return $name . "&" . $rightValue;
1661    }
1662    if ($next->value() eq "|") {
1663        $self->assertTokenValue($self->getToken(), "|", __LINE__);
1664        my $rightValue = $self->parseScopedName();
1665        return $name . "|" . $rightValue;
1666    }
1667    if ($next->value() eq "(") {
1668        my $attr = {};
1669        $self->assertTokenValue($self->getToken(), "(", __LINE__);
1670        $attr->{$name} = $self->parseArgumentList();
1671        $self->assertTokenValue($self->getToken(), ")", __LINE__);
1672        return $attr;
1673    }
1674    if ($next->type() == IdentifierToken || $next->value() =~ /$nextExtendedAttributeRest3_1/) {
1675        my @names = ();
1676        push(@names, $name);
1677        push(@names, @{$self->parseScopedNameListNoComma()});
1678        return join(' ', @names);
1679    }
1680    $self->assertUnexpectedToken($next->value());
1681}
1682
1683sub parseScopedNameListNoComma
1684{
1685    my $self = shift;
1686    my @names = ();
1687
1688    while (1) {
1689        my $next = $self->nextToken();
1690        if ($next->type() == IdentifierToken || $next->value() eq "::") {
1691            push(@names, $self->parseScopedName());
1692        } else {
1693            last;
1694        }
1695    }
1696    return \@names;
1697}
1698
1699sub parseArgumentNameKeyword
1700{
1701    my $self = shift;
1702    my $next = $self->nextToken();
1703    if ($next->value() eq "attribute") {
1704        return $self->getToken()->value();
1705    }
1706    if ($next->value() eq "callback") {
1707        return $self->getToken()->value();
1708    }
1709    if ($next->value() eq "const") {
1710        return $self->getToken()->value();
1711    }
1712    if ($next->value() eq "creator") {
1713        return $self->getToken()->value();
1714    }
1715    if ($next->value() eq "deleter") {
1716        return $self->getToken()->value();
1717    }
1718    if ($next->value() eq "dictionary") {
1719        return $self->getToken()->value();
1720    }
1721    if ($next->value() eq "enum") {
1722        return $self->getToken()->value();
1723    }
1724    if ($next->value() eq "exception") {
1725        return $self->getToken()->value();
1726    }
1727    if ($next->value() eq "getter") {
1728        return $self->getToken()->value();
1729    }
1730    if ($next->value() eq "implements") {
1731        return $self->getToken()->value();
1732    }
1733    if ($next->value() eq "inherit") {
1734        return $self->getToken()->value();
1735    }
1736    if ($next->value() eq "interface") {
1737        return $self->getToken()->value();
1738    }
1739    if ($next->value() eq "legacycaller") {
1740        return $self->getToken()->value();
1741    }
1742    if ($next->value() eq "partial") {
1743        return $self->getToken()->value();
1744    }
1745    if ($next->value() eq "serializer") {
1746        return $self->getToken()->value();
1747    }
1748    if ($next->value() eq "setter") {
1749        return $self->getToken()->value();
1750    }
1751    if ($next->value() eq "static") {
1752        return $self->getToken()->value();
1753    }
1754    if ($next->value() eq "stringifier") {
1755        return $self->getToken()->value();
1756    }
1757    if ($next->value() eq "typedef") {
1758        return $self->getToken()->value();
1759    }
1760    if ($next->value() eq "unrestricted") {
1761        return $self->getToken()->value();
1762    }
1763    $self->assertUnexpectedToken($next->value(), __LINE__);
1764}
1765
1766sub parseType
1767{
1768    my $self = shift;
1769    my $next = $self->nextToken();
1770    if ($next->value() eq "(") {
1771        my $unionType = $self->parseUnionType();
1772        my $suffix = $self->parseTypeSuffix();
1773        die "Suffix after UnionType is not supported." if $suffix ne "";
1774        return $unionType;
1775    }
1776    if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) {
1777        return $self->parseSingleType();
1778    }
1779    $self->assertUnexpectedToken($next->value(), __LINE__);
1780}
1781
1782sub parseSingleType
1783{
1784    my $self = shift;
1785    my $next = $self->nextToken();
1786    if ($next->value() eq "any") {
1787        $self->assertTokenValue($self->getToken(), "any", __LINE__);
1788        return "any" . $self->parseTypeSuffixStartingWithArray();
1789    }
1790    if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
1791        return $self->parseNonAnyType();
1792    }
1793    $self->assertUnexpectedToken($next->value(), __LINE__);
1794}
1795
1796sub parseUnionType
1797{
1798    my $self = shift;
1799    my $next = $self->nextToken();
1800    if ($next->value() eq "(") {
1801        my $unionType = UnionType->new();
1802        $self->assertTokenValue($self->getToken(), "(", __LINE__);
1803        push @{$unionType->unionMemberTypes}, $self->parseUnionMemberType();
1804        $self->assertTokenValue($self->getToken(), "or", __LINE__);
1805        push @{$unionType->unionMemberTypes}, $self->parseUnionMemberType();
1806        push @{$unionType->unionMemberTypes}, $self->parseUnionMemberTypes();
1807        $self->assertTokenValue($self->getToken(), ")", __LINE__);
1808        return $unionType;
1809    }
1810    $self->assertUnexpectedToken($next->value(), __LINE__);
1811}
1812
1813# Returns UnionType or string
1814sub parseUnionMemberType
1815{
1816    my $self = shift;
1817    my $next = $self->nextToken();
1818    if ($next->value() eq "(") {
1819        my $unionType = $self->parseUnionType();
1820        my $suffix = $self->parseTypeSuffix();
1821        die "Suffix after UnionType is not supported." if $suffix ne "";
1822        return $unionType;
1823    }
1824    if ($next->value() eq "any") {
1825        my $type = $self->assertTokenValue($self->getToken(), "any", __LINE__);
1826        $type .= $self->assertTokenValue($self->getToken(), "[", __LINE__);
1827        $type .= $self->assertTokenValue($self->getToken(), "]", __LINE__);
1828        $type .= $self->parseTypeSuffix();
1829        return $type;
1830    }
1831    if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
1832        return $self->parseNonAnyType();
1833    }
1834    $self->assertUnexpectedToken($next->value(), __LINE__);
1835}
1836
1837sub parseUnionMemberTypes
1838{
1839    my $self = shift;
1840    my @types = ();
1841    my $next = $self->nextToken();
1842    if ($next->value() eq "or") {
1843        $self->assertTokenValue($self->getToken(), "or", __LINE__);
1844        push @types, $self->parseUnionMemberType();
1845        push @types, $self->parseUnionMemberTypes();
1846    }
1847    return @types;
1848}
1849
1850sub parseNonAnyType
1851{
1852    my $self = shift;
1853    my $next = $self->nextToken();
1854    if ($next->value() =~ /$nextNonAnyType_1/) {
1855        return $self->parsePrimitiveType() . $self->parseTypeSuffix();
1856    }
1857    if ($next->value() eq "ByteString") {
1858        $self->assertTokenValue($self->getToken(), "ByteString", __LINE__);
1859        return "ByteString" . $self->parseTypeSuffix();
1860    }
1861    if ($next->value() eq "DOMString") {
1862        $self->assertTokenValue($self->getToken(), "DOMString", __LINE__);
1863        return "DOMString" . $self->parseTypeSuffix();
1864    }
1865    if ($next->value() eq "sequence") {
1866        $self->assertTokenValue($self->getToken(), "sequence", __LINE__);
1867        $self->assertTokenValue($self->getToken(), "<", __LINE__);
1868        my $type = $self->parseType();
1869        $self->assertTokenValue($self->getToken(), ">", __LINE__);
1870        return "sequence<" . $type . ">" . $self->parseNull();
1871    }
1872    if ($next->value() eq "object") {
1873        $self->assertTokenValue($self->getToken(), "object", __LINE__);
1874        return "object" . $self->parseTypeSuffix();
1875    }
1876    if ($next->value() eq "Date") {
1877        $self->assertTokenValue($self->getToken(), "Date", __LINE__);
1878        return "Date" . $self->parseTypeSuffix();
1879    }
1880    if ($next->type() == IdentifierToken || $next->value() eq "::") {
1881        my $name = $self->parseScopedName();
1882        return $name . $self->parseTypeSuffix();
1883    }
1884    $self->assertUnexpectedToken($next->value(), __LINE__);
1885}
1886
1887sub parseConstType
1888{
1889    my $self = shift;
1890    my $next = $self->nextToken();
1891    if ($next->value() =~ /$nextNonAnyType_1/) {
1892        return $self->parsePrimitiveType() . $self->parseNull();
1893    }
1894    if ($next->type() == IdentifierToken) {
1895        my $token = $self->getToken();
1896        return $token->value() . $self->parseNull();
1897    }
1898    $self->assertUnexpectedToken($next->value(), __LINE__);
1899}
1900
1901sub parsePrimitiveType
1902{
1903    my $self = shift;
1904    my $next = $self->nextToken();
1905    if ($next->value() =~ /$nextPrimitiveType_1/) {
1906        return $self->parseUnsignedIntegerType();
1907    }
1908    if ($next->value() =~ /$nextPrimitiveType_2/) {
1909        return $self->parseUnrestrictedFloatType();
1910    }
1911    if ($next->value() eq "boolean") {
1912        $self->assertTokenValue($self->getToken(), "boolean", __LINE__);
1913        return "boolean";
1914    }
1915    if ($next->value() eq "byte") {
1916        $self->assertTokenValue($self->getToken(), "byte", __LINE__);
1917        return "byte";
1918    }
1919    if ($next->value() eq "octet") {
1920        $self->assertTokenValue($self->getToken(), "octet", __LINE__);
1921        return "octet";
1922    }
1923    $self->assertUnexpectedToken($next->value(), __LINE__);
1924}
1925
1926sub parseUnrestrictedFloatType
1927{
1928    my $self = shift;
1929    my $next = $self->nextToken();
1930    if ($next->value() eq "unrestricted") {
1931        $self->assertTokenValue($self->getToken(), "unrestricted", __LINE__);
1932        return "unrestricted " . $self->parseFloatType();
1933    }
1934    if ($next->value() =~ /$nextUnrestrictedFloatType_1/) {
1935        return $self->parseFloatType();
1936    }
1937    $self->assertUnexpectedToken($next->value(), __LINE__);
1938}
1939
1940sub parseFloatType
1941{
1942    my $self = shift;
1943    my $next = $self->nextToken();
1944    if ($next->value() eq "float") {
1945        $self->assertTokenValue($self->getToken(), "float", __LINE__);
1946        return "float";
1947    }
1948    if ($next->value() eq "double") {
1949        $self->assertTokenValue($self->getToken(), "double", __LINE__);
1950        return "double";
1951    }
1952    $self->assertUnexpectedToken($next->value(), __LINE__);
1953}
1954
1955sub parseUnsignedIntegerType
1956{
1957    my $self = shift;
1958    my $next = $self->nextToken();
1959    if ($next->value() eq "unsigned") {
1960        $self->assertTokenValue($self->getToken(), "unsigned", __LINE__);
1961        return "unsigned " . $self->parseIntegerType();
1962    }
1963    if ($next->value() =~ /$nextUnsignedIntegerType_1/) {
1964        return $self->parseIntegerType();
1965    }
1966    $self->assertUnexpectedToken($next->value(), __LINE__);
1967}
1968
1969sub parseIntegerType
1970{
1971    my $self = shift;
1972    my $next = $self->nextToken();
1973    if ($next->value() eq "short") {
1974        $self->assertTokenValue($self->getToken(), "short", __LINE__);
1975        return "short";
1976    }
1977    if ($next->value() eq "int") {
1978        $self->assertTokenValue($self->getToken(), "int", __LINE__);
1979        return "int";
1980    }
1981    if ($next->value() eq "long") {
1982        $self->assertTokenValue($self->getToken(), "long", __LINE__);
1983        if ($self->parseOptionalLong()) {
1984            return "long long";
1985        }
1986        return "long";
1987    }
1988    $self->assertUnexpectedToken($next->value(), __LINE__);
1989}
1990
1991sub parseOptionalLong
1992{
1993    my $self = shift;
1994    my $next = $self->nextToken();
1995    if ($next->value() eq "long") {
1996        $self->assertTokenValue($self->getToken(), "long", __LINE__);
1997        return 1;
1998    }
1999    return 0;
2000}
2001
2002sub parseTypeSuffix
2003{
2004    my $self = shift;
2005    my $next = $self->nextToken();
2006    if ($next->value() eq "[") {
2007        $self->assertTokenValue($self->getToken(), "[", __LINE__);
2008        $self->assertTokenValue($self->getToken(), "]", __LINE__);
2009        return "[]" . $self->parseTypeSuffix();
2010    }
2011    if ($next->value() eq "?") {
2012        $self->assertTokenValue($self->getToken(), "?", __LINE__);
2013        return "?" . $self->parseTypeSuffixStartingWithArray();
2014    }
2015    return "";
2016}
2017
2018sub parseTypeSuffixStartingWithArray
2019{
2020    my $self = shift;
2021    my $next = $self->nextToken();
2022    if ($next->value() eq "[") {
2023        $self->assertTokenValue($self->getToken(), "[", __LINE__);
2024        $self->assertTokenValue($self->getToken(), "]", __LINE__);
2025        return "[]" . $self->parseTypeSuffix();
2026    }
2027    return "";
2028}
2029
2030sub parseNull
2031{
2032    my $self = shift;
2033    my $next = $self->nextToken();
2034    if ($next->value() eq "?") {
2035        $self->assertTokenValue($self->getToken(), "?", __LINE__);
2036        return "?";
2037    }
2038    return "";
2039}
2040
2041sub parseReturnType
2042{
2043    my $self = shift;
2044    my $next = $self->nextToken();
2045    if ($next->value() eq "void") {
2046        $self->assertTokenValue($self->getToken(), "void", __LINE__);
2047        return "void";
2048    }
2049    if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
2050        return $self->parseType();
2051    }
2052    $self->assertUnexpectedToken($next->value(), __LINE__);
2053}
2054
2055sub parseExceptionList
2056{
2057    my $self = shift;
2058    my $next = $self->nextToken();
2059    if ($next->value() eq "(") {
2060        my @exceptions = ();
2061        $self->assertTokenValue($self->getToken(), "(", __LINE__);
2062        push(@exceptions, @{$self->parseScopedNameList()});
2063        $self->assertTokenValue($self->getToken(), ")", __LINE__);
2064        return \@exceptions;
2065    }
2066    $self->assertUnexpectedToken($next->value(), __LINE__);
2067}
2068
2069sub parseRaises
2070{
2071    my $self = shift;
2072    my $next = $self->nextToken();
2073    if ($next->value() eq "raises") {
2074        $self->assertTokenValue($self->getToken(), "raises", __LINE__);
2075        return $self->parseExceptionList();
2076    }
2077    return [];
2078}
2079
2080sub parseOptionalSemicolon
2081{
2082    my $self = shift;
2083    my $next = $self->nextToken();
2084    if ($next->value() eq ";") {
2085        $self->assertTokenValue($self->getToken(), ";", __LINE__);
2086    }
2087}
2088
2089sub parseScopedName
2090{
2091    my $self = shift;
2092    my $next = $self->nextToken();
2093    if ($next->value() eq "::") {
2094        return $self->parseAbsoluteScopedName();
2095    }
2096    if ($next->type() == IdentifierToken) {
2097        return $self->parseRelativeScopedName();
2098    }
2099    $self->assertUnexpectedToken($next->value());
2100}
2101
2102sub parseAbsoluteScopedName
2103{
2104    my $self = shift;
2105    my $next = $self->nextToken();
2106    if ($next->value() eq "::") {
2107        $self->assertTokenValue($self->getToken(), "::");
2108        my $token = $self->getToken();
2109        $self->assertTokenType($token, IdentifierToken);
2110        return "::" . $token->value() . $self->parseScopedNameParts();
2111    }
2112    $self->assertUnexpectedToken($next->value());
2113}
2114
2115sub parseRelativeScopedName
2116{
2117    my $self = shift;
2118    my $next = $self->nextToken();
2119    if ($next->type() == IdentifierToken) {
2120        my $token = $self->getToken();
2121        return $token->value() . $self->parseScopedNameParts();
2122    }
2123    $self->assertUnexpectedToken($next->value());
2124}
2125
2126sub parseScopedNameParts
2127{
2128    my $self = shift;
2129    my @names = ();
2130
2131    while (1) {
2132        my $next = $self->nextToken();
2133        if ($next->value() eq "::") {
2134            $self->assertTokenValue($self->getToken(), "::");
2135            push(@names, "::");
2136            my $token = $self->getToken();
2137            $self->assertTokenType($token, IdentifierToken);
2138            push(@names, $token->value());
2139        } else {
2140            last;
2141        }
2142    }
2143    return join("", @names);
2144}
2145
2146sub parseScopedNameList
2147{
2148    my $self = shift;
2149    my $next = $self->nextToken();
2150    if ($next->type() == IdentifierToken || $next->value() eq "::") {
2151        my @names = ();
2152        push(@names, $self->parseScopedName());
2153        push(@names, @{$self->parseScopedNames()});
2154        return \@names;
2155    }
2156    $self->assertUnexpectedToken($next->value(), __LINE__);
2157}
2158
2159sub parseScopedNames
2160{
2161    my $self = shift;
2162    my @names = ();
2163
2164    while (1) {
2165        my $next = $self->nextToken();
2166        if ($next->value() eq ",") {
2167            $self->assertTokenValue($self->getToken(), ",");
2168            push(@names, $self->parseScopedName());
2169        } else {
2170            last;
2171        }
2172    }
2173    return \@names;
2174}
2175
2176sub applyMemberList
2177{
2178    my $interface = shift;
2179    my $members = shift;
2180
2181    for my $item (@{$members}) {
2182        if (ref($item) eq "domAttribute") {
2183            push(@{$interface->attributes}, $item);
2184            next;
2185        }
2186        if (ref($item) eq "domConstant") {
2187            push(@{$interface->constants}, $item);
2188            next;
2189        }
2190        if (ref($item) eq "domFunction") {
2191            push(@{$interface->functions}, $item);
2192            next;
2193        }
2194    }
2195}
2196
2197sub applyExtendedAttributeList
2198{
2199    my $interface = shift;
2200    my $extendedAttributeList = shift;
2201
2202    if (defined $extendedAttributeList->{"Constructors"}) {
2203        my @constructorParams = @{$extendedAttributeList->{"Constructors"}};
2204        my $index = (@constructorParams == 1) ? 0 : 1;
2205        foreach my $param (@constructorParams) {
2206            my $constructor = domFunction->new();
2207            $constructor->name("Constructor");
2208            $constructor->extendedAttributes($extendedAttributeList);
2209            $constructor->parameters($param);
2210            $constructor->overloadedIndex($index++);
2211            push(@{$interface->constructors}, $constructor);
2212        }
2213        delete $extendedAttributeList->{"Constructors"};
2214        $extendedAttributeList->{"Constructor"} = "VALUE_IS_MISSING";
2215    } elsif (defined $extendedAttributeList->{"NamedConstructor"}) {
2216        my $newDataNode = domFunction->new();
2217        $newDataNode->name("NamedConstructor");
2218        $newDataNode->extendedAttributes($extendedAttributeList);
2219        my %attributes = %{$extendedAttributeList->{"NamedConstructor"}};
2220        my @attributeKeys = keys (%attributes);
2221        my $constructorName = $attributeKeys[0];
2222        push(@{$newDataNode->parameters}, @{$attributes{$constructorName}});
2223        $extendedAttributeList->{"NamedConstructor"} = $constructorName;
2224        push(@{$interface->constructors}, $newDataNode);
2225    }
2226    if (defined $extendedAttributeList->{"CustomConstructors"}) {
2227        my @customConstructorParams = @{$extendedAttributeList->{"CustomConstructors"}};
2228        my $index = (@customConstructorParams == 1) ? 0 : 1;
2229        foreach my $param (@customConstructorParams) {
2230            my $customConstructor = domFunction->new();
2231            $customConstructor->name("CustomConstructor");
2232            $customConstructor->extendedAttributes($extendedAttributeList);
2233            $customConstructor->parameters($param);
2234            $customConstructor->overloadedIndex($index++);
2235            push(@{$interface->customConstructors}, $customConstructor);
2236        }
2237        delete $extendedAttributeList->{"CustomConstructors"};
2238        $extendedAttributeList->{"CustomConstructor"} = "VALUE_IS_MISSING";
2239    }
2240    $interface->extendedAttributes($extendedAttributeList);
2241}
2242
22431;
2244