All prototypes should call didBecomePrototype()
[WebKit.git] / Source / WebCore / bindings / scripts / IDLParser.pm
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
22 package IDLParser;
23
24 use strict;
25
26 use Carp qw<longmess>;
27 use Data::Dumper;
28
29 use preprocessor;
30 use Class::Struct;
31
32 use constant StringToken => 0;
33 use constant IntegerToken => 1;
34 use constant FloatToken => 2;
35 use constant IdentifierToken => 3;
36 use constant OtherToken => 4;
37 use constant EmptyToken => 5;
38
39 # Used to represent a parsed IDL document
40 struct( IDLDocument => {
41     interfaces => '@', # List of 'IDLInterface'
42     enumerations => '@', # List of 'IDLEnum'
43     dictionaries => '@', # List of 'IDLDictionary'
44     callbackFunctions => '@', # List of 'IDLCallbackFunction'
45     fileName => '$',
46 });
47
48 # https://heycam.github.io/webidl/#idl-types
49 struct( IDLType => {
50     name =>         '$', # Type identifier
51     isNullable =>   '$', # Is the type Nullable (T?)
52     isUnion =>      '$', # Is the type a union (T or U)
53     subtypes =>     '@', # Array of subtypes, only valid if isUnion or sequence
54     extendedAttributes => '%',
55 });
56
57 # Used to represent 'interface' blocks
58 struct( IDLInterface => {
59     type => 'IDLType',
60     parentType => 'IDLType',
61     constants => '@',    # List of 'IDLConstant'
62     operations => '@',    # List of 'IDLOperation'
63     anonymousOperations => '@', # List of 'IDLOperation'
64     attributes => '@',    # List of 'IDLAttribute'
65     constructors => '@', # Constructors, list of 'IDLOperation'
66     customConstructors => '@', # Custom constructors, list of 'IDLOperation'
67     isException => '$', # Used for exception interfaces
68     isCallback => '$', # Used for callback interfaces
69     isPartial => '$', # Used for partial interfaces
70     iterable => '$', # Used for iterable interfaces
71     mapLike => '$', # Used for mapLike interfaces
72     serializable => '$', # Used for serializable interfaces
73     extendedAttributes => '$',
74 });
75
76 # Used to represent an argument to a IDLOperation.
77 struct( IDLArgument => {
78     name => '$',
79     type => 'IDLType',
80     isVariadic => '$',
81     isOptional => '$',
82     default => '$',
83     extendedAttributes => '%',
84 });
85
86 # https://heycam.github.io/webidl/#idl-operations
87 struct( IDLOperation => {
88     name => '$',
89     type => 'IDLType', # Return type
90     arguments => '@', # List of 'IDLArgument'
91     isStatic => '$',
92     isIterable => '$',
93     isSerializer => '$',
94     isStringifier => '$',
95     isMapLike => '$',
96     specials => '@',
97     extendedAttributes => '%',
98 });
99
100
101 # https://heycam.github.io/webidl/#idl-attributes
102 struct( IDLAttribute => {
103     name => '$',
104     type => 'IDLType',
105     isStatic => '$',
106     isMapLike => '$',
107     isStringifier => '$',
108     isReadOnly => '$',
109     isInherit => '$',
110     extendedAttributes => '$',
111 });
112
113 # https://heycam.github.io/webidl/#idl-iterable
114 struct( IDLIterable => {
115     isKeyValue => '$',
116     keyType => 'IDLType',
117     valueType => 'IDLType',
118     operations => '@', # Iterable operations (entries, keys, values, [Symbol.Iterator], forEach)
119     extendedAttributes => '$',
120 });
121
122 # https://heycam.github.io/webidl/#es-maplike
123 struct( IDLMapLike => {
124     isReadOnly => '$',
125     keyType => 'IDLType',
126     valueType => 'IDLType',
127     attributes => '@', # MapLike attributes (size)
128     operations => '@', # MapLike operations (entries, keys, values, forEach, get, has and if not readonly, delete, set and clear)
129     extendedAttributes => '$',
130 });
131
132 # https://heycam.github.io/webidl/#idl-serializers
133 struct( IDLSerializable => {
134     attributes => '@', # List of attributes to serialize
135     hasAttribute => '$', # serializer = { attribute }
136     hasInherit => '$', # serializer = { inherit }
137     hasGetter => '$', # serializer = { getter }
138     operations => '@', # toJSON operation
139 });
140
141 # https://heycam.github.io/webidl/#idl-constants
142 struct( IDLConstant => {
143     name => '$',
144     type => 'IDLType',
145     value => '$',
146     extendedAttributes => '$',
147 });
148
149 # https://heycam.github.io/webidl/#idl-enums
150 struct( IDLEnum => {
151     name => '$',
152     type => 'IDLType',
153     values => '@',
154     extendedAttributes => '$',
155 });
156
157 # https://heycam.github.io/webidl/#dfn-dictionary-member
158 struct( IDLDictionaryMember => {
159     name => '$',
160     type => 'IDLType',
161     isRequired => '$',
162     default => '$',
163     extendedAttributes => '$',
164 });
165
166 # https://heycam.github.io/webidl/#idl-dictionaries
167 struct( IDLDictionary => {
168     type => 'IDLType',
169     parentType => 'IDLType',
170     members => '@', # List of 'IDLDictionaryMember'
171     extendedAttributes => '$',
172 });
173
174 # https://heycam.github.io/webidl/#idl-callback-functions
175 struct( IDLCallbackFunction => {
176     type => '$',
177     operation => 'IDLOperation',
178     extendedAttributes => '$',
179 });
180
181 # https://heycam.github.io/webidl/#idl-typedefs
182 struct( IDLTypedef => {
183     type => 'IDLType',
184 });
185
186 struct( Token => {
187     type => '$', # type of token
188     value => '$' # value of token
189 });
190
191 # Maps 'typedef name' -> Typedef
192 my %typedefs = ();
193
194 sub new {
195     my $class = shift;
196
197     my $emptyToken = Token->new();
198     $emptyToken->type(EmptyToken);
199     $emptyToken->value("empty");
200
201     my $self = {
202         DocumentContent => "",
203         EmptyToken => $emptyToken,
204         NextToken => $emptyToken,
205         Token => $emptyToken,
206         Line => "",
207         LineNumber => 1,
208         ExtendedAttributeMap => ""
209     };
210     return bless $self, $class;
211 }
212
213 sub assert
214 {
215     my $message = shift;
216
217     my $mess = longmess();
218     print Dumper($mess);
219
220     die $message;
221 }
222
223 sub assertTokenValue
224 {
225     my $self = shift;
226     my $token = shift;
227     my $value = shift;
228     my $line = shift;
229     my $msg = "Next token should be " . $value . ", but " . $token->value() . " on line " . $self->{Line};
230     if (defined ($line)) {
231         $msg .= " IDLParser.pm:" . $line;
232     }
233
234     assert $msg unless $token->value() eq $value;
235 }
236
237 sub assertTokenType
238 {
239     my $self = shift;
240     my $token = shift;
241     my $type = shift;
242     
243     assert "Next token's type should be " . $type . ", but " . $token->type() . " on line " . $self->{Line} unless $token->type() eq $type;
244 }
245
246 sub assertUnexpectedToken
247 {
248     my $self = shift;
249     my $token = shift;
250     my $line = shift;
251     my $msg = "Unexpected token " . $token . " on line " . $self->{Line};
252     if (defined ($line)) {
253         $msg .= " IDLParser.pm:" . $line;
254     }
255
256     assert $msg;
257 }
258
259 sub assertExtendedAttributesValidForContext
260 {
261     my $self = shift;
262     my $extendedAttributeList = shift;
263     my @contexts = @_;
264
265     for my $extendedAttribute (keys %{$extendedAttributeList}) {
266         # FIXME: Should this be done here, or when parsing the exteded attribute itself?
267         # Either way, we should add validation of the values, if any, at the same place.
268
269         # Extended attribute parsing collapses multiple 'Constructor' or 'CustomConstructor'
270         # attributes into a single plural version. Eventually, it would be nice if that conversion
271         # hapened later, and the parser kept things relatively simply, but for now, we just undo
272         # this transformation for the type check.
273         if ($extendedAttribute eq "Constructors") {
274             $extendedAttribute = "Constructor";
275         } elsif ($extendedAttribute eq "CustomConstructors") {
276             $extendedAttribute = "CustomConstructor";
277         }
278
279         if (!exists $self->{ExtendedAttributeMap}->{$extendedAttribute}) {
280             assert "Unknown extended attribute: '${extendedAttribute}'";
281         }
282
283         my $foundAllowedContext = 0;
284         for my $contextAllowed (@{$self->{ExtendedAttributeMap}->{$extendedAttribute}->{"contextsAllowed"}}) {
285             for my $context (@contexts) {
286                 if ($contextAllowed eq $context) {
287                     $foundAllowedContext = 1;
288                     last;
289                 }
290             }
291         }
292
293         if (!$foundAllowedContext) {
294             if (scalar(@contexts) == 1) {
295                 assert "Extended attribute '${extendedAttribute}' used in invalid context '" . $contexts[0] . "'";
296             } else {
297                 # FIXME: Improved this error message a bit.
298                 assert "Extended attribute '${extendedAttribute}' used in invalid context";
299             }
300         }
301     }
302 }
303
304 sub Parse
305 {
306     my $self = shift;
307     my $fileName = shift;
308     my $defines = shift;
309     my $preprocessor = shift;
310     my $idlAttributes = shift;
311
312     my @definitions = ();
313
314     my @lines = applyPreprocessor($fileName, $defines, $preprocessor);
315     $self->{Line} = $lines[0];
316     $self->{DocumentContent} = join(' ', @lines);
317     $self->{ExtendedAttributeMap} = $idlAttributes;
318
319     addBuiltinTypedefs();
320
321     $self->getToken();
322     eval {
323         my $result = $self->parseDefinitions();
324         push(@definitions, @{$result});
325
326         my $next = $self->nextToken();
327         $self->assertTokenType($next, EmptyToken);
328     };
329     assert $@ . " in $fileName" if $@;
330
331     my $document = IDLDocument->new();
332     $document->fileName($fileName);
333     foreach my $definition (@definitions) {
334         if (ref($definition) eq "IDLInterface") {
335             push(@{$document->interfaces}, $definition);
336         } elsif (ref($definition) eq "IDLEnum") {
337             push(@{$document->enumerations}, $definition);
338         } elsif (ref($definition) eq "IDLDictionary") {
339             push(@{$document->dictionaries}, $definition);
340         } elsif (ref($definition) eq "IDLCallbackFunction") {
341             push(@{$document->callbackFunctions}, $definition);
342         } else {
343             die "Unrecognized IDL definition kind: \"" . ref($definition) . "\"";
344         }
345     }
346     return $document;
347 }
348
349 sub ParseType
350 {
351     my ($self, $type, $idlAttributes) = @_;
352
353     $self->{Line} = $type;
354     $self->{DocumentContent} = $type;
355     $self->{ExtendedAttributeMap} = $idlAttributes;
356
357     addBuiltinTypedefs();
358
359     my $result;
360
361     $self->getToken();
362     eval {
363         $result = $self->parseType();
364
365         my $next = $self->nextToken();
366         $self->assertTokenType($next, EmptyToken);
367     };
368     assert $@ . " parsing type ${type}" if $@;
369
370     return $result;
371 }
372
373 sub nextToken
374 {
375     my $self = shift;
376     return $self->{NextToken};
377 }
378
379 sub getToken
380 {
381     my $self = shift;
382     $self->{Token} = $self->{NextToken};
383     $self->{NextToken} = $self->getTokenInternal();
384     return $self->{Token};
385 }
386
387 my $whitespaceTokenPattern = '^[\t\n\r ]*[\n\r]';
388 my $floatTokenPattern = '^(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+))';
389 my $integerTokenPattern = '^(-?[1-9][0-9]*|-?0[Xx][0-9A-Fa-f]+|-?0[0-7]*)';
390 my $stringTokenPattern = '^(\"[^\"]*\")';
391 my $identifierTokenPattern = '^([A-Z_a-z][0-9A-Z_a-z]*)';
392 my $otherTokenPattern = '^(\.\.\.|[^\t\n\r 0-9A-Z_a-z])';
393
394 sub getTokenInternal
395 {
396     my $self = shift;
397
398     if ($self->{DocumentContent} =~ /$whitespaceTokenPattern/) {
399         $self->{DocumentContent} =~ s/($whitespaceTokenPattern)//;
400         my $skipped = $1;
401         $self->{LineNumber}++ while ($skipped =~ /\n/g);
402         if ($self->{DocumentContent} =~ /^([^\n\r]+)/) {
403             $self->{Line} = $self->{LineNumber} . ":" . $1;
404         } else {
405             $self->{Line} = "Unknown";
406         }
407     }
408     $self->{DocumentContent} =~ s/^([\t\n\r ]+)//;
409     if ($self->{DocumentContent} eq "") {
410         return $self->{EmptyToken};
411     }
412
413     my $token = Token->new();
414     if ($self->{DocumentContent} =~ /$floatTokenPattern/) {
415         $token->type(FloatToken);
416         $token->value($1);
417         $self->{DocumentContent} =~ s/$floatTokenPattern//;
418         return $token;
419     }
420     if ($self->{DocumentContent} =~ /$integerTokenPattern/) {
421         $token->type(IntegerToken);
422         $token->value($1);
423         $self->{DocumentContent} =~ s/$integerTokenPattern//;
424         return $token;
425     }
426     if ($self->{DocumentContent} =~ /$stringTokenPattern/) {
427         $token->type(StringToken);
428         $token->value($1);
429         $self->{DocumentContent} =~ s/$stringTokenPattern//;
430         return $token;
431     }
432     if ($self->{DocumentContent} =~ /$identifierTokenPattern/) {
433         $token->type(IdentifierToken);
434         $token->value($1);
435         $self->{DocumentContent} =~ s/$identifierTokenPattern//;
436         return $token;
437     }
438     if ($self->{DocumentContent} =~ /$otherTokenPattern/) {
439         $token->type(OtherToken);
440         $token->value($1);
441         $self->{DocumentContent} =~ s/$otherTokenPattern//;
442         return $token;
443     }
444     die "Failed in tokenizing at " . $self->{Line};
445 }
446
447 sub unquoteString
448 {
449     my $self = shift;
450     my $quotedString = shift;
451     if ($quotedString =~ /^"([^"]*)"$/) {
452         return $1;
453     }
454     die "Failed to parse string (" . $quotedString . ") at " . $self->{Line};
455 }
456
457 sub identifierRemoveNullablePrefix
458 {
459     my $type = shift;
460     $type =~ s/^_//;
461     return $type;
462 }
463
464 sub copyExtendedAttributes
465 {
466     my $extendedAttributeList = shift;
467     my $attr = shift;
468
469     for my $key (keys %{$attr}) {
470         if ($key eq "Constructor") {
471             push(@{$extendedAttributeList->{"Constructors"}}, $attr->{$key});
472         } elsif ($key eq "Constructors") {
473             my @constructors = @{$attr->{$key}};
474             foreach my $constructor (@constructors) {
475                 push(@{$extendedAttributeList->{"Constructors"}}, $constructor);
476             }
477         } elsif ($key eq "CustomConstructor") {
478             push(@{$extendedAttributeList->{"CustomConstructors"}}, $attr->{$key});
479         } elsif ($key eq "CustomConstructors") {
480            my @customConstructors = @{$attr->{$key}};
481             foreach my $customConstructor (@customConstructors) {
482                 push(@{$extendedAttributeList->{"CustomConstructors"}}, $customConstructor);
483             }
484         } else {
485             $extendedAttributeList->{$key} = $attr->{$key};
486         }
487     }
488 }
489
490 sub isExtendedAttributeApplicableToTypes
491 {
492     my $self = shift;
493     my $extendedAttribute = shift;
494
495     if (!exists $self->{ExtendedAttributeMap}->{$extendedAttribute}) {
496         assert "Unknown extended attribute: '${extendedAttribute}'";
497     }
498
499     for my $contextAllowed (@{$self->{ExtendedAttributeMap}->{$extendedAttribute}->{"contextsAllowed"}}) {
500         if ($contextAllowed eq "type") {
501             return 1;
502         }
503     }
504
505     return 0;
506 }
507
508 sub moveExtendedAttributesApplicableToTypes
509 {
510     my $self = shift;
511     my $type = shift;
512     my $extendedAttributeList = shift;
513
514     for my $key (keys %{$extendedAttributeList}) {
515         if ($self->isExtendedAttributeApplicableToTypes($key)) {
516             if (!defined $type->extendedAttributes->{$key}) {
517                 $type->extendedAttributes->{$key} = $extendedAttributeList->{$key};
518             }
519             delete $extendedAttributeList->{$key};
520         }
521     }
522 }
523
524 sub typeDescription
525 {
526     my $type = shift;
527
528     if (scalar @{$type->subtypes}) {
529         return $type->name . '<' . join(', ', map { typeDescription($_) } @{$type->subtypes}) . '>' . ($type->isNullable ? "?" : "");
530     }
531
532     return $type->name . ($type->isNullable ? "?" : "");
533 }
534
535 sub cloneType
536 {
537     my $type = shift;
538
539     my $clonedType = IDLType->new();
540     $clonedType->name($type->name);
541     $clonedType->isNullable($type->isNullable);
542     $clonedType->isUnion($type->isUnion);
543
544     copyExtendedAttributes($clonedType->extendedAttributes, $type->extendedAttributes);
545
546     foreach my $subtype (@{$type->subtypes}) {
547         push(@{$clonedType->subtypes}, cloneType($subtype));
548     }
549
550     return $clonedType;
551 }
552
553 sub cloneArgument
554 {
555     my $argument = shift;
556
557     my $clonedArgument = IDLArgument->new();
558     $clonedArgument->name($argument->name);
559     $clonedArgument->type(cloneType($argument->type));
560     $clonedArgument->isVariadic($argument->isVariadic);
561     $clonedArgument->isOptional($argument->isOptional);
562     $clonedArgument->default($argument->default);
563     copyExtendedAttributes($clonedArgument->extendedAttributes, $argument->extendedAttributes);
564
565     return $clonedArgument;
566 }
567
568 sub cloneOperation
569 {
570     my $operation = shift;
571
572     my $clonedOperation = IDLOperation->new();
573     $clonedOperation->name($operation->name);
574     $clonedOperation->type(cloneType($operation->type));
575     
576     foreach my $argument (@{$operation->arguments}) {
577         push(@{$clonedOperation->arguments}, cloneArgument($argument));
578     }
579
580     $clonedOperation->isStatic($operation->isStatic);
581     $clonedOperation->isIterable($operation->isIterable);
582     $clonedOperation->isSerializer($operation->isSerializer);
583     $clonedOperation->isStringifier($operation->isStringifier);
584     $clonedOperation->isMapLike($operation->isMapLike);
585     $clonedOperation->specials($operation->specials);
586
587     copyExtendedAttributes($clonedOperation->extendedAttributes, $operation->extendedAttributes);
588
589     return $clonedOperation;
590 }
591
592 sub makeSimpleType
593 {
594     my $typeName = shift;
595
596     return IDLType->new(name => $typeName);
597 }
598
599 sub addBuiltinTypedefs()
600 {
601     # NOTE: This leaves out the ArrayBufferView definition as it is
602     # treated as its own type, and not a union, to allow us to utilize
603     # the shared base class all the members of the union have.
604
605     # typedef (ArrayBufferView or ArrayBuffer) BufferSource;
606
607     my $bufferSourceType = IDLType->new(name => "UNION", isUnion => 1);
608     push(@{$bufferSourceType->subtypes}, makeSimpleType("ArrayBufferView"));
609     push(@{$bufferSourceType->subtypes}, makeSimpleType("ArrayBuffer"));
610     $typedefs{"BufferSource"} = IDLTypedef->new(type => $bufferSourceType);
611
612     # typedef unsigned long long DOMTimeStamp;
613
614     my $DOMTimeStampType = IDLType->new(name => "unsigned long long");
615     $typedefs{"DOMTimeStamp"} = IDLTypedef->new(type => $DOMTimeStampType);
616 }
617
618 my $nextAttribute_1 = '^(attribute|inherit)$';
619 my $nextAttribute_2 = '^(readonly|attribute)$';
620 my $nextPrimitiveType_1 = '^(int|long|short|unsigned)$';
621 my $nextPrimitiveType_2 = '^(double|float|unrestricted)$';
622 my $nextArgumentList_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|double|float|in|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
623 my $nextNonAnyType_1 = '^(boolean|byte|double|float|long|octet|short|unrestricted|unsigned)$';
624 my $nextStringType_1 = '^(ByteString|DOMString|USVString)$';
625 my $nextInterfaceMember_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|setter|short|unrestricted|unsigned|void)$';
626 my $nextOperation_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|deleter|double|float|getter|legacycaller|long|object|octet|sequence|setter|short|unrestricted|unsigned|void)$';
627 my $nextUnrestrictedFloatType_1 = '^(double|float)$';
628 my $nextExtendedAttributeRest3_1 = '^(\,|\])$';
629 my $nextExceptionField_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
630 my $nextType_1 = '^(ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
631 my $nextSpecials_1 = '^(deleter|getter|legacycaller|setter)$';
632 my $nextDefinitions_1 = '^(callback|dictionary|enum|exception|interface|partial|typedef)$';
633 my $nextExceptionMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|\[|any|boolean|byte|const|double|float|long|object|octet|optional|sequence|short|unrestricted|unsigned)$';
634 my $nextInterfaceMembers_1 = '^(\(|ByteString|DOMString|USVString|Date|any|attribute|boolean|byte|const|deleter|double|float|getter|inherit|legacycaller|long|object|octet|readonly|sequence|serializer|setter|short|static|stringifier|unrestricted|unsigned|void)$';
635 my $nextSingleType_1 = '^(ByteString|DOMString|USVString|Date|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned)$';
636 my $nextArgumentName_1 = '^(attribute|callback|const|deleter|dictionary|enum|exception|getter|implements|inherit|interface|legacycaller|partial|serializer|setter|static|stringifier|typedef|unrestricted)$';
637 my $nextConstValue_1 = '^(false|true)$';
638 my $nextConstValue_2 = '^(-|Infinity|NaN)$';
639 my $nextDefinition_1 = '^(callback|interface)$';
640 my $nextOperationRest_1 = '^(\(|ByteString|DOMString|USVString|Date|any|boolean|byte|double|float|long|object|octet|sequence|short|unrestricted|unsigned|void)$';
641 my $nextUnsignedIntegerType_1 = '^(long|short)$';
642 my $nextDefaultValue_1 = '^(-|Infinity|NaN|false|null|true)$';
643
644
645 sub parseDefinitions
646 {
647     my $self = shift;
648     my @definitions = ();
649
650     while (1) {
651         my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
652         my $next = $self->nextToken();
653         my $definition;
654         if ($next->type() == IdentifierToken || $next->value() =~ /$nextDefinitions_1/) {
655             $definition = $self->parseDefinition($extendedAttributeList);
656         } else {
657             last;
658         }
659         if (defined ($definition)) {
660             push(@definitions, $definition);
661         }
662     }
663     $self->applyTypedefs(\@definitions);
664     return \@definitions;
665 }
666
667 sub applyTypedefs
668 {
669     my $self = shift;
670     my $definitions = shift;
671    
672     if (!%typedefs) {
673         return;
674     }
675     
676     foreach my $definition (@$definitions) {
677         if (ref($definition) eq "IDLInterface") {
678             foreach my $constant (@{$definition->constants}) {
679                 $constant->type($self->typeByApplyingTypedefs($constant->type));
680             }
681             foreach my $attribute (@{$definition->attributes}) {
682                 $attribute->type($self->typeByApplyingTypedefs($attribute->type));
683             }
684             foreach my $operation (@{$definition->operations}, @{$definition->anonymousOperations}, @{$definition->constructors}, @{$definition->customConstructors}) {
685                 $self->applyTypedefsToOperation($operation);
686             }
687             if ($definition->iterable) {
688                 if ($definition->iterable->keyType) {
689                     $definition->iterable->keyType($self->typeByApplyingTypedefs($definition->iterable->keyType));
690                 }
691                 if ($definition->iterable->valueType) {
692                     $definition->iterable->valueType($self->typeByApplyingTypedefs($definition->iterable->valueType));
693                 }
694                 foreach my $operation (@{$definition->iterable->operations}) {
695                     $self->applyTypedefsToOperation($operation);
696                 }
697             }
698             if ($definition->mapLike) {
699                 if ($definition->mapLike->keyType) {
700                     $definition->mapLike->keyType($self->typeByApplyingTypedefs($definition->mapLike->keyType));
701                 }
702                 if ($definition->mapLike->valueType) {
703                     $definition->mapLike->valueType($self->typeByApplyingTypedefs($definition->mapLike->valueType));
704                 }
705                 foreach my $attribute (@{$definition->mapLike->attributes}) {
706                     $attribute->type($self->typeByApplyingTypedefs($attribute->type));
707                 }
708                 foreach my $operation (@{$definition->mapLike->operations}) {
709                     $self->applyTypedefsToOperation($operation);
710                 }
711             }
712         } elsif (ref($definition) eq "IDLDictionary") {
713             foreach my $member (@{$definition->members}) {
714                 $member->type($self->typeByApplyingTypedefs($member->type));
715             }
716         } elsif (ref($definition) eq "IDLCallbackFunction") {
717             $self->applyTypedefsToOperation($definition->operation);
718         }
719     }
720 }
721
722 sub applyTypedefsToOperation
723 {
724     my $self = shift;
725     my $operation = shift;
726
727     if ($operation->type) {
728         $operation->type($self->typeByApplyingTypedefs($operation->type));
729     }
730
731     foreach my $argument (@{$operation->arguments}) {
732         $argument->type($self->typeByApplyingTypedefs($argument->type));
733     }
734 }
735
736 sub typeByApplyingTypedefs
737 {
738     my $self = shift;
739     my $type = shift;
740
741     assert("Missing type") if !$type;
742
743     my $numberOfSubtypes = scalar @{$type->subtypes};
744     if ($numberOfSubtypes) {
745         for my $i (0..$numberOfSubtypes - 1) {
746             my $subtype = @{$type->subtypes}[$i];
747             my $replacementSubtype = $self->typeByApplyingTypedefs($subtype);
748             @{$type->subtypes}[$i] = $replacementSubtype
749         }
750
751         return $type;
752     }
753
754     if (exists $typedefs{$type->name}) {
755         my $typedef = $typedefs{$type->name};
756
757         my $clonedType = cloneType($typedef->type);
758         $clonedType->isNullable($clonedType->isNullable || $type->isNullable);
759         $self->moveExtendedAttributesApplicableToTypes($clonedType, $type->extendedAttributes);
760
761         return $self->typeByApplyingTypedefs($clonedType);
762     }
763     
764     return $type;
765 }
766
767 sub parseDefinition
768 {
769     my $self = shift;
770     my $extendedAttributeList = shift;
771
772     my $next = $self->nextToken();
773     if ($next->value() =~ /$nextDefinition_1/) {
774         return $self->parseCallbackOrInterface($extendedAttributeList);
775     }
776     if ($next->value() eq "partial") {
777         return $self->parsePartial($extendedAttributeList);
778     }
779     if ($next->value() eq "dictionary") {
780         return $self->parseDictionary($extendedAttributeList);
781     }
782     if ($next->value() eq "exception") {
783         return $self->parseException($extendedAttributeList);
784     }
785     if ($next->value() eq "enum") {
786         return $self->parseEnum($extendedAttributeList);
787     }
788     if ($next->value() eq "typedef") {
789         return $self->parseTypedef($extendedAttributeList);
790     }
791     if ($next->type() == IdentifierToken) {
792         return $self->parseImplementsStatement($extendedAttributeList);
793     }
794     $self->assertUnexpectedToken($next->value(), __LINE__);
795 }
796
797 sub parseCallbackOrInterface
798 {
799     my $self = shift;
800     my $extendedAttributeList = shift;
801
802     my $next = $self->nextToken();
803     if ($next->value() eq "callback") {
804         $self->assertTokenValue($self->getToken(), "callback", __LINE__);
805         return $self->parseCallbackRestOrInterface($extendedAttributeList);
806     }
807     if ($next->value() eq "interface") {
808         return $self->parseInterface($extendedAttributeList);
809     }
810     $self->assertUnexpectedToken($next->value(), __LINE__);
811 }
812
813 sub parseCallbackRestOrInterface
814 {
815     my $self = shift;
816     my $extendedAttributeList = shift;
817
818     my $next = $self->nextToken();
819     if ($next->value() eq "interface") {
820         my $interface = $self->parseInterface($extendedAttributeList);
821         $interface->isCallback(1);
822         return $interface;
823     }
824     if ($next->type() == IdentifierToken) {
825         return $self->parseCallbackRest($extendedAttributeList);
826     }
827     $self->assertUnexpectedToken($next->value(), __LINE__);
828 }
829
830 sub parseInterface
831 {
832     my $self = shift;
833     my $extendedAttributeList = shift;
834
835     my $next = $self->nextToken();
836     if ($next->value() eq "interface") {
837         my $interface = IDLInterface->new();
838         $self->assertTokenValue($self->getToken(), "interface", __LINE__);
839         my $interfaceNameToken = $self->getToken();
840         $self->assertTokenType($interfaceNameToken, IdentifierToken);
841         
842         my $name = identifierRemoveNullablePrefix($interfaceNameToken->value());
843         $interface->type(makeSimpleType($name));
844
845         $next = $self->nextToken();
846         if ($next->value() eq ":") {
847             my $parent = $self->parseInheritance();
848             $interface->parentType(makeSimpleType($parent));
849         }
850
851         $self->assertTokenValue($self->getToken(), "{", __LINE__);
852         my $interfaceMembers = $self->parseInterfaceMembers();
853         $self->assertTokenValue($self->getToken(), "}", __LINE__);
854         $self->assertTokenValue($self->getToken(), ";", __LINE__);
855         applyMemberList($interface, $interfaceMembers);
856
857         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "interface");
858         applyExtendedAttributeList($interface, $extendedAttributeList);
859
860         return $interface;
861     }
862     $self->assertUnexpectedToken($next->value(), __LINE__);
863 }
864
865 sub parsePartial
866 {
867     my $self = shift;
868     my $extendedAttributeList = shift;
869
870     my $next = $self->nextToken();
871     if ($next->value() eq "partial") {
872         $self->assertTokenValue($self->getToken(), "partial", __LINE__);
873         return $self->parsePartialDefinition($extendedAttributeList);
874     }
875     $self->assertUnexpectedToken($next->value(), __LINE__);
876 }
877
878 sub parsePartialDefinition
879 {
880     my $self = shift;
881     my $extendedAttributeList = shift;
882
883     my $next = $self->nextToken();
884     if ($next->value() eq "interface") {
885         my $interface = $self->parseInterface($extendedAttributeList);
886         $interface->isPartial(1);
887         return $interface;
888     }
889     if ($next->value() eq "dictionary") {
890         return $self->parsePartialDictionary($extendedAttributeList);
891     }
892     $self->assertUnexpectedToken($next->value(), __LINE__);
893 }
894
895 sub parsePartialInterface
896 {
897     my $self = shift;
898     my $extendedAttributeList = shift;
899
900     my $next = $self->nextToken();
901     if ($next->value() eq "interface") {
902         $self->assertTokenValue($self->getToken(), "interface", __LINE__);
903         $self->assertTokenType($self->getToken(), IdentifierToken);
904         $self->assertTokenValue($self->getToken(), "{", __LINE__);
905         $self->parseInterfaceMembers();
906         $self->assertTokenValue($self->getToken(), "}", __LINE__);
907         $self->assertTokenValue($self->getToken(), ";", __LINE__);
908         return;
909     }
910     $self->assertUnexpectedToken($next->value(), __LINE__);
911 }
912
913 sub parseInterfaceMembers
914 {
915     my $self = shift;
916     my @interfaceMembers = ();
917
918     while (1) {
919         my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
920         my $next = $self->nextToken();
921         my $interfaceMember;
922
923         if ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMembers_1/) {
924             $interfaceMember = $self->parseInterfaceMember($extendedAttributeList);
925         } else {
926             last;
927         }
928         if (defined $interfaceMember) {
929             push(@interfaceMembers, $interfaceMember);
930         }
931     }
932     return \@interfaceMembers;
933 }
934
935 sub parseInterfaceMember
936 {
937     my $self = shift;
938     my $extendedAttributeList = shift;
939
940     my $next = $self->nextToken();
941     if ($next->value() eq "const") {
942         return $self->parseConst($extendedAttributeList);
943     }
944
945     if ($next->value() eq "serializer") {
946         return $self->parseSerializer($extendedAttributeList);
947     }
948
949     if ($next->value() eq "stringifier") {
950         return $self->parseStringifier($extendedAttributeList);
951     }
952
953     if ($next->value() eq "static") {
954         return $self->parseStaticMember($extendedAttributeList);
955     }
956
957     if ($next->value() eq "iterable") {
958         return $self->parseIterableRest($extendedAttributeList);
959     }
960
961     if ($next->value() eq "readonly") {
962         return $self->parseReadOnlyMember($extendedAttributeList);
963     }
964
965     if ($next->type() == IdentifierToken || $next->value() =~ /$nextInterfaceMember_1/) {
966         return $self->parseOperationOrReadWriteAttributeOrMaplike($extendedAttributeList);
967     }
968
969     $self->assertUnexpectedToken($next->value(), __LINE__);
970 }
971
972 sub parseDictionary
973 {
974     my $self = shift;
975     my $extendedAttributeList = shift;
976
977     my $next = $self->nextToken();
978     if ($next->value() eq "dictionary") {
979         $self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
980
981         my $dictionary = IDLDictionary->new();
982
983         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "dictionary");
984         $dictionary->extendedAttributes($extendedAttributeList);
985
986         my $nameToken = $self->getToken();
987         $self->assertTokenType($nameToken, IdentifierToken);
988
989         my $name = $nameToken->value();
990         $dictionary->type(makeSimpleType($name));
991
992         $next = $self->nextToken();
993         if ($next->value() eq ":") {
994             my $parent = $self->parseInheritance();
995             $dictionary->parentType(makeSimpleType($parent));
996         }
997         
998         $self->assertTokenValue($self->getToken(), "{", __LINE__);
999         $dictionary->members($self->parseDictionaryMembers());
1000         $self->assertTokenValue($self->getToken(), "}", __LINE__);
1001         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1002         return $dictionary;
1003     }
1004     $self->assertUnexpectedToken($next->value(), __LINE__);
1005 }
1006
1007 sub parseDictionaryMembers
1008 {
1009     my $self = shift;
1010
1011     my @members = ();
1012
1013     while (1) {
1014         my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
1015         my $next = $self->nextToken();
1016         if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
1017             push(@members, $self->parseDictionaryMember($extendedAttributeList));
1018         } else {
1019             last;
1020         }
1021     }
1022
1023     return \@members;
1024 }
1025
1026 sub parseDictionaryMember
1027 {
1028     my $self = shift;
1029     my $extendedAttributeList = shift;
1030
1031     my $next = $self->nextToken();
1032     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
1033         my $member = IDLDictionaryMember->new();
1034
1035         if ($next->value eq "required") {
1036             $self->assertTokenValue($self->getToken(), "required", __LINE__);
1037             $member->isRequired(1);
1038
1039             my $type = $self->parseTypeWithExtendedAttributes();
1040             $member->type($type);
1041         } else {
1042             $member->isRequired(0);
1043
1044             my $type = $self->parseType();
1045             $self->moveExtendedAttributesApplicableToTypes($type, $extendedAttributeList);
1046             
1047             $member->type($type);
1048         }
1049
1050         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "dictionary-member");
1051         $member->extendedAttributes($extendedAttributeList);
1052
1053         my $nameToken = $self->getToken();
1054         $self->assertTokenType($nameToken, IdentifierToken);
1055         $member->name($nameToken->value);
1056         $member->default($self->parseDefault());
1057         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1058         return $member;
1059     }
1060     $self->assertUnexpectedToken($next->value(), __LINE__);
1061 }
1062
1063 sub parsePartialDictionary
1064 {
1065     my $self = shift;
1066     my $next = $self->nextToken();
1067     if ($next->value() eq "dictionary") {
1068         $self->assertTokenValue($self->getToken(), "dictionary", __LINE__);
1069         $self->assertTokenType($self->getToken(), IdentifierToken);
1070         $self->assertTokenValue($self->getToken(), "{", __LINE__);
1071         $self->parseDictionaryMembers();
1072         $self->assertTokenValue($self->getToken(), "}", __LINE__);
1073         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1074         return;
1075     }
1076     $self->assertUnexpectedToken($next->value(), __LINE__);
1077 }
1078
1079 sub parseDefault
1080 {
1081     my $self = shift;
1082     my $next = $self->nextToken();
1083     if ($next->value() eq "=") {
1084         $self->assertTokenValue($self->getToken(), "=", __LINE__);
1085         return $self->parseDefaultValue();
1086     }
1087     return undef;
1088 }
1089
1090 sub parseDefaultValue
1091 {
1092     my $self = shift;
1093     my $next = $self->nextToken();
1094     if ($next->type() == FloatToken || $next->type() == IntegerToken || $next->value() =~ /$nextDefaultValue_1/) {
1095         return $self->parseConstValue();
1096     }
1097     if ($next->type() == StringToken) {
1098         return $self->getToken()->value();
1099     }
1100     if ($next->value() eq "[") {
1101         $self->assertTokenValue($self->getToken(), "[", __LINE__);
1102         $self->assertTokenValue($self->getToken(), "]", __LINE__);
1103         return "[]";
1104     }
1105     $self->assertUnexpectedToken($next->value(), __LINE__);
1106 }
1107
1108 sub parseException
1109 {
1110     my $self = shift;
1111     my $extendedAttributeList = shift;
1112
1113     my $next = $self->nextToken();
1114     if ($next->value() eq "exception") {
1115         my $interface = IDLInterface->new();
1116         $self->assertTokenValue($self->getToken(), "exception", __LINE__);
1117         my $exceptionNameToken = $self->getToken();
1118         $self->assertTokenType($exceptionNameToken, IdentifierToken);
1119
1120         my $name = identifierRemoveNullablePrefix($exceptionNameToken->value());
1121         $interface->type(makeSimpleType($name));
1122         $interface->isException(1);
1123
1124         $next = $self->nextToken();
1125         if ($next->value() eq ":") {
1126             my $parent = $self->parseInheritance();
1127             $interface->parentType(makeSimpleType($parent));
1128         }
1129         
1130         $self->assertTokenValue($self->getToken(), "{", __LINE__);
1131         my $exceptionMembers = $self->parseExceptionMembers();
1132         $self->assertTokenValue($self->getToken(), "}", __LINE__);
1133         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1134         applyMemberList($interface, $exceptionMembers);
1135         
1136         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "interface");
1137         applyExtendedAttributeList($interface, $extendedAttributeList);
1138
1139         return $interface;
1140     }
1141     $self->assertUnexpectedToken($next->value(), __LINE__);
1142 }
1143
1144 sub parseExceptionMembers
1145 {
1146     my $self = shift;
1147     my @members = ();
1148
1149     while (1) {
1150         my $next = $self->nextToken();
1151         if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionMembers_1/) {
1152             my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
1153             #my $member = $self->parseExceptionMember($extendedAttributeList);
1154             my $member = $self->parseInterfaceMember($extendedAttributeList);
1155             if (defined ($member)) {
1156                 push(@members, $member);
1157             }
1158         } else {
1159             last;
1160         }
1161     }
1162     return \@members;
1163 }
1164
1165 sub parseInheritance
1166 {
1167     my $self = shift;
1168
1169     my $next = $self->nextToken();
1170     if ($next->value() eq ":") {
1171         $self->assertTokenValue($self->getToken(), ":", __LINE__);
1172         return $self->parseName();
1173     }
1174     $self->assertUnexpectedToken($next->value(), __LINE__);
1175 }
1176
1177 sub parseEnum
1178 {
1179     my $self = shift;
1180     my $extendedAttributeList = shift;
1181
1182     my $next = $self->nextToken();
1183     if ($next->value() eq "enum") {
1184         my $enum = IDLEnum->new();
1185         $self->assertTokenValue($self->getToken(), "enum", __LINE__);
1186         my $enumNameToken = $self->getToken();
1187         $self->assertTokenType($enumNameToken, IdentifierToken);
1188         my $name = identifierRemoveNullablePrefix($enumNameToken->value());
1189         $enum->name($name);
1190         $enum->type(makeSimpleType($name));
1191         $self->assertTokenValue($self->getToken(), "{", __LINE__);
1192         push(@{$enum->values}, @{$self->parseEnumValueList()});
1193         $self->assertTokenValue($self->getToken(), "}", __LINE__);
1194         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1195         
1196         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "enum");
1197         $enum->extendedAttributes($extendedAttributeList);
1198         return $enum;
1199     }
1200     $self->assertUnexpectedToken($next->value(), __LINE__);
1201 }
1202
1203 sub parseEnumValueList
1204 {
1205     my $self = shift;
1206     my @values = ();
1207     my $next = $self->nextToken();
1208     if ($next->type() == StringToken) {
1209         my $enumValueToken = $self->getToken();
1210         $self->assertTokenType($enumValueToken, StringToken);
1211         my $enumValue = $self->unquoteString($enumValueToken->value());
1212         push(@values, $enumValue);
1213         push(@values, @{$self->parseEnumValues()});
1214         return \@values;
1215     }
1216     # value list must be non-empty
1217     $self->assertUnexpectedToken($next->value(), __LINE__);
1218 }
1219
1220 sub parseEnumValues
1221 {
1222     my $self = shift;
1223     my @values = ();
1224     my $next = $self->nextToken();
1225     if ($next->value() eq ",") {
1226         $self->assertTokenValue($self->getToken(), ",", __LINE__);
1227         my $enumValueToken = $self->getToken();
1228         $self->assertTokenType($enumValueToken, StringToken);
1229         my $enumValue = $self->unquoteString($enumValueToken->value());
1230         push(@values, $enumValue);
1231         push(@values, @{$self->parseEnumValues()});
1232         return \@values;
1233     }
1234     return \@values; # empty list (end of enumeration-values)
1235 }
1236
1237 sub parseCallbackRest
1238 {
1239     my $self = shift;
1240     my $extendedAttributeList = shift;
1241
1242     my $next = $self->nextToken();
1243     if ($next->type() == IdentifierToken) {
1244         my $callback = IDLCallbackFunction->new();
1245
1246         my $nameToken = $self->getToken();
1247         $self->assertTokenType($nameToken, IdentifierToken);
1248
1249         $callback->type(makeSimpleType($nameToken->value()));
1250
1251         $self->assertTokenValue($self->getToken(), "=", __LINE__);
1252
1253         my $operation = IDLOperation->new();
1254         $operation->type($self->parseReturnType());
1255         
1256         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "callback-function", "operation");
1257         $operation->extendedAttributes($extendedAttributeList);
1258
1259         $self->assertTokenValue($self->getToken(), "(", __LINE__);
1260
1261         push(@{$operation->arguments}, @{$self->parseArgumentList()});
1262
1263         $self->assertTokenValue($self->getToken(), ")", __LINE__);
1264         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1265
1266         $callback->operation($operation);
1267         $callback->extendedAttributes($extendedAttributeList);
1268
1269         return $callback;
1270     }
1271     $self->assertUnexpectedToken($next->value(), __LINE__);
1272 }
1273
1274 sub parseTypedef
1275 {
1276     my $self = shift;
1277     my $extendedAttributeList = shift;
1278     die "Extended attributes are not applicable to typedefs themselves: " . $self->{Line} if %{$extendedAttributeList};
1279
1280     my $next = $self->nextToken();
1281     if ($next->value() eq "typedef") {
1282         $self->assertTokenValue($self->getToken(), "typedef", __LINE__);
1283         my $typedef = IDLTypedef->new();
1284
1285         my $type = $self->parseTypeWithExtendedAttributes();
1286         $typedef->type($type);
1287
1288         my $nameToken = $self->getToken();
1289         $self->assertTokenType($nameToken, IdentifierToken);
1290         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1291         my $name = $nameToken->value();
1292         die "typedef redefinition for " . $name . " at " . $self->{Line} if (exists $typedefs{$name} && $typedef->type->name ne $typedefs{$name}->type->name);
1293         $typedefs{$name} = $typedef;
1294         return;
1295     }
1296     $self->assertUnexpectedToken($next->value(), __LINE__);
1297 }
1298
1299 sub parseImplementsStatement
1300 {
1301     my $self = shift;
1302     my $extendedAttributeList = shift;
1303
1304     my $next = $self->nextToken();
1305     if ($next->type() == IdentifierToken) {
1306         $self->parseName();
1307         $self->assertTokenValue($self->getToken(), "implements", __LINE__);
1308         $self->parseName();
1309         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1310         return;
1311     }
1312     $self->assertUnexpectedToken($next->value(), __LINE__);
1313 }
1314
1315 sub parseConst
1316 {
1317     my $self = shift;
1318     my $extendedAttributeList = shift;
1319
1320     my $next = $self->nextToken();
1321     if ($next->value() eq "const") {
1322         my $newDataNode = IDLConstant->new();
1323         $self->assertTokenValue($self->getToken(), "const", __LINE__);
1324         my $type = $self->parseConstType();
1325         $newDataNode->type($type);
1326         my $constNameToken = $self->getToken();
1327         $self->assertTokenType($constNameToken, IdentifierToken);
1328         $newDataNode->name(identifierRemoveNullablePrefix($constNameToken->value()));
1329         $self->assertTokenValue($self->getToken(), "=", __LINE__);
1330         $newDataNode->value($self->parseConstValue());
1331         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1332
1333         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "constant");
1334         $newDataNode->extendedAttributes($extendedAttributeList);
1335
1336         return $newDataNode;
1337     }
1338     $self->assertUnexpectedToken($next->value(), __LINE__);
1339 }
1340
1341 sub parseConstValue
1342 {
1343     my $self = shift;
1344     my $next = $self->nextToken();
1345     if ($next->value() =~ /$nextConstValue_1/) {
1346         return $self->parseBooleanLiteral();
1347     }
1348     if ($next->value() eq "null") {
1349         $self->assertTokenValue($self->getToken(), "null", __LINE__);
1350         return "null";
1351     }
1352     if ($next->type() == FloatToken || $next->value() =~ /$nextConstValue_2/) {
1353         return $self->parseFloatLiteral();
1354     }
1355     if ($next->type() == IntegerToken) {
1356         return $self->getToken()->value();
1357     }
1358     $self->assertUnexpectedToken($next->value(), __LINE__);
1359 }
1360
1361 sub parseBooleanLiteral
1362 {
1363     my $self = shift;
1364     my $next = $self->nextToken();
1365     if ($next->value() eq "true") {
1366         $self->assertTokenValue($self->getToken(), "true", __LINE__);
1367         return "true";
1368     }
1369     if ($next->value() eq "false") {
1370         $self->assertTokenValue($self->getToken(), "false", __LINE__);
1371         return "false";
1372     }
1373     $self->assertUnexpectedToken($next->value(), __LINE__);
1374 }
1375
1376 sub parseFloatLiteral
1377 {
1378     my $self = shift;
1379     my $next = $self->nextToken();
1380     if ($next->value() eq "-") {
1381         $self->assertTokenValue($self->getToken(), "-", __LINE__);
1382         $self->assertTokenValue($self->getToken(), "Infinity", __LINE__);
1383         return "-Infinity";
1384     }
1385     if ($next->value() eq "Infinity") {
1386         $self->assertTokenValue($self->getToken(), "Infinity", __LINE__);
1387         return "Infinity";
1388     }
1389     if ($next->value() eq "NaN") {
1390         $self->assertTokenValue($self->getToken(), "NaN", __LINE__);
1391         return "NaN";
1392     }
1393     if ($next->type() == FloatToken) {
1394         return $self->getToken()->value();
1395     }
1396     $self->assertUnexpectedToken($next->value(), __LINE__);
1397 }
1398
1399 sub parseOperationOrReadWriteAttributeOrMaplike
1400 {
1401     my $self = shift;
1402     my $extendedAttributeList = shift;
1403
1404     my $next = $self->nextToken();
1405     if ($next->value() =~ /$nextAttribute_1/) {
1406         return $self->parseReadWriteAttribute($extendedAttributeList);
1407     }
1408     if ($next->value() eq "maplike") {
1409         return $self->parseMapLikeRest($extendedAttributeList, 0);
1410     }
1411     if ($next->type() == IdentifierToken || $next->value() =~ /$nextOperation_1/) {
1412         return $self->parseOperation($extendedAttributeList);
1413     }
1414     $self->assertUnexpectedToken($next->value(), __LINE__);
1415 }
1416
1417 sub parseReadOnlyMember
1418 {
1419     my $self = shift;
1420     my $extendedAttributeList = shift;
1421
1422     my $next = $self->nextToken();
1423     if ($next->value() eq "readonly") {
1424         $self->assertTokenValue($self->getToken(), "readonly", __LINE__);
1425
1426         my $next = $self->nextToken();
1427         if ($next->value() eq "attribute") {
1428             my $attribute = $self->parseAttributeRest($extendedAttributeList);
1429             $attribute->isReadOnly(1);
1430             return $attribute;
1431         }
1432         if ($next->value() eq "maplike") {
1433             return $self->parseMapLikeRest($extendedAttributeList, 1);
1434         }
1435     }
1436     $self->assertUnexpectedToken($next->value(), __LINE__);
1437 }
1438
1439 sub parseSerializer
1440 {
1441     my $self = shift;
1442     my $extendedAttributeList = shift;
1443
1444     my $next = $self->nextToken();
1445     if ($next->value() eq "serializer") {
1446         $self->assertTokenValue($self->getToken(), "serializer", __LINE__);
1447         my $next = $self->nextToken();
1448         my $newDataNode;
1449         if ($next->value() ne ";") {
1450             $newDataNode = $self->parseSerializerRest($extendedAttributeList);
1451             my $next = $self->nextToken();
1452         } else {
1453             $newDataNode = IDLSerializable->new();
1454         }
1455
1456         my $toJSONOperation = IDLOperation->new();
1457         $toJSONOperation->name("toJSON");
1458
1459         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "operation");
1460         $toJSONOperation->extendedAttributes($extendedAttributeList);
1461         $toJSONOperation->isSerializer(1);
1462         push(@{$newDataNode->operations}, $toJSONOperation);
1463
1464         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1465         return $newDataNode;
1466     }
1467     $self->assertUnexpectedToken($next->value(), __LINE__);
1468 }
1469
1470 sub parseSerializerRest
1471 {
1472     my $self = shift;
1473     my $extendedAttributeList = shift;
1474
1475     my $next = $self->nextToken();
1476     if ($next->value() eq "=") {
1477         $self->assertTokenValue($self->getToken(), "=", __LINE__);
1478
1479         return $self->parseSerializationPattern();
1480
1481     }
1482     if ($next->type() == IdentifierToken || $next->value() eq "(") {
1483         return $self->parseOperationRest($extendedAttributeList);
1484     }
1485 }
1486
1487 sub parseSerializationPattern
1488 {
1489     my $self = shift;
1490
1491     my $next = $self->nextToken();
1492     if ($next->value() eq "{") {
1493         $self->assertTokenValue($self->getToken(), "{", __LINE__);
1494         my $newDataNode = IDLSerializable->new();
1495         $self->parseSerializationAttributes($newDataNode);
1496         $self->assertTokenValue($self->getToken(), "}", __LINE__);
1497         return $newDataNode;
1498     }
1499     if ($next->value() eq "[") {
1500         die "Serialization of lists pattern is not currently supported.";
1501     }
1502     if ($next->type() == IdentifierToken) {
1503         my @attributes = ();
1504         my $token = $self->getToken();
1505         $self->assertTokenType($token, IdentifierToken);
1506         push(@attributes, $token->value());
1507
1508         my $newDataNode = IDLSerializable->new();
1509         $newDataNode->attributes(\@attributes);
1510
1511         return $newDataNode;
1512     }
1513     $self->assertUnexpectedToken($next->value(), __LINE__);
1514 }
1515
1516 sub parseSerializationAttributes
1517 {
1518     my $self = shift;
1519     my $serializable = shift;
1520
1521     my @attributes = ();
1522     my @identifiers = $self->parseIdentifierList();
1523
1524     for my $identifier (@identifiers) {
1525         if ($identifier eq "getter") {
1526             $serializable->hasGetter(1);
1527             die "Serializer getter keyword is not currently supported.";
1528         }
1529
1530         if ($identifier eq "inherit") {
1531             $serializable->hasInherit(1);
1532             next;
1533         }
1534
1535         if ($identifier eq "attribute") {
1536             $serializable->hasAttribute(1);
1537             # Attributes will be filled in via applyMemberList()
1538             next;
1539         }
1540
1541         push(@attributes, $identifier);
1542     }
1543
1544     $serializable->attributes(\@attributes);
1545 }
1546
1547 sub parseIdentifierList
1548 {
1549     my $self = shift;
1550     my $next = $self->nextToken();
1551
1552     my @identifiers = ();
1553     if ($next->type == IdentifierToken) {
1554         push(@identifiers, $self->getToken()->value());
1555         push(@identifiers, @{$self->parseIdentifiers()});
1556     }
1557     return @identifiers;
1558 }
1559
1560 sub parseIdentifiers
1561 {
1562     my $self = shift;
1563     my @idents = ();
1564
1565     while (1) {
1566         my $next = $self->nextToken();
1567         if ($next->value() eq ",") {
1568             $self->assertTokenValue($self->getToken(), ",", __LINE__);
1569             my $token = $self->getToken();
1570             $self->assertTokenType($token, IdentifierToken);
1571             push(@idents, $token->value());
1572         } else {
1573             last;
1574         }
1575     }
1576     return \@idents;
1577 }
1578
1579 sub parseStringifier
1580 {
1581     my $self = shift;
1582     my $extendedAttributeList = shift;
1583
1584     my $next = $self->nextToken();
1585     if ($next->value() eq "stringifier") {
1586         $self->assertTokenValue($self->getToken(), "stringifier", __LINE__);
1587
1588         $next = $self->nextToken();
1589         if ($next->value() eq ";") {
1590             $self->assertTokenValue($self->getToken(), ";", __LINE__);
1591
1592             my $operation = IDLOperation->new();
1593             $operation->isStringifier(1);
1594             $operation->name("");
1595             $operation->type(makeSimpleType("DOMString"));
1596             $operation->extendedAttributes($extendedAttributeList);
1597
1598             return $operation;
1599         } else {
1600             my $attributeOrOperation = $self->parseAttributeOrOperationForStringifierOrStatic($extendedAttributeList);
1601             $attributeOrOperation->isStringifier(1);
1602
1603             return $attributeOrOperation;
1604         }
1605     }
1606     $self->assertUnexpectedToken($next->value(), __LINE__);
1607 }
1608
1609 sub parseStaticMember
1610 {
1611     my $self = shift;
1612     my $extendedAttributeList = shift;
1613
1614     my $next = $self->nextToken();
1615     if ($next->value() eq "static") {
1616         $self->assertTokenValue($self->getToken(), "static", __LINE__);
1617
1618         my $attributeOrOperation = $self->parseAttributeOrOperationForStringifierOrStatic($extendedAttributeList);
1619         $attributeOrOperation->isStatic(1);
1620
1621         return $attributeOrOperation;
1622     }
1623     $self->assertUnexpectedToken($next->value(), __LINE__);
1624 }
1625
1626 sub parseAttributeOrOperationForStringifierOrStatic
1627 {
1628     my $self = shift;
1629     my $extendedAttributeList = shift;
1630
1631     my $next = $self->nextToken();
1632     if ($next->value() =~ /$nextAttribute_2/) {
1633         my $isReadOnly = $self->parseReadOnly();
1634
1635         my $attribute = $self->parseAttributeRest($extendedAttributeList);
1636         $attribute->isReadOnly($isReadOnly);
1637
1638         return $attribute;
1639     }
1640
1641     if ($next->type() == IdentifierToken || $next->value() =~ /$nextOperationRest_1/) {
1642         my $returnType = $self->parseReturnType();
1643
1644         # NOTE: This is a non-standard addition. In WebIDL, there is no way to associate
1645         # extended attributes with a return type.
1646         $self->moveExtendedAttributesApplicableToTypes($returnType, $extendedAttributeList);
1647
1648         my $operation = $self->parseOperationRest($extendedAttributeList);
1649         $operation->type($returnType);
1650
1651         return $operation;
1652     }
1653     $self->assertUnexpectedToken($next->value(), __LINE__);
1654 }
1655
1656 sub parseReadWriteAttribute
1657 {
1658     my $self = shift;
1659     my $extendedAttributeList = shift;
1660
1661     my $next = $self->nextToken();
1662     if ($next->value() eq "inherit") {
1663         my $isInherit = $self->parseInherit();
1664         my $isReadOnly = $self->parseReadOnly();
1665
1666         my $attribute = $self->parseAttributeRest($extendedAttributeList);
1667
1668         $attribute->isInherit($isInherit);
1669         $attribute->isReadOnly($isReadOnly);
1670
1671         return $attribute;
1672     } else {
1673         return $self->parseAttributeRest($extendedAttributeList);
1674     }
1675     $self->assertUnexpectedToken($next->value(), __LINE__);
1676 }
1677
1678 sub parseAttributeRest
1679 {
1680     my $self = shift;
1681     my $extendedAttributeList = shift;
1682
1683     my $next = $self->nextToken();
1684     if ($next->value() eq "attribute") {
1685         $self->assertTokenValue($self->getToken(), "attribute", __LINE__);
1686
1687         my $attribute = IDLAttribute->new();
1688         
1689         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "attribute");
1690         $attribute->extendedAttributes($extendedAttributeList);
1691
1692         my $type = $self->parseTypeWithExtendedAttributes();
1693         $attribute->type($type);
1694
1695         my $token = $self->getToken();
1696         $self->assertTokenType($token, IdentifierToken);
1697         $attribute->name(identifierRemoveNullablePrefix($token->value()));
1698         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1699
1700         return $attribute;
1701     }
1702     $self->assertUnexpectedToken($next->value(), __LINE__);
1703 }
1704
1705 sub parseInherit
1706 {
1707     my $self = shift;
1708     my $next = $self->nextToken();
1709     if ($next->value() eq "inherit") {
1710         $self->assertTokenValue($self->getToken(), "inherit", __LINE__);
1711         return 1;
1712     }
1713     return 0;
1714 }
1715
1716 sub parseReadOnly
1717 {
1718     my $self = shift;
1719     my $next = $self->nextToken();
1720     if ($next->value() eq "readonly") {
1721         $self->assertTokenValue($self->getToken(), "readonly", __LINE__);
1722         return 1;
1723     }
1724     return 0;
1725 }
1726
1727 sub parseOperation
1728 {
1729     my $self = shift;
1730     my $extendedAttributeList = shift;
1731
1732     my $next = $self->nextToken();
1733     if ($next->value() =~ /$nextSpecials_1/) {
1734         return $self->parseSpecialOperation($extendedAttributeList);
1735     }
1736     if ($next->type() == IdentifierToken || $next->value() =~ /$nextOperationRest_1/) {
1737         my $returnType = $self->parseReturnType();
1738
1739         # NOTE: This is a non-standard addition. In WebIDL, there is no way to associate
1740         # extended attributes with a return type.
1741         $self->moveExtendedAttributesApplicableToTypes($returnType, $extendedAttributeList);
1742
1743         my $operation = $self->parseOperationRest($extendedAttributeList);
1744         $operation->type($returnType);
1745
1746         return $operation;
1747     }
1748     $self->assertUnexpectedToken($next->value(), __LINE__);
1749 }
1750
1751 sub parseSpecialOperation
1752 {
1753     my $self = shift;
1754     my $extendedAttributeList = shift;
1755
1756     my $next = $self->nextToken();
1757     if ($next->value() =~ /$nextSpecials_1/) {
1758         my @specials = ();
1759         push(@specials, @{$self->parseSpecials()});
1760         my $returnType = $self->parseReturnType();
1761
1762         # NOTE: This is a non-standard addition. In WebIDL, there is no way to associate
1763         # extended attributes with a return type.
1764         $self->moveExtendedAttributesApplicableToTypes($returnType, $extendedAttributeList);
1765
1766         my $operation = $self->parseOperationRest($extendedAttributeList);
1767         $operation->type($returnType);
1768         $operation->specials(\@specials);
1769
1770         return $operation;
1771     }
1772     $self->assertUnexpectedToken($next->value(), __LINE__);
1773 }
1774
1775 sub parseSpecials
1776 {
1777     my $self = shift;
1778     my @specials = ();
1779
1780     while (1) {
1781         my $next = $self->nextToken();
1782         if ($next->value() =~ /$nextSpecials_1/) {
1783             push(@specials, $self->parseSpecial());
1784         } else {
1785             last;
1786         }
1787     }
1788     return \@specials;
1789 }
1790
1791 sub parseSpecial
1792 {
1793     my $self = shift;
1794     my $next = $self->nextToken();
1795     if ($next->value() eq "getter") {
1796         $self->assertTokenValue($self->getToken(), "getter", __LINE__);
1797         return "getter";
1798     }
1799     if ($next->value() eq "setter") {
1800         $self->assertTokenValue($self->getToken(), "setter", __LINE__);
1801         return "setter";
1802     }
1803     if ($next->value() eq "deleter") {
1804         $self->assertTokenValue($self->getToken(), "deleter", __LINE__);
1805         return "deleter";
1806     }
1807     if ($next->value() eq "legacycaller") {
1808         $self->assertTokenValue($self->getToken(), "legacycaller", __LINE__);
1809         return "legacycaller";
1810     }
1811     $self->assertUnexpectedToken($next->value(), __LINE__);
1812 }
1813
1814 sub parseIterableRest
1815 {
1816     my $self = shift;
1817     my $extendedAttributeList = shift;
1818
1819     my $next = $self->nextToken();
1820     if ($next->value() eq "iterable") {
1821         $self->assertTokenValue($self->getToken(), "iterable", __LINE__);
1822         my $iterableNode = $self->parseOptionalIterableInterface($extendedAttributeList);
1823         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1824         return $iterableNode;
1825     }
1826     $self->assertUnexpectedToken($next->value(), __LINE__);
1827 }
1828
1829 sub parseOptionalIterableInterface
1830 {
1831     my $self = shift;
1832     my $extendedAttributeList = shift;
1833
1834     my $newDataNode = IDLIterable->new();
1835
1836     $self->assertExtendedAttributesValidForContext($extendedAttributeList, "iterable");
1837     $newDataNode->extendedAttributes($extendedAttributeList);
1838
1839     $self->assertTokenValue($self->getToken(), "<", __LINE__);
1840     my $type1 = $self->parseTypeWithExtendedAttributes();
1841
1842     if ($self->nextToken()->value() eq ",") {
1843         $self->assertTokenValue($self->getToken(), ",", __LINE__);
1844
1845         my $type2 = $self->parseTypeWithExtendedAttributes();
1846         $newDataNode->isKeyValue(1);
1847         $newDataNode->keyType($type1);
1848         $newDataNode->valueType($type2);
1849     } else {
1850         $newDataNode->isKeyValue(0);
1851         $newDataNode->valueType($type1);
1852     }
1853     $self->assertTokenValue($self->getToken(), ">", __LINE__);
1854
1855     my $symbolIteratorOperation = IDLOperation->new();
1856     $symbolIteratorOperation->name("[Symbol.Iterator]");
1857     $symbolIteratorOperation->extendedAttributes($extendedAttributeList);
1858     $symbolIteratorOperation->isIterable(1);
1859
1860     my $entriesOperation = IDLOperation->new();
1861     $entriesOperation->name("entries");
1862     $entriesOperation->extendedAttributes($extendedAttributeList);
1863     $entriesOperation->isIterable(1);
1864
1865     my $keysOperation = IDLOperation->new();
1866     $keysOperation->name("keys");
1867     $keysOperation->extendedAttributes($extendedAttributeList);
1868     $keysOperation->isIterable(1);
1869
1870     my $valuesOperation = IDLOperation->new();
1871     $valuesOperation->name("values");
1872     $valuesOperation->extendedAttributes($extendedAttributeList);
1873     $valuesOperation->isIterable(1);
1874
1875     my $forEachOperation = IDLOperation->new();
1876     $forEachOperation->name("forEach");
1877     $forEachOperation->extendedAttributes($extendedAttributeList);
1878     $forEachOperation->isIterable(1);
1879     my $forEachArgument = IDLArgument->new();
1880     $forEachArgument->name("callback");
1881     $forEachArgument->type(makeSimpleType("any"));
1882     push(@{$forEachOperation->arguments}, ($forEachArgument));
1883
1884     push(@{$newDataNode->operations}, $symbolIteratorOperation);
1885     push(@{$newDataNode->operations}, $entriesOperation);
1886     push(@{$newDataNode->operations}, $keysOperation);
1887     push(@{$newDataNode->operations}, $valuesOperation);
1888     push(@{$newDataNode->operations}, $forEachOperation);
1889
1890     return $newDataNode;
1891 }
1892
1893 sub parseMapLikeRest
1894 {
1895     my $self = shift;
1896     my $extendedAttributeList = shift;
1897     my $isReadOnly = shift;
1898
1899     my $next = $self->nextToken();
1900     if ($next->value() eq "maplike") {
1901         $self->assertTokenValue($self->getToken(), "maplike", __LINE__);
1902         my $mapLikeNode = $self->parseMapLikeProperties($extendedAttributeList, $isReadOnly);
1903         $self->assertTokenValue($self->getToken(), ";", __LINE__);
1904         return $mapLikeNode;
1905     }
1906     $self->assertUnexpectedToken($next->value(), __LINE__);
1907 }
1908
1909 sub parseMapLikeProperties
1910 {
1911     my $self = shift;
1912     my $extendedAttributeList = shift;
1913     my $isReadOnly = shift;
1914
1915     my $maplike = IDLMapLike->new();
1916     $maplike->extendedAttributes($extendedAttributeList);
1917     $maplike->isReadOnly($isReadOnly);
1918
1919     $self->assertTokenValue($self->getToken(), "<", __LINE__);
1920     $maplike->keyType($self->parseTypeWithExtendedAttributes());
1921     $self->assertTokenValue($self->getToken(), ",", __LINE__);
1922     $maplike->valueType($self->parseTypeWithExtendedAttributes());
1923     $self->assertTokenValue($self->getToken(), ">", __LINE__);
1924
1925     # FIXME: Synthetic operations should not be added during parsing. Instead, the CodeGenerator
1926     # should be responsible for them.
1927
1928     my $notEnumerableExtendedAttributeList = $extendedAttributeList;
1929     $notEnumerableExtendedAttributeList->{NotEnumerable} = 1;
1930
1931     my $sizeAttribute = IDLAttribute->new();
1932     $sizeAttribute->name("size");
1933     $sizeAttribute->isMapLike(1);
1934     $sizeAttribute->extendedAttributes($extendedAttributeList);
1935     $sizeAttribute->isReadOnly(1);
1936     $sizeAttribute->type(makeSimpleType("any"));
1937     push(@{$maplike->attributes}, $sizeAttribute);
1938
1939     my $getOperation = IDLOperation->new();
1940     $getOperation->name("get");
1941     $getOperation->isMapLike(1);
1942     my $getArgument = IDLArgument->new();
1943     $getArgument->name("key");
1944     $getArgument->type($maplike->keyType);
1945     $getArgument->extendedAttributes($extendedAttributeList);
1946     push(@{$getOperation->arguments}, ($getArgument));
1947     $getOperation->extendedAttributes($notEnumerableExtendedAttributeList);
1948     $getOperation->type(makeSimpleType("any"));
1949
1950     my $hasOperation = IDLOperation->new();
1951     $hasOperation->name("has");
1952     $hasOperation->isMapLike(1);
1953     my $hasArgument = IDLArgument->new();
1954     $hasArgument->name("key");
1955     $hasArgument->type($maplike->keyType);
1956     $hasArgument->extendedAttributes($extendedAttributeList);
1957     push(@{$hasOperation->arguments}, ($hasArgument));
1958     $hasOperation->extendedAttributes($notEnumerableExtendedAttributeList);
1959     $hasOperation->type(makeSimpleType("any"));
1960
1961     my $entriesOperation = IDLOperation->new();
1962     $entriesOperation->name("entries");
1963     $entriesOperation->isMapLike(1);
1964     $entriesOperation->extendedAttributes($notEnumerableExtendedAttributeList);
1965     $entriesOperation->type(makeSimpleType("any"));
1966
1967     my $keysOperation = IDLOperation->new();
1968     $keysOperation->name("keys");
1969     $keysOperation->isMapLike(1);
1970     $keysOperation->extendedAttributes($notEnumerableExtendedAttributeList);
1971     $keysOperation->type(makeSimpleType("any"));
1972
1973     my $valuesOperation = IDLOperation->new();
1974     $valuesOperation->name("values");
1975     $valuesOperation->isMapLike(1);
1976     $valuesOperation->extendedAttributes($extendedAttributeList);
1977     $valuesOperation->extendedAttributes->{NotEnumerable} = 1;
1978     $valuesOperation->type(makeSimpleType("any"));
1979
1980     my $forEachOperation = IDLOperation->new();
1981     $forEachOperation->name("forEach");
1982     $forEachOperation->isMapLike(1);
1983     $forEachOperation->extendedAttributes({});
1984     $forEachOperation->type(makeSimpleType("any"));
1985     my $forEachArgument = IDLArgument->new();
1986     $forEachArgument->name("callback");
1987     $forEachArgument->type(makeSimpleType("any"));
1988     $forEachArgument->extendedAttributes($extendedAttributeList);
1989     push(@{$forEachOperation->arguments}, ($forEachArgument));
1990
1991     push(@{$maplike->operations}, $getOperation);
1992     push(@{$maplike->operations}, $hasOperation);
1993     push(@{$maplike->operations}, $entriesOperation);
1994     push(@{$maplike->operations}, $keysOperation);
1995     push(@{$maplike->operations}, $valuesOperation);
1996     push(@{$maplike->operations}, $forEachOperation);
1997
1998     return $maplike if $isReadOnly;
1999
2000     my $addOperation = IDLOperation->new();
2001     $addOperation->name("add");
2002     $addOperation->isMapLike(1);
2003     my $addArgument = IDLArgument->new();
2004     $addArgument->name("key");
2005     $addArgument->type($maplike->keyType);
2006     $addArgument->extendedAttributes($extendedAttributeList);
2007     push(@{$addOperation->arguments}, ($addArgument));
2008     $addOperation->extendedAttributes($notEnumerableExtendedAttributeList);
2009     $addOperation->type(makeSimpleType("any"));
2010
2011     my $clearOperation = IDLOperation->new();
2012     $clearOperation->name("clear");
2013     $clearOperation->isMapLike(1);
2014     $clearOperation->extendedAttributes($notEnumerableExtendedAttributeList);
2015     $clearOperation->type(makeSimpleType("void"));
2016
2017     my $deleteOperation = IDLOperation->new();
2018     $deleteOperation->name("delete");
2019     $deleteOperation->isMapLike(1);
2020     my $deleteArgument = IDLArgument->new();
2021     $deleteArgument->name("key");
2022     $deleteArgument->type($maplike->keyType);
2023     $deleteArgument->extendedAttributes($extendedAttributeList);
2024     push(@{$deleteOperation->arguments}, ($deleteArgument));
2025     $deleteOperation->extendedAttributes($notEnumerableExtendedAttributeList);
2026     $deleteOperation->type(makeSimpleType("any"));
2027
2028     push(@{$maplike->operations}, $addOperation);
2029     push(@{$maplike->operations}, $clearOperation);
2030     push(@{$maplike->operations}, $deleteOperation);
2031
2032     return $maplike;
2033 }
2034
2035 sub parseOperationRest
2036 {
2037     my $self = shift;
2038     my $extendedAttributeList = shift;
2039
2040     my $next = $self->nextToken();
2041     if ($next->type() == IdentifierToken || $next->value() eq "(") {
2042         my $operation = IDLOperation->new();
2043
2044         my $name = $self->parseOptionalIdentifier();
2045         $operation->name(identifierRemoveNullablePrefix($name));
2046
2047         $self->assertTokenValue($self->getToken(), "(", $name, __LINE__);
2048
2049         push(@{$operation->arguments}, @{$self->parseArgumentList()});
2050
2051         $self->assertTokenValue($self->getToken(), ")", __LINE__);
2052         $self->assertTokenValue($self->getToken(), ";", __LINE__);
2053
2054         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "operation");
2055         $operation->extendedAttributes($extendedAttributeList);
2056
2057         return $operation;
2058     }
2059     $self->assertUnexpectedToken($next->value(), __LINE__);
2060 }
2061
2062 sub parseOptionalIdentifier
2063 {
2064     my $self = shift;
2065     my $next = $self->nextToken();
2066     if ($next->type() == IdentifierToken) {
2067         my $token = $self->getToken();
2068         return $token->value();
2069     }
2070     return "";
2071 }
2072
2073 sub parseArgumentList
2074 {
2075     my $self = shift;
2076     my @arguments = ();
2077
2078     my $next = $self->nextToken();
2079     if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
2080         push(@arguments, $self->parseArgument());
2081         push(@arguments, @{$self->parseArguments()});
2082     }
2083     return \@arguments;
2084 }
2085
2086 sub parseArguments
2087 {
2088     my $self = shift;
2089     my @arguments = ();
2090
2091     while (1) {
2092         my $next = $self->nextToken();
2093         if ($next->value() eq ",") {
2094             $self->assertTokenValue($self->getToken(), ",", __LINE__);
2095             push(@arguments, $self->parseArgument());
2096         } else {
2097             last;
2098         }
2099     }
2100     return \@arguments;
2101 }
2102
2103 sub parseArgument
2104 {
2105     my $self = shift;
2106     my $next = $self->nextToken();
2107     if ($next->type() == IdentifierToken || $next->value() =~ /$nextArgumentList_1/) {
2108         my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
2109         my $argument = $self->parseOptionalOrRequiredArgument($extendedAttributeList);
2110         return $argument;
2111     }
2112     $self->assertUnexpectedToken($next->value(), __LINE__);
2113 }
2114
2115 sub parseOptionalOrRequiredArgument
2116 {
2117     my $self = shift;
2118     my $extendedAttributeList = shift;
2119
2120     my $argument = IDLArgument->new();
2121
2122     my $next = $self->nextToken();
2123     if ($next->value() eq "optional") {
2124         $self->assertTokenValue($self->getToken(), "optional", __LINE__);
2125
2126         my $type = $self->parseTypeWithExtendedAttributes();
2127         $argument->type($type);
2128         $argument->isOptional(1);
2129         $argument->name($self->parseArgumentName());
2130         $argument->default($self->parseDefault());
2131
2132         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "argument");
2133         $argument->extendedAttributes($extendedAttributeList);
2134
2135         return $argument;
2136     }
2137     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
2138         my $type = $self->parseType();
2139         $self->moveExtendedAttributesApplicableToTypes($type, $extendedAttributeList);
2140
2141         $argument->type($type);
2142         $argument->isOptional(0);
2143         $argument->isVariadic($self->parseEllipsis());
2144         $argument->name($self->parseArgumentName());
2145
2146         $self->assertExtendedAttributesValidForContext($extendedAttributeList, "argument");
2147         $argument->extendedAttributes($extendedAttributeList);
2148
2149         return $argument;
2150     }
2151     $self->assertUnexpectedToken($next->value(), __LINE__);
2152 }
2153
2154 sub parseArgumentName
2155 {
2156     my $self = shift;
2157     my $next = $self->nextToken();
2158     if ($next->value() =~ /$nextArgumentName_1/) {
2159         return $self->parseArgumentNameKeyword();
2160     }
2161     if ($next->type() == IdentifierToken) {
2162         return $self->getToken()->value();
2163     }
2164     $self->assertUnexpectedToken($next->value(), __LINE__);
2165 }
2166
2167 sub parseEllipsis
2168 {
2169     my $self = shift;
2170     my $next = $self->nextToken();
2171     if ($next->value() eq "...") {
2172         $self->assertTokenValue($self->getToken(), "...", __LINE__);
2173         return 1;
2174     }
2175     return 0;
2176 }
2177
2178 sub parseExceptionMember
2179 {
2180     my $self = shift;
2181     my $extendedAttributeList = shift;
2182
2183     my $next = $self->nextToken();
2184     if ($next->value() eq "const") {
2185         return $self->parseConst($extendedAttributeList);
2186     }
2187     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
2188         return $self->parseExceptionField($extendedAttributeList);
2189     }
2190     $self->assertUnexpectedToken($next->value(), __LINE__);
2191 }
2192
2193 sub parseExceptionField
2194 {
2195     my $self = shift;
2196     my $extendedAttributeList = shift;
2197
2198     my $next = $self->nextToken();
2199     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
2200         my $newDataNode = IDLAttribute->new();
2201         $newDataNode->isReadOnly(1);
2202
2203         my $type = $self->parseType();
2204         $newDataNode->type($type);
2205         
2206         my $token = $self->getToken();
2207         $self->assertTokenType($token, IdentifierToken);
2208         $newDataNode->name(identifierRemoveNullablePrefix($token->value()));
2209         $self->assertTokenValue($self->getToken(), ";", __LINE__);
2210         $newDataNode->extendedAttributes($extendedAttributeList);
2211         return $newDataNode;
2212     }
2213     $self->assertUnexpectedToken($next->value(), __LINE__);
2214 }
2215
2216 sub parseExtendedAttributeListAllowEmpty
2217 {
2218     my $self = shift;
2219     my $next = $self->nextToken();
2220     if ($next->value() eq "[") {
2221         return $self->parseExtendedAttributeList();
2222     }
2223     return {};
2224 }
2225
2226 sub parseExtendedAttributeList
2227 {
2228     my $self = shift;
2229     my $next = $self->nextToken();
2230     if ($next->value() eq "[") {
2231         $self->assertTokenValue($self->getToken(), "[", __LINE__);
2232         my $extendedAttributeList = {};
2233         my $attr = $self->parseExtendedAttribute();
2234         copyExtendedAttributes($extendedAttributeList, $attr);
2235         $attr = $self->parseExtendedAttributes();
2236         copyExtendedAttributes($extendedAttributeList, $attr);
2237         $self->assertTokenValue($self->getToken(), "]", __LINE__);
2238         return $extendedAttributeList;
2239     }
2240     $self->assertUnexpectedToken($next->value(), __LINE__);
2241 }
2242
2243 sub parseExtendedAttributes
2244 {
2245     my $self = shift;
2246     my $extendedAttributeList = {};
2247
2248     while (1) {
2249         my $next = $self->nextToken();
2250         if ($next->value() eq ",") {
2251             $self->assertTokenValue($self->getToken(), ",", __LINE__);
2252             my $attr = $self->parseExtendedAttribute2();
2253             copyExtendedAttributes($extendedAttributeList, $attr);
2254         } else {
2255             last;
2256         }
2257     }
2258     return $extendedAttributeList;
2259 }
2260
2261 sub parseExtendedAttribute
2262 {
2263     my $self = shift;
2264     my $next = $self->nextToken();
2265     if ($next->type() == IdentifierToken) {
2266         my $name = $self->parseName();
2267         return $self->parseExtendedAttributeRest($name);
2268     }
2269     # backward compatibility. Spec doesn' allow "[]". But WebKit requires.
2270     if ($next->value() eq ']') {
2271         return {};
2272     }
2273     $self->assertUnexpectedToken($next->value(), __LINE__);
2274 }
2275
2276 sub parseExtendedAttribute2
2277 {
2278     my $self = shift;
2279     my $next = $self->nextToken();
2280     if ($next->type() == IdentifierToken) {
2281         my $name = $self->parseName();
2282         return $self->parseExtendedAttributeRest($name);
2283     }
2284     return {};
2285 }
2286
2287 sub parseExtendedAttributeRest
2288 {
2289     my $self = shift;
2290     my $name = shift;
2291     my $attrs = {};
2292
2293     my $next = $self->nextToken();
2294     if ($next->value() eq "(") {
2295         $self->assertTokenValue($self->getToken(), "(", __LINE__);
2296         $attrs->{$name} = $self->parseArgumentList();
2297         $self->assertTokenValue($self->getToken(), ")", __LINE__);
2298         return $attrs;
2299     }
2300     if ($next->value() eq "=") {
2301         $self->assertTokenValue($self->getToken(), "=", __LINE__);
2302         $attrs->{$name} = $self->parseExtendedAttributeRest2();
2303         return $attrs;
2304     }
2305
2306     if ($name eq "Constructor" || $name eq "CustomConstructor") {
2307         $attrs->{$name} = [];
2308     } else {
2309         $attrs->{$name} = "VALUE_IS_MISSING";
2310     }
2311     return $attrs;
2312 }
2313
2314 sub parseExtendedAttributeRest2
2315 {
2316     my $self = shift;
2317     my $next = $self->nextToken();
2318     if ($next->value() eq "(") {
2319         $self->assertTokenValue($self->getToken(), "(", __LINE__);
2320         my @arguments = $self->parseIdentifierList();
2321         $self->assertTokenValue($self->getToken(), ")", __LINE__);
2322         return \@arguments;
2323     }
2324     if ($next->type() == IdentifierToken) {
2325         my $name = $self->parseName();
2326         return $self->parseExtendedAttributeRest3($name);
2327     }
2328     if ($next->type() == IntegerToken) {
2329         my $token = $self->getToken();
2330         return $token->value();
2331     }
2332     $self->assertUnexpectedToken($next->value(), __LINE__);
2333 }
2334
2335 sub parseExtendedAttributeRest3
2336 {
2337     my $self = shift;
2338     my $name = shift;
2339
2340     my $next = $self->nextToken();
2341     if ($next->value() eq "&") {
2342         $self->assertTokenValue($self->getToken(), "&", __LINE__);
2343         my $rightValue = $self->parseName();
2344         return $name . "&" . $rightValue;
2345     }
2346     if ($next->value() eq "|") {
2347         $self->assertTokenValue($self->getToken(), "|", __LINE__);
2348         my $rightValue = $self->parseName();
2349         return $name . "|" . $rightValue;
2350     }
2351     if ($next->value() eq "(") {
2352         my $attr = {};
2353         $self->assertTokenValue($self->getToken(), "(", __LINE__);
2354         $attr->{$name} = $self->parseArgumentList();
2355         $self->assertTokenValue($self->getToken(), ")", __LINE__);
2356         return $attr;
2357     }
2358     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExtendedAttributeRest3_1/) {
2359         $self->parseNameNoComma();
2360         return $name;
2361     }
2362     $self->assertUnexpectedToken($next->value());
2363 }
2364
2365 sub parseArgumentNameKeyword
2366 {
2367     my $self = shift;
2368     my $next = $self->nextToken();
2369     if ($next->value() eq "attribute") {
2370         return $self->getToken()->value();
2371     }
2372     if ($next->value() eq "callback") {
2373         return $self->getToken()->value();
2374     }
2375     if ($next->value() eq "const") {
2376         return $self->getToken()->value();
2377     }
2378     if ($next->value() eq "deleter") {
2379         return $self->getToken()->value();
2380     }
2381     if ($next->value() eq "dictionary") {
2382         return $self->getToken()->value();
2383     }
2384     if ($next->value() eq "enum") {
2385         return $self->getToken()->value();
2386     }
2387     if ($next->value() eq "exception") {
2388         return $self->getToken()->value();
2389     }
2390     if ($next->value() eq "getter") {
2391         return $self->getToken()->value();
2392     }
2393     if ($next->value() eq "implements") {
2394         return $self->getToken()->value();
2395     }
2396     if ($next->value() eq "inherit") {
2397         return $self->getToken()->value();
2398     }
2399     if ($next->value() eq "interface") {
2400         return $self->getToken()->value();
2401     }
2402     if ($next->value() eq "legacycaller") {
2403         return $self->getToken()->value();
2404     }
2405     if ($next->value() eq "partial") {
2406         return $self->getToken()->value();
2407     }
2408     if ($next->value() eq "serializer") {
2409         return $self->getToken()->value();
2410     }
2411     if ($next->value() eq "setter") {
2412         return $self->getToken()->value();
2413     }
2414     if ($next->value() eq "static") {
2415         return $self->getToken()->value();
2416     }
2417     if ($next->value() eq "stringifier") {
2418         return $self->getToken()->value();
2419     }
2420     if ($next->value() eq "typedef") {
2421         return $self->getToken()->value();
2422     }
2423     if ($next->value() eq "unrestricted") {
2424         return $self->getToken()->value();
2425     }
2426     $self->assertUnexpectedToken($next->value(), __LINE__);
2427 }
2428
2429 sub parseType
2430 {
2431     my $self = shift;
2432     my $next = $self->nextToken();
2433
2434     my $extendedAttributeList = {};
2435
2436     if ($next->value() eq "(") {
2437         my $unionType = $self->parseUnionType();
2438         $unionType->isNullable($self->parseNull());
2439         $unionType->extendedAttributes($extendedAttributeList);
2440         return $unionType;
2441     }
2442     if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) {
2443         my $singleType = $self->parseSingleType();
2444         $singleType->extendedAttributes($extendedAttributeList);
2445         return $singleType;
2446     }
2447     $self->assertUnexpectedToken($next->value(), __LINE__);
2448 }
2449
2450 sub parseTypeWithExtendedAttributes
2451 {
2452     my $self = shift;
2453     
2454     my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
2455     $self->assertExtendedAttributesValidForContext($extendedAttributeList, "type");
2456
2457     my $next = $self->nextToken();
2458     if ($next->value() eq "(") {
2459         my $unionType = $self->parseUnionType();
2460         $unionType->isNullable($self->parseNull());
2461         $unionType->extendedAttributes($extendedAttributeList);
2462         return $unionType;
2463     }
2464     if ($next->type() == IdentifierToken || $next->value() =~ /$nextType_1/) {
2465         my $singleType = $self->parseSingleType();
2466         $singleType->extendedAttributes($extendedAttributeList);
2467         return $singleType;
2468     }
2469     $self->assertUnexpectedToken($next->value(), __LINE__);
2470 }
2471
2472 sub parseSingleType
2473 {
2474     my $self = shift;
2475     my $next = $self->nextToken();
2476     if ($next->value() eq "any") {
2477         $self->assertTokenValue($self->getToken(), "any", __LINE__);
2478         
2479         my $anyType = IDLType->new();
2480         $anyType->name("any");
2481         return $anyType;
2482     }
2483     if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
2484         my $nonAnyType = $self->parseNonAnyType();
2485         $nonAnyType->isNullable($self->parseNull());
2486         return $nonAnyType;
2487     }
2488     $self->assertUnexpectedToken($next->value(), __LINE__);
2489 }
2490
2491 sub parseUnionType
2492 {
2493     my $self = shift;
2494     my $next = $self->nextToken();
2495
2496     my $unionType = IDLType->new();
2497     $unionType->name("UNION");
2498     $unionType->isUnion(1);
2499
2500     if ($next->value() eq "(") {
2501         $self->assertTokenValue($self->getToken(), "(", __LINE__);
2502         
2503         push(@{$unionType->subtypes}, $self->parseUnionMemberType());
2504         push(@{$unionType->subtypes}, $self->parseUnionMemberTypes());
2505         
2506         $self->assertTokenValue($self->getToken(), ")", __LINE__);
2507
2508         return $unionType;
2509     }
2510     $self->assertUnexpectedToken($next->value(), __LINE__);
2511 }
2512
2513 sub parseUnionMemberType
2514 {
2515     my $self = shift;
2516
2517     my $extendedAttributeList = $self->parseExtendedAttributeListAllowEmpty();
2518     $self->assertExtendedAttributesValidForContext($extendedAttributeList, "type");
2519
2520     my $next = $self->nextToken();
2521
2522     if ($next->value() eq "(") {
2523         my $unionType = $self->parseUnionType();
2524         $unionType->isNullable($self->parseNull());
2525         $unionType->extendedAttributes($extendedAttributeList);
2526         return $unionType;
2527     }
2528
2529     if ($next->type() == IdentifierToken || $next->value() =~ /$nextSingleType_1/) {
2530         my $nonAnyType = $self->parseNonAnyType();
2531         $nonAnyType->isNullable($self->parseNull());
2532         $nonAnyType->extendedAttributes($extendedAttributeList);
2533         return $nonAnyType;
2534     }
2535     $self->assertUnexpectedToken($next->value(), __LINE__);
2536 }
2537
2538 sub parseUnionMemberTypes
2539 {
2540     my $self = shift;
2541     my $next = $self->nextToken();
2542
2543     my @subtypes = ();
2544
2545     if ($next->value() eq "or") {
2546         $self->assertTokenValue($self->getToken(), "or", __LINE__);
2547         push(@subtypes, $self->parseUnionMemberType());
2548         push(@subtypes, $self->parseUnionMemberTypes());
2549     }
2550
2551     return @subtypes;
2552 }
2553
2554 sub parseNonAnyType
2555 {
2556     my $self = shift;
2557     my $next = $self->nextToken();
2558
2559     my $type = IDLType->new();
2560
2561     if ($next->value() =~ /$nextNonAnyType_1/) {
2562         $type->name($self->parsePrimitiveType());
2563         return $type;
2564     }
2565     if ($next->value() =~ /$nextStringType_1/) {
2566         $type->name($self->parseStringType());
2567         return $type;
2568     }
2569     if ($next->value() eq "object") {
2570         $self->assertTokenValue($self->getToken(), "object", __LINE__);
2571
2572         $type->name("object");
2573         return $type;
2574     }
2575     if ($next->value() eq "Error") {
2576         $self->assertTokenValue($self->getToken(), "Error", __LINE__);
2577
2578         $type->name("Error");
2579         return $type;
2580     }
2581     if ($next->value() eq "DOMException") {
2582         $self->assertTokenValue($self->getToken(), "DOMException", __LINE__);
2583
2584         $type->name("DOMException");
2585         return $type;
2586     }
2587     if ($next->value() eq "Date") {
2588         $self->assertTokenValue($self->getToken(), "Date", __LINE__);
2589
2590         $type->name("Date");
2591         return $type;
2592     }
2593     if ($next->value() eq "sequence") {
2594         $self->assertTokenValue($self->getToken(), "sequence", __LINE__);
2595         $self->assertTokenValue($self->getToken(), "<", __LINE__);
2596
2597         my $subtype = $self->parseTypeWithExtendedAttributes();
2598
2599         $self->assertTokenValue($self->getToken(), ">", __LINE__);
2600
2601         $type->name("sequence");
2602         push(@{$type->subtypes}, $subtype);
2603
2604         return $type;
2605     }
2606     if ($next->value() eq "FrozenArray") {
2607         $self->assertTokenValue($self->getToken(), "FrozenArray", __LINE__);
2608         $self->assertTokenValue($self->getToken(), "<", __LINE__);
2609
2610         my $subtype = $self->parseTypeWithExtendedAttributes();
2611
2612         $self->assertTokenValue($self->getToken(), ">", __LINE__);
2613
2614         $type->name("FrozenArray");
2615         push(@{$type->subtypes}, $subtype);
2616
2617         return $type;
2618     }
2619     if ($next->value() eq "Promise") {
2620         $self->assertTokenValue($self->getToken(), "Promise", __LINE__);
2621         $self->assertTokenValue($self->getToken(), "<", __LINE__);
2622
2623         my $subtype = $self->parseReturnType();
2624
2625         $self->assertTokenValue($self->getToken(), ">", __LINE__);
2626
2627         $type->name("Promise");
2628         push(@{$type->subtypes}, $subtype);
2629
2630         return $type;
2631     }
2632     if ($next->value() eq "record") {
2633         $self->assertTokenValue($self->getToken(), "record", __LINE__);
2634         $self->assertTokenValue($self->getToken(), "<", __LINE__);
2635
2636         my $keyType = IDLType->new();
2637         $keyType->name($self->parseStringType());
2638
2639         $self->assertTokenValue($self->getToken(), ",", __LINE__);
2640
2641         my $valueType = $self->parseTypeWithExtendedAttributes();
2642
2643         $self->assertTokenValue($self->getToken(), ">", __LINE__);
2644
2645         $type->name("record");
2646         push(@{$type->subtypes}, $keyType);
2647         push(@{$type->subtypes}, $valueType);
2648
2649         return $type;
2650     }
2651     if ($next->type() == IdentifierToken) {
2652         my $identifier = $self->getToken();
2653
2654         $type->name(identifierRemoveNullablePrefix($identifier->value()));
2655         return $type;
2656     }
2657     $self->assertUnexpectedToken($next->value(), __LINE__);
2658 }
2659
2660 sub parseConstType
2661 {
2662     my $self = shift;
2663     my $next = $self->nextToken();
2664
2665     my $type = IDLType->new();
2666
2667     if ($next->value() =~ /$nextNonAnyType_1/) {
2668         $type->name($self->parsePrimitiveType());
2669         $type->isNullable($self->parseNull());
2670         return $type;
2671     }
2672     if ($next->type() == IdentifierToken) {
2673         my $identifier = $self->getToken();
2674         
2675         $type->name($identifier->value());
2676         $type->isNullable($self->parseNull());
2677
2678         return $type;
2679     }
2680     $self->assertUnexpectedToken($next->value(), __LINE__);
2681 }
2682
2683 sub parseStringType
2684 {
2685     my $self = shift;
2686     my $next = $self->nextToken();
2687     if ($next->value() eq "ByteString") {
2688         $self->assertTokenValue($self->getToken(), "ByteString", __LINE__);
2689         return "ByteString";
2690     }
2691     if ($next->value() eq "DOMString") {
2692         $self->assertTokenValue($self->getToken(), "DOMString", __LINE__);
2693         return "DOMString";
2694     }
2695     if ($next->value() eq "USVString") {
2696         $self->assertTokenValue($self->getToken(), "USVString", __LINE__);
2697         return "USVString";
2698     }
2699     $self->assertUnexpectedToken($next->value(), __LINE__);
2700 }
2701
2702 sub parsePrimitiveType
2703 {
2704     my $self = shift;
2705     my $next = $self->nextToken();
2706     if ($next->value() =~ /$nextPrimitiveType_1/) {
2707         return $self->parseUnsignedIntegerType();
2708     }
2709     if ($next->value() =~ /$nextPrimitiveType_2/) {
2710         return $self->parseUnrestrictedFloatType();
2711     }
2712     if ($next->value() eq "boolean") {
2713         $self->assertTokenValue($self->getToken(), "boolean", __LINE__);
2714         return "boolean";
2715     }
2716     if ($next->value() eq "byte") {
2717         $self->assertTokenValue($self->getToken(), "byte", __LINE__);
2718         return "byte";
2719     }
2720     if ($next->value() eq "octet") {
2721         $self->assertTokenValue($self->getToken(), "octet", __LINE__);
2722         return "octet";
2723     }
2724     $self->assertUnexpectedToken($next->value(), __LINE__);
2725 }
2726
2727 sub parseUnrestrictedFloatType
2728 {
2729     my $self = shift;
2730     my $next = $self->nextToken();
2731     if ($next->value() eq "unrestricted") {
2732         $self->assertTokenValue($self->getToken(), "unrestricted", __LINE__);
2733         return "unrestricted " . $self->parseFloatType();
2734     }
2735     if ($next->value() =~ /$nextUnrestrictedFloatType_1/) {
2736         return $self->parseFloatType();
2737     }
2738     $self->assertUnexpectedToken($next->value(), __LINE__);
2739 }
2740
2741 sub parseFloatType
2742 {
2743     my $self = shift;
2744     my $next = $self->nextToken();
2745     if ($next->value() eq "float") {
2746         $self->assertTokenValue($self->getToken(), "float", __LINE__);
2747         return "float";
2748     }
2749     if ($next->value() eq "double") {
2750         $self->assertTokenValue($self->getToken(), "double", __LINE__);
2751         return "double";
2752     }
2753     $self->assertUnexpectedToken($next->value(), __LINE__);
2754 }
2755
2756 sub parseUnsignedIntegerType
2757 {
2758     my $self = shift;
2759     my $next = $self->nextToken();
2760     if ($next->value() eq "unsigned") {
2761         $self->assertTokenValue($self->getToken(), "unsigned", __LINE__);
2762         return "unsigned " . $self->parseIntegerType();
2763     }
2764     if ($next->value() =~ /$nextUnsignedIntegerType_1/) {
2765         return $self->parseIntegerType();
2766     }
2767     $self->assertUnexpectedToken($next->value(), __LINE__);
2768 }
2769
2770 sub parseIntegerType
2771 {
2772     my $self = shift;
2773     my $next = $self->nextToken();
2774     if ($next->value() eq "short") {
2775         $self->assertTokenValue($self->getToken(), "short", __LINE__);
2776         return "short";
2777     }
2778     if ($next->value() eq "int") {
2779         $self->assertTokenValue($self->getToken(), "int", __LINE__);
2780         return "int";
2781     }
2782     if ($next->value() eq "long") {
2783         $self->assertTokenValue($self->getToken(), "long", __LINE__);
2784         if ($self->parseOptionalLong()) {
2785             return "long long";
2786         }
2787         return "long";
2788     }
2789     $self->assertUnexpectedToken($next->value(), __LINE__);
2790 }
2791
2792 sub parseOptionalLong
2793 {
2794     my $self = shift;
2795     my $next = $self->nextToken();
2796     if ($next->value() eq "long") {
2797         $self->assertTokenValue($self->getToken(), "long", __LINE__);
2798         return 1;
2799     }
2800     return 0;
2801 }
2802
2803 sub parseNull
2804 {
2805     my $self = shift;
2806     my $next = $self->nextToken();
2807     if ($next->value() eq "?") {
2808         $self->assertTokenValue($self->getToken(), "?", __LINE__);
2809         return 1;
2810     }
2811     return 0;
2812 }
2813
2814 sub parseReturnType
2815 {
2816     my $self = shift;
2817     my $next = $self->nextToken();
2818     if ($next->value() eq "void") {
2819         $self->assertTokenValue($self->getToken(), "void", __LINE__);
2820         
2821         my $voidType = IDLType->new();
2822         $voidType->name("void");
2823         return $voidType;
2824     }
2825     if ($next->type() == IdentifierToken || $next->value() =~ /$nextExceptionField_1/) {
2826         return $self->parseType();
2827     }
2828     $self->assertUnexpectedToken($next->value(), __LINE__);
2829 }
2830
2831 sub parseOptionalSemicolon
2832 {
2833     my $self = shift;
2834     my $next = $self->nextToken();
2835     if ($next->value() eq ";") {
2836         $self->assertTokenValue($self->getToken(), ";", __LINE__);
2837     }
2838 }
2839
2840 sub parseNameNoComma
2841 {
2842     my $self = shift;
2843     my $next = $self->nextToken();
2844     if ($next->type() == IdentifierToken) {
2845         my $identifier = $self->getToken();
2846         return ($identifier->value());
2847     }
2848
2849     return ();
2850 }
2851
2852 sub parseName
2853 {
2854     my $self = shift;
2855     my $next = $self->nextToken();
2856     if ($next->type() == IdentifierToken) {
2857         my $identifier = $self->getToken();
2858         return $identifier->value();
2859     }
2860     $self->assertUnexpectedToken($next->value());
2861 }
2862
2863 sub applyMemberList
2864 {
2865     my $interface = shift;
2866     my $members = shift;
2867
2868     for my $item (@{$members}) {
2869         if (ref($item) eq "IDLAttribute") {
2870             push(@{$interface->attributes}, $item);
2871             next;
2872         }
2873         if (ref($item) eq "IDLConstant") {
2874             push(@{$interface->constants}, $item);
2875             next;
2876         }
2877         if (ref($item) eq "IDLIterable") {
2878             $interface->iterable($item);
2879             next;
2880         }
2881         if (ref($item) eq "IDLMapLike") {
2882             $interface->mapLike($item);
2883             next;
2884         }
2885         if (ref($item) eq "IDLOperation") {
2886             if ($item->name eq "") {
2887                 push(@{$interface->anonymousOperations}, $item);
2888             } else {
2889                 push(@{$interface->operations}, $item);
2890             }
2891             next;
2892         }
2893         if (ref($item) eq "IDLSerializable") {
2894             $interface->serializable($item);
2895             next;
2896         }
2897     }
2898
2899     if ($interface->serializable) {
2900         my $numSerializerAttributes = @{$interface->serializable->attributes};
2901         if ($interface->serializable->hasAttribute) {
2902             foreach my $attribute (@{$interface->attributes}) {
2903                 push(@{$interface->serializable->attributes}, $attribute->name);
2904             }
2905         } elsif ($numSerializerAttributes == 0) {
2906             foreach my $attribute (@{$interface->attributes}) {
2907                 push(@{$interface->serializable->attributes}, $attribute->name);
2908             }
2909         }
2910     }
2911 }
2912
2913 sub applyExtendedAttributeList
2914 {
2915     my $interface = shift;
2916     my $extendedAttributeList = shift;
2917
2918     if (defined $extendedAttributeList->{"Constructors"}) {
2919         my @constructorParams = @{$extendedAttributeList->{"Constructors"}};
2920         my $index = (@constructorParams == 1) ? 0 : 1;
2921         foreach my $param (@constructorParams) {
2922             my $constructor = IDLOperation->new();
2923             $constructor->name("Constructor");
2924             $constructor->extendedAttributes($extendedAttributeList);
2925             $constructor->arguments($param);
2926             push(@{$interface->constructors}, $constructor);
2927         }
2928         delete $extendedAttributeList->{"Constructors"};
2929         $extendedAttributeList->{"Constructor"} = "VALUE_IS_MISSING";
2930     } elsif (defined $extendedAttributeList->{"NamedConstructor"}) {
2931         my $newDataNode = IDLOperation->new();
2932         $newDataNode->name("NamedConstructor");
2933         $newDataNode->extendedAttributes($extendedAttributeList);
2934         my %attributes = %{$extendedAttributeList->{"NamedConstructor"}};
2935         my @attributeKeys = keys (%attributes);
2936         my $constructorName = $attributeKeys[0];
2937         push(@{$newDataNode->arguments}, @{$attributes{$constructorName}});
2938         $extendedAttributeList->{"NamedConstructor"} = $constructorName;
2939         push(@{$interface->constructors}, $newDataNode);
2940     }
2941     if (defined $extendedAttributeList->{"CustomConstructors"}) {
2942         my @customConstructorParams = @{$extendedAttributeList->{"CustomConstructors"}};
2943         my $index = (@customConstructorParams == 1) ? 0 : 1;
2944         foreach my $param (@customConstructorParams) {
2945             my $customConstructor = IDLOperation->new();
2946             $customConstructor->name("CustomConstructor");
2947             $customConstructor->extendedAttributes($extendedAttributeList);
2948             $customConstructor->arguments($param);
2949             push(@{$interface->customConstructors}, $customConstructor);
2950         }
2951         delete $extendedAttributeList->{"CustomConstructors"};
2952         $extendedAttributeList->{"CustomConstructor"} = "VALUE_IS_MISSING";
2953     }
2954     
2955     $interface->extendedAttributes($extendedAttributeList);
2956 }
2957
2958 1;
2959