/[suikacvs]/markup/html/whatpm/Whatpm/WebIDL.pm
Suika

Contents of /markup/html/whatpm/Whatpm/WebIDL.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.18 - (hide annotations) (download)
Tue Sep 16 13:59:55 2008 UTC (16 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.17: +70 -57 lines
++ whatpm/t/webidl/ChangeLog	16 Sep 2008 13:59:48 -0000
	webidl-valuetype.dat, webidl-typedef.dat: Test results are updated
	for new error type names.

2008-09-16  Wakaba  <wakaba@suika.fam.cx>

	* webidl-defs.dat, webidl-interface.dat, webidl-exception.dat,
++ whatpm/Whatpm/ChangeLog	16 Sep 2008 13:58:58 -0000
	* WebIDL.pm: Checker's error types are redefined.

2008-09-16  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package Whatpm::WebIDL;
2     use strict;
3    
4     package Whatpm::WebIDL::Parser;
5    
6 wakaba 1.11 my $integer = qr/-?0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*/;
7     ## ISSUE: Spec's pattern is wrong as a Perl5 regular expression.
8 wakaba 1.1 my $float = qr/-?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+/;
9     my $identifier = qr/[A-Z_a-z][0-9A-Z_a-z]*/;
10     my $whitespace = qr<[\t\n\r ]+|[\t\n\r ]*((//.*|/\*.*?\*/)[\t\n\r ]*)+>;
11    
12 wakaba 1.15 my $default_levels = {
13     must => 'm',
14     should => 's',
15     warn => 'w',
16     fact => 'w',
17     undefined => 'w',
18     info => 'i',
19     uncertain => 'u',
20     };
21    
22 wakaba 1.1 sub new ($) {
23     my $self = bless {
24 wakaba 1.15 level => $default_levels,
25 wakaba 1.1 }, $_[0];
26     return $self;
27     } # new
28    
29     sub parse_char_string ($$;$) {
30     my $self = shift;
31     my $s = ref $_[0] ? $_[0] : \($_[0]);
32    
33     my $defs = Whatpm::WebIDL::Definitions->new;
34 wakaba 1.9 $defs->set_user_data (manakai_source_line => 1);
35     $defs->set_user_data (manakai_source_column => 1);
36 wakaba 1.1
37     pos ($$s) = 0;
38     my $line = 1;
39     my $column = 0;
40    
41     my $get_next_token = sub {
42     if (length $$s <= pos $$s) {
43     return {type => 'eof'};
44     }
45    
46     while ($$s =~ /\G($whitespace)/gc) {
47     my $v = $1;
48     while ($v =~ s/^[^\x0D\x0A]*(?>\x0D\x0A?|\x0A)//) {
49     $line++;
50     $column = 0;
51     }
52     $column += length $v;
53     }
54    
55     if (length $$s <= pos $$s) {
56     return {type => 'eof'};
57     }
58    
59     ## ISSUE: "must"s in "A. IDL grammer" are not "MUST"s.
60    
61     if ($$s =~ /\G($identifier)/gc) {
62     my $v = $1;
63     $column += length $v;
64     if ({
65     module => 1, interface => 1, exception => 1, typedef => 1,
66     valuetype => 1, DOMString => 1, sequence => 1, unsigned => 1,
67     short => 1, const => 1, TRUE => 1, FALSE => 1, readonly => 1,
68     attribute => 1, getraises => 1, setraises => 1, raises => 1, in => 1,
69     any => 1, boolean => 1, octet => 1, float => 1, Object => 1,
70     short => 1, long => 1, void => 1,
71     }->{$v}) {
72     return {type => $v};
73     } else {
74     return {type => 'identifier', value => $v};
75     }
76     } elsif ($$s =~ /\G($float)/gc) { ## ISSUE: negative number
77     $column += length $1;
78     return {type => 'float', value => $1};
79     } elsif ($$s =~ /\G($integer)/gc) { ## ISSUE: negative nmber
80     $column += length $1;
81     return {type => 'integer', value => $1};
82     } elsif ($$s =~ /\G::/gcs) {
83     $column += 2;
84     return {type => '::'};
85     } elsif ($$s =~ /\G(.)/gcs) { ## NOTE: Should never be a newline char.
86     $column++;
87     return {type => $1};
88     } else {
89     die "get_next_token: non-possible case: " . substr ($$s, pos $$s, 20);
90     }
91     }; # $get_next_token
92    
93     my $state = 'before definitions';
94     my $token = $get_next_token->();
95     my $nest_level = 0;
96     my $next_state;
97     my $xattrs;
98 wakaba 1.4 my $prev_xattrs = [];
99 wakaba 1.1 my $last_xattr;
100     my $read_only;
101     my $current_type;
102     my @current = ($defs);
103    
104     my $_onerror = $_[1] || sub {
105     my %opt = @_;
106     my $r = 'Line ' . $opt{line} . ' column ' . $opt{column} . ': ';
107    
108     if ($opt{token}) {
109 wakaba 1.17 $r .= 'Token ' . (defined $opt{token}->{value}
110     ? $opt{token}->{value} : $opt{token}->{type}) . ': ';
111 wakaba 1.1 }
112    
113     $r .= $opt{type} . ';' . $opt{level};
114    
115     warn $r . "\n";
116     }; # $_onerror
117     my $onerror = sub {
118     $_onerror->(line => $line, column => $column, token => $token, @_);
119     }; # $onerror
120    
121     my $get_scoped_name = sub {
122 wakaba 1.10 ## NOTE: Convert a |ScopedName| into a "scoped name".
123    
124 wakaba 1.1 my $name = [];
125    
126     ## NOTE: "DOMString" is not a scoped name, while "::DOMString"
127     ## and "x::DOMString" are.
128    
129     if ($token->{type} eq 'identifier') {
130 wakaba 1.10 my $identifier = $token->{value};
131     $identifier =~ s/^_//;
132     push @$name, $identifier;
133 wakaba 1.1 $token = $get_next_token->();
134     while ($token->{type} eq '::') {
135 wakaba 1.2 $token = $get_next_token->();
136 wakaba 1.1 if ($token->{type} eq 'identifier') {
137 wakaba 1.10 my $identifier = $token->{value};
138     $identifier =~ s/^_//;
139     push @$name, $identifier;
140 wakaba 1.1 $token = $get_next_token->();
141     } elsif ($token->{type} eq 'DOMString') {
142 wakaba 1.13 push @$name, 'DOMString', '', '';
143 wakaba 1.1 $token = $get_next_token->();
144     last;
145     }
146     }
147     } elsif ($token->{type} eq '::') {
148     push @$name, '';
149     while ($token->{type} eq '::') {
150 wakaba 1.2 $token = $get_next_token->();
151 wakaba 1.1 if ($token->{type} eq 'identifier') {
152 wakaba 1.10 my $identifier = $token->{value};
153     $identifier =~ s/^_//;
154     push @$name, $identifier;
155 wakaba 1.1 $token = $get_next_token->();
156     } elsif ($token->{type} eq 'DOMString') {
157 wakaba 1.13 push @$name, 'DOMString', '', '';
158 wakaba 1.1 $token = $get_next_token->();
159     last;
160     } else {
161     last;
162     }
163     }
164    
165     if (@$name == 1) {
166     return undef;
167     }
168     } else {
169     # reconsume
170     return undef;
171     }
172 wakaba 1.10 return join '::', @$name;
173 wakaba 1.1 }; # $get_scoped_name
174    
175     my $get_type;
176     $get_type = sub {
177     my $r;
178     if ({
179     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
180     DOMString => 1, Object => 1, short => 1,
181     }->{$token->{type}}) {
182 wakaba 1.11 $r = '::'.$token->{type}.'::';
183 wakaba 1.1 $token = $get_next_token->();
184     } elsif ($token->{type} eq 'unsigned') {
185     $token = $get_next_token->();
186     if ($token->{type} eq 'short') {
187 wakaba 1.11 $r = '::unsigned '.$token->{type}.'::';
188 wakaba 1.1 $token = $get_next_token->();
189     } elsif ($token->{type} eq 'long') {
190     $token = $get_next_token->();
191     if ($token->{type} eq 'long') {
192 wakaba 1.11 $r = '::unsigned long long::';
193 wakaba 1.1 $token = $get_next_token->();
194     } else {
195 wakaba 1.11 $r = '::unsigned long::';
196 wakaba 1.1 # reconsume
197     }
198     } else {
199 wakaba 1.17 $onerror->(type => 'after unsigned',
200     level => $self->{level}->{must});
201 wakaba 1.1 return undef;
202     }
203     } elsif ($token->{type} eq 'long') {
204     $token = $get_next_token->();
205     if ($token->{type} eq 'long') {
206 wakaba 1.11 $r = '::long long::';
207 wakaba 1.1 $token = $get_next_token->();
208     } else {
209 wakaba 1.11 $r = '::long::';
210 wakaba 1.1 # reconsume
211     }
212     } elsif ($token->{type} eq '::' or $token->{type} eq 'identifier') {
213     $r = $get_scoped_name->();
214     if (defined $r) {
215     # next token
216     } else { # "::" not followed by identifier or "DOMString"
217 wakaba 1.17 $onerror->(type => 'scoped name:dcolon',
218     level => $self->{level}->{must});
219 wakaba 1.1 return undef;
220     }
221     } elsif ($token->{type} eq 'sequence') {
222     $token = $get_next_token->();
223     if ($token->{type} eq '<') {
224     $token = $get_next_token->();
225     if ({
226     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
227     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
228     sequence => 1, '::' => 1, identifier => 1,
229     }->{$token->{type}}) {
230     my $type = $get_type->();
231     if (defined $type) {
232     if ($token->{type} eq '>') {
233 wakaba 1.11 $r = '::::sequence::::' . $type;
234 wakaba 1.1 $token = $get_next_token->();
235     } else {
236 wakaba 1.17 $onerror->(type => 'no sequence gt',
237     level => $self->{level}->{must});
238 wakaba 1.1 return undef;
239     }
240     } else {
241     # error reported
242     return undef;
243     }
244     } else {
245 wakaba 1.17 $onerror->(type => 'no sequence type',
246     level => $self->{level}->{must});
247 wakaba 1.1 return undef;
248     }
249     } else {
250 wakaba 1.17 $onerror->(type => 'no sequence lt',
251     level => $self->{level}->{must});
252 wakaba 1.1 return undef;
253     }
254     } else {
255     die "get_type: bad token: $token->{type}";
256     }
257    
258     return $r;
259     }; # $get_type
260    
261     while (1) {
262     if ($state eq 'before definitions') {
263 wakaba 1.4 $xattrs = [];
264 wakaba 1.1 if ($token->{type} eq '[') {
265     $token = $get_next_token->();
266     $state = 'before xattr';
267     $next_state = 'before def';
268     } elsif ({module => 1, interface => 1, exception => 1,
269     typedef => 1, valuetype => 1, const => 1}->{$token->{type}}) {
270     # reconsume
271     $state = 'before def';
272     } elsif ($token->{type} eq '}' and @current > 1) {
273     $token = $get_next_token->();
274 wakaba 1.5 $state = 'before block semicolon';
275 wakaba 1.1 } elsif ($token->{type} eq 'eof') {
276     last;
277     } else {
278 wakaba 1.17 $onerror->(type => 'before webidl defs',
279     level => $self->{level}->{must});
280 wakaba 1.1 # reconsume
281     $state = 'ignore';
282     $nest_level = 0;
283     $next_state = 'before definitions';
284     }
285     } elsif ($state eq 'before xattr') {
286     if ($token->{type} eq 'identifier') {
287 wakaba 1.15 my $id = $token->{value};
288     $id =~ s/^_//;
289     push @current, Whatpm::WebIDL::ExtendedAttribute->new ($id);
290 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
291     $current[-1]->set_user_data (manakai_source_column => $column);
292 wakaba 1.4 push @$xattrs, $current[-1];
293 wakaba 1.1 $token = $get_next_token->();
294     $state = 'after xattr';
295     } else {
296 wakaba 1.17 $onerror->(type => 'before xattr',
297     level => $self->{level}->{must});
298 wakaba 1.1 # reconsume
299     $state = 'ignore';
300     $nest_level = 0;
301 wakaba 1.4 $next_state = 'before definitions'; ## TODO:
302 wakaba 1.1 }
303     } elsif ($state eq 'after xattr') {
304     if ($token->{type} eq '=') {
305     $token = $get_next_token->();
306     $state = 'before xattrarg';
307 wakaba 1.4 } elsif ($token->{type} eq '(') {
308 wakaba 1.15 $current[-1]->has_argument_list (1);
309 wakaba 1.4 $token = $get_next_token->();
310     if ($token->{type} eq ')') {
311     $token = $get_next_token->();
312     push @$prev_xattrs, $xattrs;
313     $state = 'after xattrarg';
314     } else {
315     push @$prev_xattrs, $xattrs;
316     # reconsume
317     $state = 'before argument';
318     }
319 wakaba 1.1 } else {
320 wakaba 1.4 push @$prev_xattrs, $xattrs;
321 wakaba 1.1 # reconsume
322     $state = 'after xattrarg';
323     }
324     } elsif ($state eq 'before xattrarg') {
325     if ($token->{type} eq 'identifier') {
326 wakaba 1.9 my $identifier = $token->{value};
327     $identifier =~ s/^_//;
328     $current[-1]->value ($identifier);
329 wakaba 1.1 $token = $get_next_token->();
330 wakaba 1.4 if ($token->{type} eq '(') {
331 wakaba 1.15 $current[-1]->has_argument_list (1);
332 wakaba 1.4 $token = $get_next_token->();
333     if ($token->{type} eq ')') {
334     push @$prev_xattrs, $xattrs;
335     $token = $get_next_token->();
336     $state = 'after xattrarg';
337     } else {
338     push @$prev_xattrs, $xattrs;
339     # reconsume
340     $state = 'before argument';
341     }
342     } else {
343     push @$prev_xattrs, $xattrs;
344     # reconsume
345     $state = 'after xattrarg';
346     }
347 wakaba 1.1 } else {
348 wakaba 1.17 $onerror->(type => 'before xattrarg',
349     level => $self->{level}->{must});
350 wakaba 1.1 # reconsume
351     $state = 'ignore';
352     $nest_level = 0;
353     $next_state = 'before definitions';
354     }
355     } elsif ($state eq 'after xattrarg') {
356 wakaba 1.4 pop @current; # xattr
357     $xattrs = pop @$prev_xattrs;
358 wakaba 1.1 if ($token->{type} eq ',') {
359     $token = $get_next_token->();
360     $state = 'before xattr';
361     } elsif ($token->{type} eq ']') {
362     $token = $get_next_token->();
363 wakaba 1.4 if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
364     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
365 wakaba 1.9 $state = 'before def';
366 wakaba 1.4 } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
367     $state = 'before interface member';
368     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Exception')) {
369     $state = 'before exception member';
370     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Operation') or
371     $current[-1]->isa ('Whatpm::WebIDL::ExtendedAttribute')) {
372     $state = 'before argument in';
373     } else {
374     die "$0: Unknown xattr context: " . ref $current[-1];
375     }
376 wakaba 1.1 } else {
377 wakaba 1.17 $onerror->(type => 'after xattr',
378     level => $self->{level}->{must});
379 wakaba 1.1 # reconsume
380     $state = 'ignore';
381     $nest_level = 0;
382 wakaba 1.4 $next_state = 'before definitions'; ## TODO:
383 wakaba 1.1 }
384     } elsif ($state eq 'before def') {
385     if ($token->{type} eq 'module') {
386     $token = $get_next_token->();
387     if ($token->{type} eq 'identifier') {
388 wakaba 1.9 my $identifier = $token->{value};
389     $identifier =~ s/^_//;
390     push @current, Whatpm::WebIDL::Module->new ($identifier);
391     $current[-1]->set_user_data (manakai_source_line => $line);
392     $current[-1]->set_user_data (manakai_source_column => $column);
393 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
394 wakaba 1.1 $token = $get_next_token->();
395     $state = 'before module block';
396     next;
397     } else {
398 wakaba 1.17 $onerror->(type => 'no webidl identifier',
399     text => 'module',
400     level => $self->{level}->{must});
401 wakaba 1.1 #
402     }
403     } elsif ($token->{type} eq 'interface') {
404     $token = $get_next_token->();
405     if ($token->{type} eq 'identifier') {
406 wakaba 1.9 my $identifier = $token->{value};
407     $identifier =~ s/^_//;
408     push @current, Whatpm::WebIDL::Interface->new ($identifier);
409 wakaba 1.8 $current[-1]->set_user_data (manakai_source_line => $line);
410     $current[-1]->set_user_data (manakai_source_column => $column);
411 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
412 wakaba 1.1 $token = $get_next_token->();
413     $state = 'before interface inheritance';
414     next;
415     } else {
416 wakaba 1.17 $onerror->(type => 'no webidl identifier',
417     text => 'interface',
418     level => $self->{level}->{must});
419 wakaba 1.1 #
420     }
421     } elsif ($token->{type} eq 'exception') {
422     $token = $get_next_token->();
423     if ($token->{type} eq 'identifier') {
424 wakaba 1.9 my $identifier = $token->{value};
425     $identifier =~ s/^_//;
426     push @current, Whatpm::WebIDL::Exception->new ($identifier);
427     $current[-1]->set_user_data (manakai_source_line => $line);
428     $current[-1]->set_user_data (manakai_source_column => $column);
429 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
430 wakaba 1.1 $token = $get_next_token->();
431     $state = 'before exception block';
432     next;
433     } else {
434 wakaba 1.17 $onerror->(type => 'no webidl identifier',
435     text => 'exception',
436     level => $self->{level}->{must});
437 wakaba 1.1 #
438     }
439     } elsif ($token->{type} eq 'typedef') {
440     $token = $get_next_token->();
441     $state = 'before typedef type';
442     next;
443     } elsif ($token->{type} eq 'valuetype') {
444     $token = $get_next_token->();
445     if ($token->{type} eq 'identifier') {
446 wakaba 1.9 my $identifier = $token->{value};
447     $identifier =~ s/^_//;
448     push @current, Whatpm::WebIDL::Valuetype->new ($identifier);
449     $current[-1]->set_user_data (manakai_source_line => $line);
450     $current[-1]->set_user_data (manakai_source_column => $column);
451 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
452 wakaba 1.1 $token = $get_next_token->();
453     $state = 'before boxed type';
454     next;
455     } elsif ($token->{type} eq 'DOMString') {
456     push @current, Whatpm::WebIDL::Valuetype->new ('::DOMString::');
457 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
458     $current[-1]->set_user_data (manakai_source_column => $column);
459 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
460 wakaba 1.1 $token = $get_next_token->();
461     if ($token->{type} eq 'sequence') {
462     $token = $get_next_token->();
463     if ($token->{type} eq '<') {
464     $token = $get_next_token->();
465     if ($token->{type} eq 'unsigned') {
466     $token = $get_next_token->();
467     if ($token->{type} eq 'short') {
468     $token = $get_next_token->();
469     if ($token->{type} eq '>') {
470 wakaba 1.11 $current[-1]->type ('::::sequence::::::unsigned short::');
471 wakaba 1.1 $token = $get_next_token->();
472     $state = 'before semicolon';
473     $next_state = 'before definitions';
474     next;
475     } else {
476     #
477     }
478     } else {
479     #
480     }
481     } else {
482     #
483     }
484     } else {
485     #
486     }
487     } else {
488     #
489     }
490 wakaba 1.14 $onerror->(type => 'valuetype DOMString',
491 wakaba 1.17 level => $self->{level}->{must});
492 wakaba 1.8 pop @current; # valuetype
493 wakaba 1.1 #
494     } else {
495 wakaba 1.17 $onerror->(type => 'no webidl identifier',
496     text => 'valuetype',
497     level => $self->{level}->{must});
498 wakaba 1.1 #
499     }
500     } elsif ($token->{type} eq 'const') {
501     $token = $get_next_token->();
502     $state = 'before const type';
503     $next_state = 'before definitions';
504     next;
505     } else {
506 wakaba 1.17 $onerror->(type => 'before webidl def',
507     level => $self->{level}->{must});
508 wakaba 1.1 # reconsume
509     #
510     }
511     $state = 'ignore';
512     $nest_level = 0;
513     $next_state = 'before definitions';
514     } elsif ($state eq 'before module block') {
515     if ($token->{type} eq '{') {
516     $token = $get_next_token->();
517     $state = 'before definitions';
518     } else {
519 wakaba 1.17 $onerror->(type => 'before webidl block',
520     text => 'module',
521     level => $self->{level}->{must});
522 wakaba 1.1 pop @current; # module
523     # reconsume
524     $state = 'ignore';
525     $nest_level = 0;
526     $next_state = 'before definitions';
527     }
528     } elsif ($state eq 'before interface inheritance') {
529     if ($token->{type} eq ':') {
530     $token = $get_next_token->();
531     $state = 'before parent interface name';
532 wakaba 1.8 } elsif ($token->{type} eq ';') {
533     $current[-1]->is_forward_declaration (1);
534     # reconsume
535     $state = 'before semicolon';
536     $next_state = 'before interface member';
537 wakaba 1.1 } else {
538     # reconsume
539     $state = 'before interface block';
540     }
541     } elsif ($state eq 'before parent interface name') {
542     my $name = $get_scoped_name->();
543     if (defined $name) {
544     $current[-1]->append_inheritance ($name);
545    
546     if ($token->{type} eq ',') {
547     $token = $get_next_token->();
548     # stay in the state
549     } else {
550     # reconsume
551     $state = 'before interface block';
552     }
553     } else {
554 wakaba 1.17 $onerror->(type => 'scoped name', level => $self->{level}->{must});
555     pop @current; # interface
556 wakaba 1.1 # reconsume
557     $state = 'ignore';
558     $nest_level = 0;
559     }
560 wakaba 1.2 } elsif ($state eq 'before exception name') {
561     my $name = $get_scoped_name->();
562     if (defined $name) {
563     my $method = $next_state eq '*raises' ? 'append_raises' :
564     $next_state eq '*getraises' ? 'append_getraises' :
565     'append_setraises';
566     $current[-1]->$method ($name);
567    
568     if ($token->{type} eq ',') {
569     $token = $get_next_token->();
570     # stay in the state
571     } elsif ($token->{type} eq ')') {
572     $token = $get_next_token->();
573     if ($next_state eq '*getraises' and $token->{type} eq 'setraises') {
574     $token = $get_next_token->();
575     $state = 'after raises';
576     $next_state = '*setraises';
577     } else {
578     # reprocess
579     $state = 'before semicolon';
580     $next_state = 'before interface member';
581     }
582     } else {
583     $onerror->(type => 'after exception name',
584 wakaba 1.17 level => $self->{level}->{must});
585 wakaba 1.2 # reconsume
586     $state = 'ignore';
587     $nest_level = 0;
588     }
589     } else {
590 wakaba 1.17 $onerror->(type => 'scoped name', level => $self->{level}->{must});
591 wakaba 1.2 # reconsume
592     $state = 'ignore';
593     $nest_level = 0;
594     }
595 wakaba 1.1 } elsif ($state eq 'before interface block') {
596     if ($token->{type} eq '{') {
597     $token = $get_next_token->();
598     $state = 'before members';
599     $next_state = 'before interface member';
600     } else {
601 wakaba 1.17 $onerror->(type => 'before webidl block',
602     text => 'interface',
603     level => $self->{level}->{must});
604 wakaba 1.8 pop @current; # interface
605 wakaba 1.1 # reconsume
606     $state = 'ignore';
607     $nest_level = 0;
608     }
609     } elsif ($state eq 'before exception block') {
610     if ($token->{type} eq '{') {
611     $token = $get_next_token->();
612     $state = 'before members';
613     $next_state = 'before exception member';
614     } else {
615 wakaba 1.17 $onerror->(type => 'before webidl block',
616     text => 'exception',
617     level => $self->{level}->{must});
618     pop @current; # exception
619 wakaba 1.1 # reconsume
620     $state = 'ignore';
621     $nest_level = 0;
622     }
623     } elsif ($state eq 'before members') {
624 wakaba 1.4 $xattrs = [];
625 wakaba 1.1 if ($token->{type} eq '[') {
626     $token = $get_next_token->();
627     $state = 'before xattr';
628     #$next_state = $next_state; # 'before interface member' or ...
629     } elsif ($token->{type} eq '}') {
630     $token = $get_next_token->();
631 wakaba 1.5 $state = 'before block semicolon';
632 wakaba 1.1 } else {
633     # reconsume
634     $state = $next_state; # ... 'before exception member'
635     }
636     } elsif ($state eq 'before interface member') {
637     if ($token->{type} eq 'const') {
638     $token = $get_next_token->();
639     $state = 'before const type';
640     $next_state = 'before definitions';
641     } elsif ($token->{type} eq 'readonly') {
642     $read_only = 1;
643     $token = $get_next_token->();
644     if ($token->{type} eq 'attribute') {
645     $token = $get_next_token->();
646     $state = 'after attribute';
647     } else {
648     # reconsume
649     $state = 'ignore';
650     $nest_level = 0;
651     $next_state = 'before interface member';
652     }
653     } elsif ($token->{type} eq 'attribute') {
654     $read_only = 0;
655     $token = $get_next_token->();
656     $state = 'after attribute';
657     } elsif ({
658     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
659     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
660     '::' => 1, identifier => 1,
661     }->{$token->{type}}) {
662     # reconsume
663     $state = 'before operation type';
664     } elsif ($token->{type} eq '}') {
665     $token = $get_next_token->();
666     $state = 'before semicolon';
667     $next_state = 'before definitions';
668     } elsif ($token->{type} eq 'eof') {
669     last;
670     } else {
671     $onerror->(type => 'before interface member',
672 wakaba 1.17 level => $self->{level}->{must});
673 wakaba 1.1 # reconsume
674     $state = 'ignore';
675     $nest_level = 0;
676     }
677     } elsif ($state eq 'before exception member') {
678     if ({
679     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
680     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
681     '::' => 1, identifier => 1,
682     }->{$token->{type}}) {
683 wakaba 1.3 # reconsume
684     $state = 'before exception member type';
685 wakaba 1.1 } elsif ($token->{type} eq '}') {
686     $token = $get_next_token->();
687     $state = 'before semicolon';
688     $next_state = 'before definitions';
689     } elsif ($token->{type} eq 'eof') {
690     last;
691     } else {
692     $onerror->(type => 'before exception member',
693 wakaba 1.17 level => $self->{level}->{must});
694 wakaba 1.1 # reconsume
695     $state = 'ignore';
696     $nest_level = 0;
697     }
698     } elsif ($state eq 'before typedef type') {
699     if ({
700     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
701     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
702     sequence => 1, '::' => 1, identifier => 1,
703     }->{$token->{type}}) {
704     $current_type = $get_type->();
705     if (defined $current_type) {
706     # next token
707     $state = 'before typedef rest';
708     } else {
709     # reconsume
710     $state = 'ignore';
711     $nest_level = 0;
712     $next_state = 'before definitions';
713     }
714     } else {
715 wakaba 1.17 $onerror->(type => 'before webidl type',
716     text => 'typedef',
717     level => $self->{level}->{must});
718 wakaba 1.1 # reconsume
719     $state = 'ignore';
720     $nest_level = 0;
721     $next_state = 'before definitions';
722     }
723     } elsif ($state eq 'before boxed type') {
724     if ({
725     boolean => 1, octet => 1, float => 1,
726     short => 1, long => 1, unsigned => 1,
727     sequence => 1, '::' => 1, identifier => 1,
728     }->{$token->{type}}) {
729     $current_type = $get_type->();
730     if (defined $current_type) {
731     $current[-1]->type ($current_type);
732     # next token
733     $state = 'before semicolon';
734     $next_state = 'before definitions';
735     } else {
736 wakaba 1.8 pop @current; # valuetype
737 wakaba 1.1 # reconsume
738     $state = 'ignore';
739     $nest_level = 0;
740     $next_state = 'before definitions';
741     }
742     } else {
743 wakaba 1.17 $onerror->(type => 'before webidl type',
744     text => 'valuetype',
745     level => $self->{level}->{must});
746 wakaba 1.8 pop @current; # valuetype
747 wakaba 1.1 # reconsume
748     $state = 'ignore';
749     $nest_level = 0;
750     $next_state = 'before definitions';
751     }
752     } elsif ($state eq 'before const type') {
753     if ({
754     any => 1, boolean => 1, octet => 1, float => 1,
755     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
756     '::' => 1, identifier => 1,
757     }->{$token->{type}}) {
758     $current_type = $get_type->();
759     if (defined $current_type) {
760     # next token
761     $state = 'before const identifier';
762     } else {
763     # reconsume
764     $state = 'ignore';
765     $nest_level = 0;
766     #$next_state = $next_state;
767     }
768     } else {
769 wakaba 1.17 $onerror->(type => 'before webidl type',
770     text => 'const',
771     level => $self->{level}->{must});
772 wakaba 1.1 # reconsume
773     $state = 'ignore';
774     $nest_level = 0;
775     #$next_state = $next_state;
776     }
777     } elsif ($state eq 'before typedef rest') {
778     if ($token->{type} eq 'identifier') {
779     ## TODO: unescape
780     push @current, Whatpm::WebIDL::Typedef->new ($token->{value});
781 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
782     $current[-1]->set_user_data (manakai_source_column => $column);
783 wakaba 1.1 $current[-1]->type ($current_type);
784 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
785 wakaba 1.1 $token = $get_next_token->();
786     $state = 'before semicolon';
787     $next_state = 'before definitions';
788     } elsif ($token->{type} eq 'DOMString') {
789     push @current, Whatpm::WebIDL::Typedef->new ('::DOMString::');
790     $current[-1]->type ($current_type);
791 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
792     $current[-1]->set_user_data (manakai_source_column => $column);
793 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
794 wakaba 1.1 $token = $get_next_token->();
795     $state = 'before semicolon';
796     $next_state = 'before defnitions';
797     } else {
798 wakaba 1.17 $onerror->(type => 'no webidl identifier',
799     text => 'typedef',
800     level => $self->{level}->{must});
801 wakaba 1.1 # reconsume
802     $state = 'ignore';
803     $nest_level = 0;
804     $next_state = 'before definitions';
805     }
806     } elsif ($state eq 'before const identifier') {
807     if ($token->{type} eq 'identifier') {
808 wakaba 1.9 my $identifier = $token->{value};
809     $identifier =~ s/^_//;
810     push @current, Whatpm::WebIDL::Const->new ($identifier);
811     $current[-1]->set_user_data (manakai_source_line => $line);
812     $current[-1]->set_user_data (manakai_source_column => $column);
813 wakaba 1.1 $current[-1]->type ($current_type);
814 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
815 wakaba 1.1 $token = $get_next_token->();
816     if ($token->{type} eq '=') {
817     $token = $get_next_token->();
818     $state = 'before const expr';
819     next;
820     } else {
821 wakaba 1.17 $onerror->(type => 'no const eq', level => $self->{level}->{must});
822 wakaba 1.1 #
823     }
824     } else {
825 wakaba 1.17 $onerror->(type => 'no webidl identifier',
826     text => 'const',
827     level => $self->{level}->{must});
828 wakaba 1.1 #
829     }
830     # reconsume
831     $state = 'ignore';
832     $nest_level = 0;
833     #$next_state = $next_state;
834     } elsif ($state eq 'before const expr') {
835     if ($token->{type} eq 'TRUE' or $token->{type} eq 'FALSE') {
836     $current[-1]->value ([$token->{type}]);
837     #
838 wakaba 1.11 } elsif ($token->{type} eq 'integer') {
839     if ($token->{value} =~ /^0[Xx]/) {
840     $current[-1]->value ([$token->{type}, hex substr $token->{value},2]);
841     } elsif ($token->{value} =~ /^-0[Xx]/) {
842     $current[-1]->value ([$token->{type},-hex substr $token->{value},3]);
843     } elsif ($token->{value} =~ /^0/) {
844     $current[-1]->value ([$token->{type}, oct $token->{value}]);
845     } elsif ($token->{value} =~ /^-0/) {
846     $current[-1]->value ([$token->{type},-oct substr $token->{value},1]);
847     } else {
848     $current[-1]->value ([$token->{type}, 0+$token->{value}]);
849     }
850     #
851     } elsif ($token->{type} eq 'float') {
852     $current[-1]->value ([$token->{type}, 0+$token->{value}]);
853 wakaba 1.1 #
854     } else {
855     # reconsume
856     $state = 'ignore';
857     $nest_level = 0;
858     #$next_state = $next_state;
859     next;
860     }
861    
862     $token = $get_next_token->();
863     $state = 'before semicolon';
864     #$next_state = $next_state;
865     } elsif ($state eq 'after attribute') {
866     if ({
867     any => 1, boolean => 1, octet => 1, float => 1,
868     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
869     '::' => 1, identifier => 1,
870     }->{$token->{type}}) {
871     $current_type = $get_type->();
872     if (defined $current_type) {
873     # next token
874     $state = 'before attribute identifier';
875     } else {
876     # reconsume
877     $state = 'ignore';
878     $nest_level = 0;
879     $next_state = 'before interface member';
880     }
881     } else {
882 wakaba 1.17 $onerror->(type => 'before webidl type',
883     text => 'attribute',
884     level => $self->{level}->{must});
885 wakaba 1.1 # reconsume
886     $state = 'ignore';
887     $nest_level = 0;
888     $next_state = 'before interface member';
889     }
890 wakaba 1.3 } elsif ($state eq 'before exception member type') {
891 wakaba 1.17 #if ({
892     # any => 1, boolean => 1, octet => 1, float => 1,
893     # DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
894     # '::' => 1, identifier => 1,
895     #}->{$token->{type}}) {
896 wakaba 1.3 $current_type = $get_type->();
897     if (defined $current_type) {
898     # next token
899     $state = 'before exception member identifier';
900     } else {
901     # reconsume
902     $state = 'ignore';
903     $nest_level = 0;
904     $next_state = 'before exception member';
905     }
906 wakaba 1.17 #} else {
907     # $onerror->(type => 'before webidl type:exception member',
908     # level => $self->{level}->{must});
909     # # reconsume
910     # $state = 'ignore';
911     # $nest_level = 0;
912     # $next_state = 'before exception member';
913     #}
914 wakaba 1.1 } elsif ($state eq 'before operation type') {
915 wakaba 1.17 #if ({
916     # any => 1, boolean => 1, octet => 1, float => 1,
917     # DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
918     # '::' => 1, identifier => 1,
919     # void => 1,
920     #}->{$token->{type}}) {
921 wakaba 1.1 $current_type = $get_type->();
922     if (defined $current_type) {
923     # next token
924     $state = 'before operation identifier';
925     } else {
926     # reconsume
927     $state = 'ignore';
928     $nest_level = 0;
929     $next_state = 'before interface member';
930     }
931 wakaba 1.17 #} else {
932     # $onerror->(type => 'before webidl type',
933     # text => 'operation',
934     # level => $self->{level}->{must});
935     # # reconsume
936     # $state = 'ignore';
937     # $nest_level = 0;
938     # $next_state = 'before interface member';
939     #}
940 wakaba 1.1 } elsif ($state eq 'before argument type') {
941     if ({
942     any => 1, boolean => 1, octet => 1, float => 1,
943     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
944     '::' => 1, identifier => 1,
945     }->{$token->{type}}) {
946     $current_type = $get_type->();
947     if (defined $current_type) {
948     # next token
949     $state = 'before argument identifier';
950     } else {
951     # reconsume
952     $state = 'ignore';
953     $nest_level = 0;
954     }
955     } else {
956 wakaba 1.17 $onerror->(type => 'before webidl type:argument',
957     level => $self->{level}->{must});
958 wakaba 1.1 # reconsume
959     $state = 'ignore';
960     $nest_level = 0;
961     }
962     } elsif ($state eq 'before attribute identifier') {
963     if ($token->{type} eq 'identifier') {
964 wakaba 1.10 my $identifier = $token->{value};
965     $identifier =~ s/^_//;
966     push @current, Whatpm::WebIDL::Attribute->new ($identifier);
967 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
968     $current[-1]->set_user_data (manakai_source_column => $column);
969 wakaba 1.1 $current[-1]->readonly ($read_only);
970     $current[-1]->type ($current_type);
971 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
972 wakaba 1.1 $token = $get_next_token->();
973     if ($token->{type} eq 'getraises') {
974     $token = $get_next_token->();
975 wakaba 1.2 $state = 'after raises';
976     $next_state = '*getraises';
977 wakaba 1.1 next;
978     } elsif ($token->{type} eq 'setraises') {
979     $token = $get_next_token->();
980 wakaba 1.2 $state = 'after raises';
981     $next_state = '*setraises';
982 wakaba 1.1 next;
983     } else {
984     # reconsume
985     $state = 'before semicolon';
986     $next_state = 'before interface member';
987     next;
988     }
989     } else {
990 wakaba 1.17 $onerror->(type => 'no webidl identifier',
991     text => 'attribute',
992     level => $self->{level}->{must});
993 wakaba 1.1 #
994     }
995     # reconsume
996     $state = 'ignore';
997     $nest_level = 0;
998 wakaba 1.3 $next_state = 'before interface member';
999     } elsif ($state eq 'before exception member identifier') {
1000     if ($token->{type} eq 'identifier') {
1001 wakaba 1.13 my $identifier = $token->{value};
1002     $identifier =~ s/^_//;
1003     push @current, Whatpm::WebIDL::ExceptionMember->new ($identifier);
1004 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
1005     $current[-1]->set_user_data (manakai_source_column => $column);
1006 wakaba 1.3 $current[-1]->type ($current_type);
1007 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
1008 wakaba 1.3 $token = $get_next_token->();
1009     $state = 'before semicolon';
1010     $next_state = 'before exception member';
1011     } else {
1012 wakaba 1.17 $onerror->(type => 'no webidl identifier:exception member',
1013     level => $self->{level}->{must});
1014 wakaba 1.3 # reconsume
1015     $state = 'ignore';
1016     $nest_level = 0;
1017     }
1018 wakaba 1.1 } elsif ($state eq 'before operation identifier') {
1019     if ($token->{type} eq 'identifier') {
1020     ## TODO: unescape
1021     push @current, Whatpm::WebIDL::Operation->new ($token->{value});
1022 wakaba 1.9 $current[-1]->set_user_data (manakai_source_line => $line);
1023     $current[-1]->set_user_data (manakai_source_column => $column);
1024 wakaba 1.1 $current[-1]->type ($current_type);
1025 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
1026 wakaba 1.1 $token = $get_next_token->();
1027     if ($token->{type} eq '(') {
1028     $token = $get_next_token->();
1029     if ($token->{type} eq ')') {
1030     $token = $get_next_token->();
1031 wakaba 1.2 $state = 'before raises';
1032     $next_state = '*raises';
1033 wakaba 1.1 next;
1034     } else {
1035     # reconsume
1036     $state = 'before argument';
1037     next;
1038     }
1039     } else {
1040 wakaba 1.17 $onerror->(type => 'no arguments lparen',
1041     level => $self->{level}->{must});
1042 wakaba 1.1 #
1043     }
1044     } else {
1045 wakaba 1.17 $onerror->(type => 'no webidl identifier:operation',
1046     level => $self->{level}->{must});
1047 wakaba 1.1 #
1048     }
1049     # reconsume
1050     $state = 'ignore';
1051     $nest_level = 0;
1052 wakaba 1.3 $next_state = 'before interface member';
1053 wakaba 1.1 } elsif ($state eq 'before argument identifier') {
1054     if ($token->{type} eq 'identifier') {
1055 wakaba 1.15 my $id = $token->{value};
1056     $id =~ s/^_//;
1057     my $arg = Whatpm::WebIDL::Argument->new ($id);
1058 wakaba 1.9 $arg->set_user_data (manakai_source_line => $line);
1059     $arg->set_user_data (manakai_source_column => $column);
1060 wakaba 1.1 $arg->type ($current_type);
1061 wakaba 1.4 $arg->set_extended_attribute_node ($_) for @$xattrs;
1062 wakaba 1.1 $current[-1]->append_child ($arg);
1063     $token = $get_next_token->();
1064     if ($token->{type} eq ')') {
1065     $token = $get_next_token->();
1066 wakaba 1.4 if ($current[-1]->isa ('Whatpm::WebIDL::Operation')) {
1067     $state = 'before raises';
1068     } else {
1069     $state = 'after xattrarg';
1070     }
1071 wakaba 1.1 next;
1072     } elsif ($token->{type} eq ',') {
1073     $token = $get_next_token->();
1074     $state = 'before argument';
1075     next;
1076     } else {
1077     $onerror->(type => 'after argument',
1078 wakaba 1.17 level => $self->{level}->{must});
1079 wakaba 1.1 #
1080     }
1081     } else {
1082 wakaba 1.17 $onerror->(type => 'no webidl identifier:argument',
1083     level => $self->{level}->{must});
1084 wakaba 1.1 #
1085     }
1086     # reconsume
1087     $state = 'ignore';
1088     $nest_level = 0;
1089     } elsif ($state eq 'before argument') {
1090 wakaba 1.4 $xattrs = [];
1091 wakaba 1.1 if ($token->{type} eq '[') {
1092     $token = $get_next_token->();
1093     $state = 'before xattr';
1094     $next_state = 'before argument in';
1095     } else {
1096     # reconsume
1097     $state = 'before argument in';
1098     }
1099     } elsif ($state eq 'before argument in') {
1100     if ($token->{type} eq 'in') {
1101     $token = $get_next_token->();
1102     $state = 'before argument type';
1103     } else {
1104 wakaba 1.17 $onerror->(type => 'no argument in',
1105     level => $self->{level}->{must});
1106 wakaba 1.1 $state = 'ignore';
1107     $nest_level = 0;
1108     }
1109     } elsif ($state eq 'before raises') {
1110     if ($token->{type} eq 'raises') {
1111     $token = $get_next_token->();
1112     $state = 'after raises';
1113 wakaba 1.2 $next_state = '*raises';
1114 wakaba 1.1 } else {
1115     # reconsume
1116     $state = 'before semicolon';
1117     $next_state = 'before interface member';
1118     }
1119     } elsif ($state eq 'after raises') {
1120 wakaba 1.2 if ($token->{type} eq '(') {
1121     $token = $get_next_token->();
1122     $state = 'before exception name';
1123     } else {
1124 wakaba 1.17 $onerror->(type => 'no raises lparen',
1125     level => $self->{level}->{must});
1126 wakaba 1.2 $state = 'ignore';
1127     $nest_level = 0;
1128     }
1129 wakaba 1.1 } elsif ($state eq 'before semicolon') {
1130     if ($token->{type} eq ';') {
1131     $current[-2]->append_child ($current[-1]);
1132     pop @current;
1133     $token = $get_next_token->();
1134 wakaba 1.5 if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
1135     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1136     $state = 'before definitions';
1137     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
1138     $state = 'before members';
1139     $next_state = 'before interface member';
1140     } else {
1141     $state = 'before members';
1142     $next_state = 'before exception member';
1143     }
1144 wakaba 1.1 } else {
1145 wakaba 1.17 $onerror->(type => 'no webidl semicolon',
1146     level => $self->{level}->{must});
1147 wakaba 1.5 # reconsume
1148     $state = 'ignore';
1149     $nest_level = 0;
1150     }
1151     } elsif ($state eq 'before block semicolon') {
1152     if ($token->{type} eq ';') {
1153     $current[-2]->append_child ($current[-1]);
1154 wakaba 1.1 pop @current;
1155 wakaba 1.5 $token = $get_next_token->();
1156     if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
1157     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1158     $state = 'before definitions';
1159     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
1160     $state = 'before members';
1161     $next_state = 'before interface member';
1162     } else {
1163     $state = 'before members';
1164     $next_state = 'before exception member';
1165     }
1166     } else {
1167 wakaba 1.17 $onerror->(type => 'no webidl semicolon',
1168     level => $self->{level}->{must});
1169 wakaba 1.5 pop @current; # avoid appended by 'ignore'
1170 wakaba 1.1 # reconsume
1171     $state = 'ignore';
1172     $nest_level = 0;
1173     }
1174     } elsif ($state eq 'ignore') {
1175 wakaba 1.5 if ($nest_level == 0 and $token->{type} eq ';') {
1176     while (@current > 1) {
1177     if ($current[-1]->isa ('Whatpm::WebIDL::Interface') or
1178     $current[-1]->isa ('Whatpm::WebIDL::Exception') or
1179     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1180     last;
1181     }
1182     pop @current;
1183     }
1184    
1185 wakaba 1.1 $token = $get_next_token->();
1186 wakaba 1.5 if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
1187     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1188     $state = 'before definitions';
1189     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
1190     $state = 'before members';
1191     $next_state = 'before interface member';
1192     } else {
1193     $state = 'before members';
1194     $next_state = 'before exception member';
1195     }
1196 wakaba 1.1 } elsif ($token->{type} eq '{') {
1197     $nest_level++;
1198     $token = $get_next_token->();
1199     # stay in the state
1200     } elsif ($nest_level and $token->{type} eq '}') {
1201     $nest_level--;
1202     $token = $get_next_token->();
1203     # stay in the state
1204     } elsif ($token->{type} eq 'eof') {
1205 wakaba 1.5 while (@current > 1) {
1206     if ($current[-1]->isa ('Whatpm::WebIDL::Interface') or
1207     $current[-1]->isa ('Whatpm::WebIDL::Exception') or
1208     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1209     last;
1210     }
1211     pop @current;
1212     }
1213    
1214 wakaba 1.1 last;
1215     } else {
1216     # ignore the token
1217     $token = $get_next_token->();
1218     # stay in the state
1219     }
1220     } else {
1221     die "parse_char_string: unkown state: $state";
1222     }
1223     }
1224    
1225     if (@current > 1) {
1226 wakaba 1.17 $onerror->(type => 'premature end of webidl',
1227     level => $self->{level}->{must});
1228 wakaba 1.5 while (@current > 1) {
1229     $current[-2]->append_child ($current[-1]);
1230     pop @current;
1231     }
1232 wakaba 1.1 }
1233    
1234     $get_type = undef; # unlink loop
1235    
1236     return $defs;
1237     } # parse_char_string
1238    
1239 wakaba 1.8 package Whatpm::WebIDL::Node;
1240 wakaba 1.1
1241 wakaba 1.9 require Scalar::Util;
1242    
1243 wakaba 1.1 sub new ($) {
1244     return bless {child_nodes => []}, $_[0];
1245     } # new
1246    
1247     sub append_child ($$) {
1248     my $self = shift;
1249     my $child = shift;
1250    
1251     ## TODO: child type
1252     ## TODO: parent check
1253    
1254     push @{$self->{child_nodes}}, $child;
1255    
1256 wakaba 1.9 $child->{parent_node} = $self;
1257     Scalar::Util::weaken ($child->{parent_node});
1258    
1259 wakaba 1.1 return $child;
1260     } # append_child
1261    
1262 wakaba 1.8 sub child_nodes ($) {
1263     return [@{$_[0]->{child_nodes}}]; # dead list
1264     } # child_nodes
1265    
1266     sub idl_text ($) {
1267     return '[[ERROR: ' . (ref $_[0]) . '->idl_text]]';
1268     } # idl_text
1269    
1270 wakaba 1.1 sub node_name ($) {
1271 wakaba 1.8 return $_[0]->{node_name}; # may be undef
1272 wakaba 1.1 } # node_name
1273    
1274 wakaba 1.9 sub parent_node ($) {
1275     return $_[0]->{parent_node};
1276     } # parent_node
1277    
1278 wakaba 1.8 sub get_user_data ($$) {
1279     return $_[0]->{user_data}->{$_[1]};
1280     } # get_user_data
1281    
1282     sub set_user_data ($$$) {
1283     if (defined $_[2]) {
1284     $_[0]->{user_data}->{$_[1]} = ''.$_[2];
1285     } else {
1286     delete $_[0]->{user_data}->{$_[1]};
1287     }
1288     } # set_user_data
1289    
1290     package Whatpm::WebIDL::Definitions;
1291     push our @ISA, 'Whatpm::WebIDL::Node';
1292    
1293     sub idl_text ($) {
1294     return join "\x0A", map {$_->idl_text} @{$_[0]->{child_nodes}};
1295     } # idl_text
1296    
1297 wakaba 1.15 my $xattr_defs = {
1298     Constructor => {
1299     #allow_id => 0,
1300     allow_arglist => 1,
1301     allowed_type => {Interface => 1},
1302 wakaba 1.16 allow_multiple => 1,
1303 wakaba 1.15 check => sub {
1304 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1305     $resolve, $constructors) = @_;
1306 wakaba 1.15
1307     ## NOTE: Arguments
1308     unshift @$items,
1309     map { {node => $_, scope => $item->{scope}} }
1310     @{$xattr->{child_nodes}};
1311     },
1312     },
1313     ExceptionConsts => {
1314     allow_id => 1,
1315     #allow_arglist => 0,
1316     allowed_type => {Module => 1},
1317 wakaba 1.16 #allow_multiple => 0,
1318 wakaba 1.15 check => sub {
1319 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1320     $resolve, $constructors) = @_;
1321 wakaba 1.15
1322     my $id = $xattr->value;
1323     if (defined $id) {
1324     my $has_x;
1325     for my $x (@{$item->{node}->child_nodes}) {
1326     next unless $x->isa ('Whatpm::WebIDL::Exception');
1327     if ($x->node_name eq $id) {
1328     $has_x = 1;
1329     last;
1330     }
1331     }
1332     unless ($has_x) {
1333     $onerror->(type => 'exception not defined',
1334 wakaba 1.18 text => $id,
1335 wakaba 1.15 node => $xattr,
1336     level => $levels->{must});
1337     }
1338     } else {
1339     $onerror->(type => 'xattr id missing',
1340     text => $xattr_name,
1341     node => $xattr,
1342     level => $levels->{must});
1343     }
1344     },
1345     },
1346     IndexGetter => {
1347     #allow_id => 0,
1348     #allow_arglist => 0,
1349     allowed_type => {Operation => 1},
1350 wakaba 1.16 #allow_multiple => 0,
1351 wakaba 1.15 check => sub {
1352 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1353     $resolve, $constructors) = @_;
1354 wakaba 1.15
1355     if (@{$item->{node}->{child_nodes}} != 1 or
1356     $item->{node}->{child_nodes}->[0]->type_text ne 'unsigned long') {
1357     $onerror->(type => 'wrong signature accessor',
1358     text => $xattr_name,
1359     node => $xattr,
1360     level => $levels->{fact});
1361     }
1362 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1363     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1364 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1365     text => $xattr_name,
1366     node => $xattr,
1367     level => $levels->{undefined});
1368     }
1369 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1370 wakaba 1.15 },
1371     },
1372     IndexSetter => {
1373     #allow_id => 0,
1374     #allow_arglist => 0,
1375     allowed_type => {Operation => 1},
1376 wakaba 1.16 #allow_multiple => 0,
1377 wakaba 1.15 check => sub {
1378 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1379     $resolve, $constructors) = @_;
1380 wakaba 1.15
1381     if (@{$item->{node}->{child_nodes}} != 2 or
1382     $item->{node}->{child_nodes}->[0]->type_text ne 'unsigned long') {
1383     $onerror->(type => 'wrong signature accessor',
1384     text => $xattr_name,
1385     node => $xattr,
1386     level => $levels->{fact});
1387     }
1388 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1389     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1390 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1391     text => $xattr_name,
1392     node => $xattr,
1393     level => $levels->{undefined});
1394     }
1395 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1396 wakaba 1.15 },
1397     },
1398     NameGetter => {
1399     #allow_id => 0,
1400     #allow_arglist => 0,
1401     allowed_type => {Operation => 1},
1402 wakaba 1.16 #allow_multiple => 0,
1403 wakaba 1.15 check => sub {
1404 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1405     $resolve, $constructors) = @_;
1406 wakaba 1.15
1407     if (@{$item->{node}->{child_nodes}} != 1 or
1408     $item->{node}->{child_nodes}->[0]->type_text ne 'DOMString') {
1409     $onerror->(type => 'wrong signature accessor',
1410     text => $xattr_name,
1411     node => $xattr,
1412     level => $levels->{fact});
1413     }
1414 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1415     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1416 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1417     text => $xattr_name,
1418     node => $xattr,
1419     level => $levels->{undefined});
1420     }
1421 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1422 wakaba 1.15 },
1423     },
1424     NameSetter => {
1425     #allow_id => 0,
1426     #allow_arglist => 0,
1427     allowed_type => {Operation => 1},
1428 wakaba 1.16 #allow_multiple => 0,
1429 wakaba 1.15 check => sub {
1430 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1431     $resolve, $constructors) = @_;
1432 wakaba 1.15
1433     if (@{$item->{node}->{child_nodes}} != 2 or
1434     $item->{node}->{child_nodes}->[0]->type ne '::DOMString::') {
1435     $onerror->(type => 'wrong signature accessor',
1436     text => $xattr_name,
1437     node => $xattr,
1438     level => $levels->{fact});
1439     }
1440 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1441     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1442 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1443     text => $xattr_name,
1444     node => $xattr,
1445     level => $levels->{undefined});
1446     }
1447 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1448 wakaba 1.15 },
1449     },
1450     Null => {
1451     allow_id => 1,
1452     #allow_arglist => 0,
1453     allowed_type => {Argument => 1, Attribute => 1},
1454     ## ISSUE: Is this allwoed for extended attribute's arguments?
1455 wakaba 1.16 #allow_multiple => 0,
1456 wakaba 1.15 check => sub {
1457 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1458     $resolve, $constructors) = @_;
1459 wakaba 1.15
1460 wakaba 1.16 ## ISSUE: [Null=Empty] readonly attribute is not disallowed
1461 wakaba 1.15
1462     if ($item->{node}->type ne '::DOMString::') {
1463     $onerror->(type => 'xattr for wrong type',
1464     text => $xattr_name,
1465     node => $xattr,
1466     level => $levels->{fact});
1467     }
1468    
1469     my $id = $xattr->value;
1470     if (defined $id) {
1471     if ($id eq 'Null' or $id eq 'Empty') {
1472     #
1473     } else {
1474     $onerror->(type => 'xattr id value not allowed',
1475     text => $xattr_name,
1476     value => $id,
1477     node => $xattr,
1478     level => $levels->{must});
1479     }
1480     } else {
1481     $onerror->(type => 'xattr id missing',
1482     text => $xattr_name,
1483     node => $xattr,
1484     level => $levels->{must});
1485     }
1486     },
1487     },
1488 wakaba 1.16 PutForwards => {
1489     allow_id => 1,
1490     #allow_arglist => 0,
1491     allowed_type => {Attribute => 1},
1492     #allow_multiple => 0,
1493     check => sub {
1494     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1495     $resolve, $constructors) = @_;
1496    
1497     ## NOTE: Direct or indirect cirlic reference is not an error.
1498    
1499     unless ($item->{node}->readonly) {
1500     $onerror->(type => 'attr not readonly',
1501     text => $xattr_name,
1502     node => $xattr,
1503     level => $levels->{fact});
1504     }
1505    
1506     my $type_item = $resolve->($item->{node}->type, $item->{scope});
1507     if ($type_item and
1508     $type_item->{node}->isa ('Whatpm::WebIDL::Interface')) {
1509     my $id = $xattr->value;
1510     if (defined $id) {
1511     ## ISSUE: "attribute that exists on the interface and which
1512     ## has the same type as this attribute.": "same type"?
1513     ## ISSUE: must be read-write attribute?
1514    
1515     my $check = sub ($) {
1516     my $type_item = shift;
1517    
1518     A: {
1519     for my $attr (@{$type_item->{node}->{child_nodes}}) {
1520     next unless $attr->isa ('Whatpm::WebIDL::Attribute');
1521     if ($attr->node_name eq $id) {
1522     last A;
1523     }
1524     }
1525    
1526     $onerror->(type => 'referenced attr not defined',
1527     text => $xattr_name,
1528     value => $id,
1529     node => $xattr,
1530     level => $levels->{must});
1531     } # A
1532     }; # $check
1533    
1534     if ($type_item->{node}->is_forward_declaration) {
1535     ## NOTE: Checked later.
1536     push @$items, {code => sub {
1537     $check->($resolve->($item->{node}->type, $item->{scope}));
1538     }};
1539     } else {
1540     $check->($type_item);
1541     }
1542     } else {
1543     $onerror->(type => 'xattr id missing',
1544     text => $xattr_name,
1545     node => $xattr,
1546     level => $levels->{must});
1547     }
1548     } else {
1549     ## NOTE: Builtin types, or undefined interface
1550     $onerror->(type => 'attr type not interface',
1551     text => $xattr_name,
1552     node => $xattr,
1553     level => $levels->{fact});
1554     }
1555     },
1556     },
1557     Stringifies => {
1558     allow_id => 1,
1559     #allow_arglist => 0,
1560     allowed_type => {Interface => 1},
1561     #allow_multiple => 0,
1562     check => sub {
1563     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1564     $resolve, $constructors) = @_;
1565    
1566     my $id = $xattr->value;
1567     if (defined $id) {
1568     A: {
1569     for my $attr (@{$item->{node}->{child_nodes}}) {
1570     next unless $attr->isa ('Whatpm::WebIDL::Attribute');
1571     if ($attr->node_name eq $id) {
1572     last A;
1573     }
1574     }
1575    
1576     $onerror->(type => 'referenced attr not defined',
1577     text => $xattr_name,
1578     value => $id,
1579     node => $xattr,
1580     level => $levels->{must});
1581     } # A
1582     }
1583     },
1584     },
1585     Variadic => {
1586     #allow_id => 0,
1587     #allow_arglist => 0,
1588     allowed_type => {Argument => 1},
1589     #allow_multiple => 0,
1590     check => sub {
1591     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1592     $resolve, $constructors) = @_;
1593    
1594     ## ISSUE: is this allowed on extended attribute arguuments?
1595    
1596     ## NOTE: If this is not the final argument, then an error will
1597     ## be raised later.
1598     $item->{has_arg_xattr}->{variadic} = 1;
1599     },
1600     },
1601    
1602     ## ECMAScript specific extended attributes
1603     NamedConstructor => {
1604     allow_id => 1,
1605     allow_arglist => 1,
1606     allowed_type => {Interface => 1, Exception => 1},
1607     allow_multiple => 1,
1608     check => sub {
1609     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1610     $resolve, $constructors) = @_;
1611    
1612     ## NOTE: [NamedConstructor=a,NamedConstructor=a] is not disallowed.
1613    
1614     my $id = $xattr->value;
1615     if (defined $id) {
1616     if ($constructors->{$id} and
1617     $constructors->{$id}->{node} ne $item->{node}) {
1618     $onerror->(type => 'duplicate constructor name',
1619     value => $id,
1620     node => $xattr,
1621     level => $levels->{must});
1622     } else {
1623     $constructors->{$id} = {node => $item->{node},
1624     is_named_constructor => $xattr};
1625     }
1626     } else {
1627     $onerror->(type => 'xattr id missing',
1628     text => $xattr_name,
1629     node => $xattr,
1630     level => $levels->{must});
1631     }
1632     },
1633     },
1634     NativeObject => {
1635     allow_id => 1,
1636     #allow_arglist => 0,
1637     allowed_type => {Interface => 1},
1638     #allow_multiple => 0,
1639     check => sub {
1640     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1641     $resolve, $constructors) = @_;
1642    
1643     my $id = $xattr->value;
1644     if (defined $id and $id ne 'FunctionOnly') {
1645     $onerror->(type => 'xattr id value not allowed',
1646     text => $xattr_name,
1647     value => $id,
1648     node => $xattr,
1649     level => $levels->{must});
1650     }
1651    
1652     ## TODO: We should warn if the condition in the section 4.5 is not met.
1653     },
1654     },
1655     NoInterfaceObject => {
1656     #allow_id => 0,
1657     #allow_arglist => 0,
1658     allowed_type => {Interface => 1, Exception => 1},
1659     #allow_multiple => 0,
1660     check => sub {
1661     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1662     $resolve, $constructors) = @_;
1663    
1664     ## ISSUE: [Constructor, NoInterfaceObject]
1665     },
1666     },
1667     Undefined => {
1668     allow_id => 1,
1669     #allow_arglist => 0,
1670     allowed_type => {Argument => 1, Attribute => 1},
1671     ## ISSUE: Is this allwoed for extended attribute's arguments?
1672     #allow_multiple => 0,
1673     #check : is set later
1674     },
1675 wakaba 1.15 }; # $xattr_defs
1676 wakaba 1.16 $xattr_defs->{Undefined}->{check} = $xattr_defs->{Null}->{check};
1677 wakaba 1.15
1678     sub check ($$;$) {
1679     my ($self, $onerror, $levels) = @_;
1680    
1681     $levels ||= $default_levels;
1682 wakaba 1.8
1683 wakaba 1.11 my $check_const_value = sub ($) {
1684     my $item = shift;
1685    
1686     my $type = $item->{node}->type;
1687     my $value = $item->{node}->value;
1688    
1689     ## NOTE: Although it is not explicitly spelled out in the spec,
1690     ## it can be assumed, imho, that "any" type accepts all of these
1691     ## constant values.
1692     ## ISSUE: Should I ask the editor to clarify the spec about this?
1693    
1694 wakaba 1.18 if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
1695     if ($type eq '::boolean::') {
1696     #
1697     } elsif ($type eq '::any::') {
1698     #
1699     } else {
1700     $onerror->(type => 'const type mismatch',
1701     node => $item->{node},
1702     text => $item->{node}->type_text,
1703     value => $value->[0],
1704     level => $levels->{must});
1705 wakaba 1.11 }
1706     } elsif ($value->[0] eq 'integer') {
1707     if ($type eq '::octet::') {
1708     if ($value->[1] < 0 or 255 < $value->[1]) {
1709     $onerror->(type => 'const value out of range',
1710 wakaba 1.18 text => $item->{node}->type_text,
1711     value => $value->[1],
1712 wakaba 1.11 node => $item->{node},
1713 wakaba 1.18 level => $levels->{must});
1714 wakaba 1.11 }
1715     } elsif ($type eq '::short::') {
1716     if ($value->[1] < -32768 or 32767 < $value->[1]) {
1717     $onerror->(type => 'const value out of range',
1718 wakaba 1.18 text => $item->{node}->type_text,
1719     value => $value->[1],
1720 wakaba 1.11 node => $item->{node},
1721 wakaba 1.18 level => $levels->{must});
1722 wakaba 1.11 }
1723     } elsif ($type eq '::unsigned short::') {
1724     if ($value->[1] < 0 or 65535 < $value->[1]) {
1725     $onerror->(type => 'const value out of range',
1726 wakaba 1.18 text => $item->{node}->type_text,
1727     value => $value->[1],
1728 wakaba 1.11 node => $item->{node},
1729 wakaba 1.18 level => $levels->{must});
1730 wakaba 1.11 }
1731     } elsif ($type eq '::long::') {
1732     if ($value->[1] < -2147483648 or 2147483647 < $value->[1]) {
1733     $onerror->(type => 'const value out of range',
1734 wakaba 1.18 text => $item->{node}->type_text,
1735     value => $value->[1],
1736 wakaba 1.11 node => $item->{node},
1737 wakaba 1.18 level => $levels->{must});
1738 wakaba 1.11 }
1739     } elsif ($type eq '::unsigned long::') {
1740     if ($value->[1] < 0 or 4294967295 < $value->[1]) {
1741     $onerror->(type => 'const value out of range',
1742 wakaba 1.18 text => $item->{node}->type_text,
1743     value => $value->[1],
1744 wakaba 1.11 node => $item->{node},
1745 wakaba 1.18 level => $levels->{must});
1746 wakaba 1.11 }
1747     } elsif ($type eq '::long long::') {
1748     if ($value->[1] < -9223372036854775808 or
1749     9223372036854775807 < $value->[1]) {
1750     $onerror->(type => 'const value out of range',
1751 wakaba 1.18 text => $item->{node}->type_text,
1752     value => $value->[1],
1753 wakaba 1.11 node => $item->{node},
1754 wakaba 1.18 level => $levels->{must});
1755 wakaba 1.11 }
1756     } elsif ($type eq '::unsigned long long::') {
1757     if ($value->[1] < 0 or 18446744073709551615 < $value->[1]) {
1758     $onerror->(type => 'const value out of range',
1759 wakaba 1.18 text => $item->{node}->type_text,
1760     value => $value->[1],
1761 wakaba 1.11 node => $item->{node},
1762 wakaba 1.18 level => $levels->{must});
1763 wakaba 1.11 }
1764     } elsif ($type eq '::any::') {
1765     if ($value->[1] < -9223372036854775808 or
1766     18446744073709551615 < $value->[1]) {
1767     $onerror->(type => 'const value out of range',
1768 wakaba 1.18 text => $item->{node}->type_text,
1769     value => $value->[1],
1770 wakaba 1.11 node => $item->{node},
1771 wakaba 1.18 level => $levels->{must});
1772 wakaba 1.11 }
1773     } else {
1774     $onerror->(type => 'const type mismatch',
1775 wakaba 1.18 text => $item->{node}->type_text,
1776     value => $value->[1],
1777 wakaba 1.11 node => $item->{node},
1778 wakaba 1.18 level => $levels->{must});
1779 wakaba 1.11 }
1780     } elsif ($value->[0] eq 'float') {
1781     if ($type eq '::float::' or $type eq '::any::') {
1782     #
1783     } else {
1784     $onerror->(type => 'const type mismatch',
1785 wakaba 1.18 text => $item->{node}->type_text,
1786     value => $value->[1],
1787 wakaba 1.11 node => $item->{node},
1788 wakaba 1.18 level => $levels->{must});
1789 wakaba 1.11 }
1790     }
1791     ## NOTE: Otherwise, an error of the implementation or the application.
1792     }; # $check_const_value
1793    
1794 wakaba 1.12 my $defined_qnames = {};
1795     my $resolve = sub ($$) {
1796     my $i_sn = shift;
1797     my $scope = shift;
1798    
1799 wakaba 1.16 if ($i_sn =~ /\A::(?>[^:]+)::\z/ or
1800 wakaba 1.13 $i_sn =~ /^::::sequence::::/) {
1801     return undef;
1802     } elsif ($i_sn =~ /::DOMString\z/ or
1803     $i_sn =~ /::DOMString::::\z/) {
1804 wakaba 1.12 return undef;
1805     } elsif ($i_sn =~ /^::/) {
1806     if ($defined_qnames->{$i_sn}) {
1807     return $defined_qnames->{$i_sn};
1808     } else {
1809     return undef;
1810     }
1811     } else {
1812     if ($defined_qnames->{$scope . $i_sn}) {
1813     return $defined_qnames->{$scope . $i_sn};
1814     } elsif ($defined_qnames->{'::' . $i_sn}) {
1815     return $defined_qnames->{'::' . $i_sn};
1816     } else {
1817     return undef;
1818     }
1819     }
1820     }; # $resolve
1821    
1822 wakaba 1.10 my $items = [map { {node => $_, scope => '::'} } @{$self->{child_nodes}}];
1823 wakaba 1.9
1824 wakaba 1.16 my $constructors = {};
1825     ## NOTE: Items are: identifier => {node => $interface_or_exception,
1826     ## is_named_constructor => $named_constructor_xattr/undef}.
1827    
1828 wakaba 1.9 while (@$items) {
1829     my $item = shift @$items;
1830 wakaba 1.16 if (not $item->{node}) {
1831     $item->{code}->();
1832     next;
1833     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Definition') and
1834     not $item->{defined_members}) {
1835     ## NOTE: Const in Interface does not have this.
1836 wakaba 1.13 if ($item->{node}->isa ('Whatpm::WebIDL::Module')) {
1837     unshift @$items,
1838     map {
1839     {node => $_, parent => $item->{node},
1840     scope => $item->{scope} . $item->{node}->node_name . '::'}
1841     }
1842     @{$item->{node}->{child_nodes}};
1843     } else {
1844     unless ($item->{parent}) {
1845     $onerror->(type => 'non-module definition',
1846 wakaba 1.18 node => $item->{node},
1847     level => $levels->{should});
1848 wakaba 1.13 }
1849     }
1850    
1851 wakaba 1.9 if ($item->{node}->isa ('Whatpm::WebIDL::Interface')) {
1852 wakaba 1.10 for my $i_sn (@{$item->{node}->{inheritances}}) {
1853 wakaba 1.12 my $def = $resolve->($i_sn, $item->{scope});
1854    
1855     unless ($def and $def->{node}->isa ('Whatpm::WebIDL::Interface')) {
1856 wakaba 1.13 $i_sn =~ s/::DOMString::::\z/::DOMString/;
1857 wakaba 1.12 $onerror->(type => 'interface not defined',
1858     node => $item->{node},
1859 wakaba 1.18 text => $i_sn,
1860     level => $levels->{must});
1861 wakaba 1.10 }
1862     }
1863    
1864     my $defined_members = {};
1865 wakaba 1.15 my $defined_accessors = {};
1866 wakaba 1.9 unshift @$items,
1867 wakaba 1.12 map { {node => $_, defined_members => $defined_members,
1868 wakaba 1.15 defined_accessors => $defined_accessors,
1869 wakaba 1.12 scope => $item->{scope}} }
1870 wakaba 1.9 @{$item->{node}->{child_nodes}};
1871     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Exception')) {
1872 wakaba 1.13 my $defined_members = {};
1873 wakaba 1.9 unshift @$items,
1874 wakaba 1.13 map { {node => $_, defined_members => $defined_members,
1875 wakaba 1.12 scope => $item->{scope}} }
1876 wakaba 1.9 @{$item->{node}->{child_nodes}};
1877 wakaba 1.11 } elsif ($item->{node}->isa ('Whatpm::WebIDL::Const')) {
1878     $check_const_value->($item);
1879 wakaba 1.13 } elsif ($item->{node}->isa ('Whatpm::WebIDL::Typedef')) {
1880     my $name = $item->{node}->node_name;
1881     my $type = $item->{node}->type;
1882     if ($name eq '::DOMString::' or
1883     $type eq '::DOMString::' or
1884     $type =~ /::DOMString::::\z/) {
1885     $onerror->(type => 'typedef ignored',
1886 wakaba 1.18 node => $item->{node},
1887     level => $levels->{info});
1888 wakaba 1.11 }
1889 wakaba 1.13 ## ISSUE: Refernece to a non-defined interface is not non-conforming.
1890    
1891     ## ISSUE: What does "ignored" mean?
1892     ## "typedef dom::DOMString a; typedef long a;" is conforming?
1893     ## "typedef dom::DOMString b; interface c { attribute b d; };" is?
1894    
1895     ## ISSUE: Is "sequence<undefinedtype>" conforming?
1896    
1897     if ($type =~ /\A::([^:]+)::\z/) {
1898     $item->{allow_null} = {
1899     boolean => 1, octet => 1, short => 1, 'unsigned short' => 1,
1900     long => 1, 'unsigned long' => 1, 'long long' => 1,
1901     'unsigned long long' => 1, float => 1,
1902     }->{$1};
1903     } elsif ($type =~ /^::::sequence::::/) {
1904     $item->{allow_null} = 1;
1905     } else {
1906     my $def = $resolve->($type, $item->{scope});
1907     $item->{allow_null} = $def->{allow_null};
1908     }
1909     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Valuetype')) {
1910     my $name = $item->{node}->node_name;
1911     if ($name eq '::DOMString::') {
1912 wakaba 1.18 $onerror->(type => 'valuetype ignored',
1913     node => $item->{node},
1914     level => $levels->{info});
1915 wakaba 1.13 } else {
1916     my $type = $item->{node}->type;
1917     if ($type =~ /\A::[^:]+::\z/) {
1918     #
1919     } elsif ($type =~ /^::::sequence::::/) {
1920     ## ISSUE: Is "sequence<unknowntype>" conforming?
1921     } else {
1922     my $def = $resolve->($type, $item->{scope});
1923     if ($def and
1924     $def->{allow_null}) {
1925     #
1926     } else {
1927     ## ISSUE: It is not explicitly specified that ScopedName
1928     ## must refer a defined type.
1929     $onerror->(type => 'not boxable type',
1930 wakaba 1.18 text => $item->{node}->type_text,
1931 wakaba 1.13 node => $item->{node},
1932 wakaba 1.18 level => $levels->{must});
1933 wakaba 1.13 }
1934     }
1935 wakaba 1.9 }
1936     }
1937    
1938     my $qname = $item->{node}->qualified_name;
1939     if ($defined_qnames->{$qname}) {
1940     ## NOTE: "The identifier of a definition MUST be locally unique":
1941     ## Redundant with another requirement below.
1942    
1943 wakaba 1.10 ## ISSUE: |interface x; interface x {};| is non-conforming
1944     ## according to the current spec text.
1945    
1946     ## ISSUE: |interface x;| with no |interface x {};| is conforming
1947     ## according to the current spec text.
1948    
1949 wakaba 1.18 ## ISSUE: |interface x; exception x {}|
1950    
1951 wakaba 1.9 $onerror->(type => 'duplicate qname',
1952 wakaba 1.18 node => $item->{node},
1953     level => $levels->{must},
1954     text => $qname);
1955 wakaba 1.16
1956     if ($item->{node}->isa ('Whatpm::WebIDL::Interface') and
1957     $defined_qnames->{$qname}->{node}->isa
1958     ('Whatpm::WebIDL::Interface') and
1959     $defined_qnames->{$qname}->{node}->is_forward_declaration) {
1960     $defined_qnames->{$qname} = $item;
1961     }
1962 wakaba 1.9 } else {
1963 wakaba 1.10 $defined_qnames->{$qname} = $item;
1964     ## NOTE: This flag must be turned on AFTER inheritance check is
1965     ## performed (c.f. |interface x : x {};|).
1966 wakaba 1.9 }
1967     } elsif ($item->{node}->isa ('Whatpm::WebIDL::InterfaceMember')) {
1968     if ($item->{node}->isa ('Whatpm::WebIDL::Operation')) {
1969 wakaba 1.12 ## NOTE: Arguments
1970 wakaba 1.16 my $has_arg_xattr = {};
1971 wakaba 1.9 unshift @$items,
1972 wakaba 1.16 map { {node => $_, scope => $item->{scope},
1973     has_arg_xattr => $has_arg_xattr} }
1974 wakaba 1.9 @{$item->{node}->{child_nodes}};
1975 wakaba 1.10 } else {
1976     my $name = $item->{node}->node_name;
1977     if ($item->{defined_members}->{$name}) {
1978 wakaba 1.13 $onerror->(type => 'duplicate member',
1979 wakaba 1.18 node => $item->{node},
1980     text => $name,
1981     level => $levels->{must});
1982 wakaba 1.10 ## ISSUE: Whether the example below is conforming or not
1983     ## is ambigious:
1984     ## |interface a { attribute any b; any b (); };|
1985     } else {
1986     $item->{defined_members}->{$name} = 1;
1987     }
1988 wakaba 1.12 }
1989 wakaba 1.11
1990 wakaba 1.12 if ($item->{node}->isa ('Whatpm::WebIDL::Attribute') or
1991     $item->{node}->isa ('Whatpm::WebIDL::Operation')) {
1992     my $type = $item->{node}->type;
1993     if ($type =~ /\A::[^:]+::\z/) { # note that sequence<> not allowed
1994     #
1995     } else { # scoped name
1996     my $def = $resolve->($type, $item->{scope});
1997    
1998     unless ($def and
1999     ($def->{node}->isa ('Whatpm::WebIDL::Interface') or
2000     $def->{node}->isa ('Whatpm::WebIDL::Typedef') or
2001     $def->{node}->isa ('Whatpm::WebIDL::Valuetype'))) {
2002     $onerror->(type => 'type not defined',
2003     node => $item->{node},
2004 wakaba 1.18 text => $item->{node}->type_text,
2005     level => $levels->{must});
2006 wakaba 1.12 }
2007 wakaba 1.11 }
2008 wakaba 1.12
2009     for (@{$item->{node}->{raises} or []}, # for operations
2010     @{$item->{node}->{getraises} or []}, # for attributes
2011     @{$item->{node}->{setraises} or []}) { # for attributes
2012     my $def = $resolve->($_, $item->{scope});
2013    
2014     unless ($def and
2015     $def->{node}->isa ('Whatpm::WebIDL::Exception')) {
2016     $onerror->(type => 'exception not defined',
2017 wakaba 1.18 text => $_,
2018 wakaba 1.12 node => $item->{node},
2019 wakaba 1.18 level => $levels->{must});
2020 wakaba 1.12 }
2021     }
2022    
2023     ## ISSUE: readonly setraises is not disallowed
2024     ## ISSUE: raises (x,x) and raises (x,::x) and etc. are not disallowed
2025     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Const')) {
2026     $check_const_value->($item);
2027 wakaba 1.9 }
2028 wakaba 1.13 } elsif ($item->{node}->isa ('Whatpm::WebIDL::Argument') or
2029     $item->{node}->isa ('Whatpm::WebIDL::ExceptionMember')) {
2030 wakaba 1.16 if ($item->{has_arg_xattr}->{variadic} and
2031     $item->{node}->isa ('Whatpm::WebIDL::Argument')) {
2032     $onerror->(type => 'argument after variadic',
2033     node => $item->{node},
2034     level => $levels->{fact});
2035     }
2036    
2037 wakaba 1.15 ## ISSUE: No uniqueness constraints for arguments in an operation,
2038     ## so we don't check it for arguments.
2039    
2040     ## ISSUE: For extended attributes, semantics of the argument
2041     ## (e.g. the identifier is given by the |identifier| in the |Argument|)
2042     ## is not explicitly defined. In addition, no uniqueness constraint
2043     ## is defined, so we don't check it for arguments.
2044 wakaba 1.12
2045 wakaba 1.13 my $name = $item->{node}->node_name;
2046     if ($item->{defined_members}->{$name}) {
2047     $onerror->(type => 'duplicate member',
2048 wakaba 1.18 text => $name,
2049     node => $item->{node},
2050     level => $levels->{must});
2051 wakaba 1.13 } else {
2052     $item->{defined_members}->{$name} = 1;
2053     }
2054    
2055 wakaba 1.12 my $type = $item->{node}->type;
2056     if ($type =~ /\A::[^:]+::\z/) { # note that sequence<> not allowed
2057     #
2058     } else { # scoped name
2059     my $def = $resolve->($type, $item->{scope});
2060    
2061     unless ($def and
2062     ($def->{node}->isa ('Whatpm::WebIDL::Interface') or
2063     $def->{node}->isa ('Whatpm::WebIDL::Typedef') or
2064     $def->{node}->isa ('Whatpm::WebIDL::Valuetype'))) {
2065     $onerror->(type => 'type not defined',
2066 wakaba 1.18 text => $item->{node}->type_text,
2067 wakaba 1.12 node => $item->{node},
2068 wakaba 1.18 level => $levels->{must});
2069 wakaba 1.12 }
2070 wakaba 1.13 }
2071 wakaba 1.9 }
2072    
2073     my $xattrs = $item->{node}->{xattrs} || [];
2074 wakaba 1.16 my $has_xattr;
2075 wakaba 1.15 X: for my $xattr (@$xattrs) {
2076 wakaba 1.9 my $xattr_name = $xattr->node_name;
2077 wakaba 1.15 my $xattr_def = $xattr_defs->{$xattr_name};
2078    
2079     unless ($xattr_def) {
2080     $onerror->(type => 'unknown xattr',
2081     text => $xattr_name,
2082     node => $xattr,
2083     level => $levels->{uncertain});
2084     next X;
2085     }
2086    
2087     A: {
2088     for my $cls (keys %{$xattr_def->{allowed_type} or {}}) {
2089     if ($item->{node}->isa ('Whatpm::WebIDL::' . $cls)) {
2090 wakaba 1.16 if ($cls eq 'Interface' and
2091     $item->{node}->is_forward_declaration) {
2092     #
2093     } else {
2094     last A;
2095     }
2096 wakaba 1.15 }
2097     }
2098    
2099     $onerror->(type => 'xattr not applicable',
2100     text => $xattr_name,
2101 wakaba 1.16 node => $xattr,
2102     level => $levels->{fact});
2103 wakaba 1.15 next X;
2104     } # A
2105    
2106 wakaba 1.16 if ($has_xattr->{$xattr_name} and not $xattr_def->{allow_multiple}) {
2107     ## ISSUE: Whether multiple extended attributes with the same
2108     ## name are allowed is not explicitly specified in the spec.
2109     ## It is, however, specified that some extended attributes may
2110     ## be specified more than once.
2111     $onerror->(type => 'duplicate xattr',
2112     text => $xattr_name,
2113     node => $xattr,
2114     level => $levels->{warn});
2115     }
2116     $has_xattr->{$xattr_name} = 1;
2117    
2118 wakaba 1.15 if (not $xattr_def->{allow_id} and defined $xattr->value) {
2119     $onerror->(type => 'xattr id not allowed',
2120     text => $xattr_name,
2121     node => $xattr,
2122     level => $levels->{must});
2123     }
2124     if (not $xattr_def->{allow_arglist} and $xattr->has_argument_list) {
2125     $onerror->(type => 'xattr arglist not allowed',
2126     text => $xattr_name,
2127     node => $xattr,
2128     level => $levels->{must});
2129     }
2130    
2131     $xattr_def->{check}->($self, $onerror, $levels, $items, $item,
2132 wakaba 1.16 $xattr, $xattr_name, $resolve, $constructors);
2133     }
2134 wakaba 1.15
2135 wakaba 1.16 if (not $has_xattr->{NoInterfaceObject} and
2136     (($item->{node}->isa ('Whatpm::WebIDL::Interface') and
2137     not $item->{node}->is_forward_declaration) or
2138     $item->{node}->isa ('Whatpm::WebIDL::Exception'))) {
2139     my $id = $item->{node}->node_name;
2140     if ($constructors->{$id} and
2141     $constructors->{$id}->{is_named_constructor}) {
2142     $onerror->(type => 'duplicate constructor name',
2143     value => $id,
2144     node => $constructors->{$id}->{is_named_constructor},
2145     level => $levels->{must});
2146     } else {
2147     ## NOTE: Duplication is not checked in this case, since any
2148     ## duplication of interface/exception identifiers are detected
2149     ## by the parser.
2150     $constructors->{$id} = {node => $item->{node}};
2151 wakaba 1.9 }
2152 wakaba 1.8 }
2153     }
2154     } # check
2155    
2156     package Whatpm::WebIDL::Definition;
2157     push our @ISA, 'Whatpm::WebIDL::Node';
2158    
2159     sub new ($$) {
2160     return bless {child_nodes => [], node_name => ''.$_[1]}, $_[0];
2161     } # new
2162    
2163 wakaba 1.4 sub set_extended_attribute_node ($$) {
2164     my $self = shift;
2165     ## TODO: check
2166     push @{$self->{xattrs} ||= []}, shift;
2167     } # set_extended_attribute_node
2168    
2169     sub _xattrs_text ($) {
2170     my $self = shift;
2171    
2172     unless ($self->{xattrs} and
2173     @{$self->{xattrs}}) {
2174     return '';
2175     }
2176    
2177     my $r = '[';
2178     $r .= join ', ', map {$_->idl_text} @{$self->{xattrs}};
2179     $r .= ']';
2180     return $r;
2181     } # _xattrs_text
2182    
2183 wakaba 1.9 sub qualified_name ($) {
2184     my $self = shift;
2185    
2186     my $parent = $self->{parent_node};
2187     if ($parent and $parent->isa ('Whatpm::WebIDL::Definition')) {
2188     return $parent->qualified_name . '::' . $self->{node_name};
2189     } else {
2190     return '::' . $self->{node_name};
2191     }
2192     } # qualified_name
2193    
2194 wakaba 1.1 sub type ($;$) {
2195     if (@_ > 1) {
2196     if (defined $_[1]) {
2197     $_[0]->{type} = $_[1];
2198     } else {
2199 wakaba 1.11 $_[0]->{type} = '::any::';
2200 wakaba 1.1 }
2201     }
2202     return $_[0]->{type};
2203     } # type
2204    
2205 wakaba 1.6 my $serialize_type;
2206     $serialize_type = sub ($) {
2207     my $type = shift;
2208 wakaba 1.11 if ($type =~ s/^::::sequence:::://) {
2209     return 'sequence<' . $serialize_type->($type) . '>';
2210     } elsif ($type =~ /\A::([^:]+)::\z/) {
2211     return $1;
2212 wakaba 1.6 } else {
2213 wakaba 1.13 $type =~ s/::DOMString::::\z/::DOMString/;
2214 wakaba 1.10 return $type; ## TODO: escape identifiers...
2215 wakaba 1.6 }
2216     }; # $serialize_type
2217    
2218 wakaba 1.1 sub type_text ($) {
2219     my $type = $_[0]->{type};
2220     return undef unless defined $type;
2221 wakaba 1.6
2222     return $serialize_type->($type);
2223 wakaba 1.1 } # type_text
2224 wakaba 1.6
2225 wakaba 1.1 package Whatpm::WebIDL::Module;
2226     push our @ISA, 'Whatpm::WebIDL::Definition';
2227    
2228     sub idl_text ($) {
2229 wakaba 1.4 my $self = shift;
2230     my $r = $self->_xattrs_text;
2231     $r .= ' ' if length $r;
2232 wakaba 1.8 $r .= 'module ' . $self->node_name . " {\x0A\x0A"; ## TODO: escape
2233 wakaba 1.4 for (@{$self->{child_nodes}}) {
2234 wakaba 1.1 $r .= $_->idl_text;
2235     }
2236     $r .= "\x0A};\x0A";
2237     return $r;
2238     } # idl_text
2239    
2240     package Whatpm::WebIDL::Interface;
2241     push our @ISA, 'Whatpm::WebIDL::Definition';
2242    
2243     sub new ($$) {
2244     my $self = shift->SUPER::new (@_);
2245     $self->{inheritances} = [];
2246     return $self;
2247     } # new
2248    
2249     sub append_inheritance ($$) {
2250     my $self = shift;
2251     my $scoped_name = shift;
2252     push @{$self->{inheritances}}, $scoped_name;
2253     } # append_inheritance
2254    
2255     sub idl_text ($) {
2256 wakaba 1.3 my $self = shift;
2257 wakaba 1.4 my $r = $self->_xattrs_text;
2258     $r .= ' ' if length $r;
2259 wakaba 1.9 $r .= 'interface ' . $self->node_name;
2260 wakaba 1.8
2261     if ($self->{is_forward_declaration}) {
2262     $r .= ";\x0A";
2263     return $r;
2264     }
2265    
2266 wakaba 1.3 if (@{$self->{inheritances}}) {
2267     $r .= ' : '; ## TODO: ...
2268 wakaba 1.10 $r .= join ', ', map {$serialize_type->($_)} @{$self->{inheritances}};
2269 wakaba 1.3 }
2270     $r .= " {\x0A"; ## TODO: escape
2271     for (@{$self->{child_nodes}}) {
2272 wakaba 1.1 $r .= ' ' . $_->idl_text;
2273     }
2274     $r .= "};\x0A";
2275     return $r;
2276     } # idl_text
2277    
2278 wakaba 1.8 sub is_forward_declaration ($;$) {
2279     if (@_ > 1) {
2280     if ($_[1]) {
2281     $_[0]->{is_forward_declaration} = 1;
2282     } else {
2283     delete $_[0]->{is_forward_declaration};
2284     }
2285     }
2286    
2287     return $_[0]->{is_forward_declaration};
2288     } # is_forward_declaration
2289    
2290 wakaba 1.1 package Whatpm::WebIDL::Exception;
2291     push our @ISA, 'Whatpm::WebIDL::Definition';
2292    
2293 wakaba 1.3 sub idl_text ($) {
2294 wakaba 1.4 my $self = shift;
2295     my $r = $self->_xattrs_text;
2296     $r .= ' ' if length $r;
2297 wakaba 1.9 $r .= 'exception ' . $self->node_name . " {\x0A"; ## TODO: escape
2298 wakaba 1.4 for (@{$self->{child_nodes}}) {
2299 wakaba 1.3 $r .= ' ' . $_->idl_text;
2300     }
2301     $r .= "};\x0A";
2302     return $r;
2303     } # idl_text
2304    
2305 wakaba 1.1 package Whatpm::WebIDL::Typedef;
2306     push our @ISA, 'Whatpm::WebIDL::Definition';
2307    
2308     sub new ($$) {
2309     my $self = shift->SUPER::new (@_);
2310 wakaba 1.11 $self->{type} = '::any::';
2311 wakaba 1.1 return $self;
2312     } # new
2313    
2314     sub idl_text ($) {
2315 wakaba 1.4 my $self = shift;
2316     my $r = $self->_xattrs_text;
2317     $r .= ' ' if length $r;
2318 wakaba 1.13 my $node_name = $self->node_name;
2319     $node_name = 'DOMString' if $node_name eq '::DOMString::';
2320 wakaba 1.1 ## TODO: escape
2321 wakaba 1.13 $r .= 'typedef ' . $self->type_text . ' ' . $node_name . ";\x0A";
2322 wakaba 1.4 return $r;
2323 wakaba 1.1 } # idl_text
2324    
2325     package Whatpm::WebIDL::Valuetype;
2326     push our @ISA, 'Whatpm::WebIDL::Definition';
2327    
2328     sub new ($$) {
2329     my $self = shift->SUPER::new (@_);
2330 wakaba 1.11 $self->{type} = '::boolean::';
2331 wakaba 1.1 return $self;
2332     } # new
2333    
2334     sub idl_text ($) {
2335 wakaba 1.4 my $self = shift;
2336     my $r = $self->_xattrs_text;
2337     $r .= ' ' if length $r;
2338 wakaba 1.14 my $name = $self->node_name;
2339     $name = 'DOMString' if $name eq '::DOMString::';
2340 wakaba 1.1 ## TODO: escape
2341 wakaba 1.14 $r .= 'valuetype ' . $name . ' ' . $self->type_text . ";\x0A";
2342 wakaba 1.4 return $r;
2343 wakaba 1.1 } # idl_text
2344    
2345     package Whatpm::WebIDL::InterfaceMember;
2346 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2347 wakaba 1.1
2348     sub new ($$) {
2349     return bless {node_name => ''.$_[1]}, $_[0];
2350     } # new
2351    
2352 wakaba 1.8 sub child_nodes ($) { return [] }
2353    
2354 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
2355    
2356     *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
2357    
2358 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
2359    
2360     *type_text = \&Whatpm::WebIDL::Definition::type_text;
2361    
2362     package Whatpm::WebIDL::Const;
2363     push our @ISA, 'Whatpm::WebIDL::Definition', 'Whatpm::WebIDL::InterfaceMember';
2364    
2365     sub new ($$) {
2366     my $self = shift->SUPER::new (@_); # Definition->new should be called
2367 wakaba 1.11 $self->{type} = '::boolean::';
2368 wakaba 1.1 $self->{value} = ['FALSE'];
2369     return $self;
2370     } # new
2371    
2372     sub value ($;$) {
2373     if (@_ > 1) {
2374 wakaba 1.11 if (defined $_[1]) {
2375     $_[0]->{value} = $_[1];
2376     } else {
2377     $_[0]->{value} = ['FALSE'];
2378     }
2379 wakaba 1.1 }
2380    
2381     return $_[0]->{value};
2382     } # value
2383    
2384     sub value_text ($) {
2385     my $value = $_[0]->{value};
2386    
2387     if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
2388     return $value->[0];
2389     } elsif ($value->[0] eq 'integer' or $value->[0] eq 'float') {
2390     ## TODO: format
2391     return $value->[1];
2392     } else {
2393     return undef;
2394     }
2395     } # value_text
2396    
2397     sub idl_text ($) {
2398 wakaba 1.4 my $self = shift;
2399     my $r = $self->_xattrs_text;
2400     $r .= ' ' if length $r;
2401     $r .= 'const ' . $self->type_text . ' ' . $self->node_name . ' = ' . $self->value_text . ";\x0A"; ## TODO: escape
2402     return $r;
2403 wakaba 1.1 } # idl_text
2404    
2405     package Whatpm::WebIDL::Attribute;
2406     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
2407    
2408     sub new ($$) {
2409     my $self = shift->SUPER::new (@_);
2410 wakaba 1.11 $self->{type} = '::any::';
2411 wakaba 1.2 $self->{getraises} = [];
2412     $self->{setraises} = [];
2413 wakaba 1.1 return $self;
2414     } # new
2415    
2416 wakaba 1.2 sub append_getraises ($$) {
2417     ## TODO: error check, etc.
2418     push @{$_[0]->{getraises}}, $_[1];
2419     } # append_getraises
2420    
2421     sub append_setraises ($$) {
2422     ## TODO: error check, etc.
2423     push @{$_[0]->{setraises}}, $_[1];
2424     } # append_setraises
2425    
2426 wakaba 1.1 sub readonly ($;$) {
2427     if (@_ > 1) {
2428     $_[0]->{readonly} = $_[1];
2429     }
2430    
2431     return $_[0]->{readonly};
2432     } # readonly
2433    
2434     sub idl_text ($) {
2435 wakaba 1.2 my $self = shift;
2436 wakaba 1.4 my $r = $self->_xattrs_text;
2437     $r .= ' ' if length $r;
2438     $r .= ($self->readonly ? 'readonly ' : '') . 'attribute ' . $self->type_text . ' ' . $self->node_name;
2439 wakaba 1.1 ## TODO: escape
2440 wakaba 1.2 if (@{$self->{getraises}}) {
2441     $r .= ' getraises (';
2442     ## todo: ...
2443 wakaba 1.12 $r .= join ', ', map {$serialize_type->($_)} @{$self->{getraises}};
2444 wakaba 1.2 $r .= ')';
2445     }
2446     if (@{$self->{setraises}}) {
2447     $r .= ' setraises (';
2448     ## todo: ...
2449 wakaba 1.12 $r .= join ', ', map {$serialize_type->($_)} @{$self->{setraises}};
2450 wakaba 1.2 $r .= ')';
2451     }
2452     $r .= ";\x0A";
2453     return $r;
2454 wakaba 1.1 } # idl_text
2455    
2456     package Whatpm::WebIDL::Operation;
2457     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
2458    
2459     sub new ($$) {
2460     my $self = shift->SUPER::new (@_);
2461 wakaba 1.11 $self->{type} = '::any::';
2462 wakaba 1.1 $self->{child_nodes} = [];
2463 wakaba 1.2 $self->{raises} = [];
2464 wakaba 1.1 return $self;
2465     } # new
2466    
2467 wakaba 1.2 sub append_raises ($$) {
2468     ## TODO: error check, etc.
2469     push @{$_[0]->{raises}}, $_[1];
2470     } # append_raises
2471    
2472 wakaba 1.1 sub idl_text ($) {
2473 wakaba 1.2 my $self = shift;
2474 wakaba 1.4 my $r = $self->_xattrs_text;
2475     $r .= ' ' if length $r;
2476     $r .= $self->type_text . ' ' . $self->node_name . ' ('; ## TODO: escape
2477 wakaba 1.2 $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
2478     $r .= ')';
2479     if (@{$self->{raises}}) {
2480     $r .= ' raises (';
2481     ## todo: ...
2482 wakaba 1.12 $r .= join ', ', map {$serialize_type->($_)} @{$self->{raises}};
2483 wakaba 1.2 $r .= ')';
2484     }
2485 wakaba 1.1 $r .= ";\x0A";
2486     return $r;
2487     } # idl_text
2488    
2489     package Whatpm::WebIDL::Argument;
2490 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2491 wakaba 1.1
2492     sub new ($$) {
2493 wakaba 1.11 return bless {node_name => ''.$_[1], type => '::any::'}, $_[0];
2494 wakaba 1.1 } # new
2495    
2496     sub idl_text ($) {
2497 wakaba 1.4 my $self = shift;
2498     my $r = $self->_xattrs_text;
2499     $r .= ' ' if length $r;
2500     $r .= 'in ' . $self->type_text . ' ' . $self->node_name; ## TODO: escape
2501     return $r;
2502 wakaba 1.3 } # idl_text
2503    
2504 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
2505    
2506     *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
2507    
2508 wakaba 1.3 *type = \&Whatpm::WebIDL::Definition::type;
2509    
2510     *type_text = \&Whatpm::WebIDL::Definition::type_text;
2511    
2512     package Whatpm::WebIDL::ExceptionMember;
2513 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2514 wakaba 1.3
2515     sub new ($$) {
2516 wakaba 1.11 return bless {node_name => ''.$_[1], type => '::any::'}, $_[0];
2517 wakaba 1.3 } # new
2518    
2519     sub idl_text ($) {
2520 wakaba 1.4 my $self = shift;
2521     my $r = $self->_xattrs_text;
2522     $r .= ' ' if length $r;
2523     $r .= $self->type_text . ' ' . $self->node_name . ";\x0A"; ## TODO: escape
2524     return $r;
2525 wakaba 1.1 } # idl_text
2526    
2527 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
2528    
2529     *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
2530    
2531 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
2532    
2533     *type_text = \&Whatpm::WebIDL::Definition::type_text;
2534 wakaba 1.9
2535 wakaba 1.4 package Whatpm::WebIDL::ExtendedAttribute;
2536 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2537 wakaba 1.4
2538     sub new ($$) {
2539     return bless {child_nodes => [], node_name => ''.$_[1]};
2540     } # new
2541    
2542 wakaba 1.15 sub has_argument_list ($;$) {
2543     if (@_ > 1) {
2544     if ($_[1]) {
2545     $_[0]->{has_argument_list} = 1;
2546     } else {
2547     delete $_[0]->{has_argument_list};
2548     }
2549     }
2550    
2551     return ($_[0]->{has_argument_list} or scalar @{$_[0]->{child_nodes}});
2552     } # has_argument_list
2553    
2554 wakaba 1.4 sub idl_text ($) {
2555     my $self = shift;
2556     my $r = $self->node_name; ## TODO:] esceape
2557     if (defined $self->{value}) {
2558     $r .= '=' . $self->{value}; ## TODO: escape
2559     }
2560 wakaba 1.15 if ($self->has_argument_list) {
2561 wakaba 1.4 $r .= ' (';
2562     $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
2563     $r .= ')';
2564     }
2565     return $r;
2566     } # idl_text
2567    
2568     sub value ($;$) {
2569     if (@_ > 1) {
2570     if (defined $_[1]) {
2571     $_[0]->{value} = ''.$_[1];
2572     } else {
2573     delete $_[0]->{value};
2574     }
2575     }
2576    
2577     return $_[0]->{value};
2578     } # value
2579 wakaba 1.1
2580     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24