/[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.20 - (hide annotations) (download)
Mon Oct 13 06:18:32 2008 UTC (16 years ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.19: +32 -2 lines
++ whatpm/t/ChangeLog	13 Oct 2008 06:18:26 -0000
2008-10-13  Wakaba  <wakaba@suika.fam.cx>

	* tokenizer-test-2.dat: A test result was wrong.

++ whatpm/Whatpm/ChangeLog	13 Oct 2008 06:17:59 -0000
2008-10-13  Wakaba  <wakaba@suika.fam.cx>

	* HTML.pm.src: Steps for CDATA/RCDATA elements in tree
	construction stage synced with the spec (HTML5 revisions 2139 and
	2302).

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24