/[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.19 - (hide annotations) (download)
Tue Sep 16 14:41:38 2008 UTC (16 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.18: +11 -0 lines
++ whatpm/Whatpm/ChangeLog	16 Sep 2008 14:41:24 -0000
	* Makefile: WebIDL.html added.

	* WebIDL.pod: New documentation.

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

1 wakaba 1.1 package Whatpm::WebIDL;
2     use strict;
3 wakaba 1.19 our $VERSION=do{my @r=(q$Revision: 1.16 $=~/\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     package Whatpm::WebIDL::Definitions;
1292     push our @ISA, 'Whatpm::WebIDL::Node';
1293    
1294     sub idl_text ($) {
1295     return join "\x0A", map {$_->idl_text} @{$_[0]->{child_nodes}};
1296     } # idl_text
1297    
1298 wakaba 1.15 my $xattr_defs = {
1299     Constructor => {
1300     #allow_id => 0,
1301     allow_arglist => 1,
1302     allowed_type => {Interface => 1},
1303 wakaba 1.16 allow_multiple => 1,
1304 wakaba 1.15 check => sub {
1305 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1306     $resolve, $constructors) = @_;
1307 wakaba 1.15
1308     ## NOTE: Arguments
1309     unshift @$items,
1310     map { {node => $_, scope => $item->{scope}} }
1311     @{$xattr->{child_nodes}};
1312     },
1313     },
1314     ExceptionConsts => {
1315     allow_id => 1,
1316     #allow_arglist => 0,
1317     allowed_type => {Module => 1},
1318 wakaba 1.16 #allow_multiple => 0,
1319 wakaba 1.15 check => sub {
1320 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1321     $resolve, $constructors) = @_;
1322 wakaba 1.15
1323     my $id = $xattr->value;
1324     if (defined $id) {
1325     my $has_x;
1326     for my $x (@{$item->{node}->child_nodes}) {
1327     next unless $x->isa ('Whatpm::WebIDL::Exception');
1328     if ($x->node_name eq $id) {
1329     $has_x = 1;
1330     last;
1331     }
1332     }
1333     unless ($has_x) {
1334     $onerror->(type => 'exception not defined',
1335 wakaba 1.18 text => $id,
1336 wakaba 1.15 node => $xattr,
1337     level => $levels->{must});
1338     }
1339     } else {
1340     $onerror->(type => 'xattr id missing',
1341     text => $xattr_name,
1342     node => $xattr,
1343     level => $levels->{must});
1344     }
1345     },
1346     },
1347     IndexGetter => {
1348     #allow_id => 0,
1349     #allow_arglist => 0,
1350     allowed_type => {Operation => 1},
1351 wakaba 1.16 #allow_multiple => 0,
1352 wakaba 1.15 check => sub {
1353 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1354     $resolve, $constructors) = @_;
1355 wakaba 1.15
1356     if (@{$item->{node}->{child_nodes}} != 1 or
1357     $item->{node}->{child_nodes}->[0]->type_text ne 'unsigned long') {
1358     $onerror->(type => 'wrong signature accessor',
1359     text => $xattr_name,
1360     node => $xattr,
1361     level => $levels->{fact});
1362     }
1363 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1364     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1365 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1366     text => $xattr_name,
1367     node => $xattr,
1368     level => $levels->{undefined});
1369     }
1370 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1371 wakaba 1.15 },
1372     },
1373     IndexSetter => {
1374     #allow_id => 0,
1375     #allow_arglist => 0,
1376     allowed_type => {Operation => 1},
1377 wakaba 1.16 #allow_multiple => 0,
1378 wakaba 1.15 check => sub {
1379 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1380     $resolve, $constructors) = @_;
1381 wakaba 1.15
1382     if (@{$item->{node}->{child_nodes}} != 2 or
1383     $item->{node}->{child_nodes}->[0]->type_text ne 'unsigned long') {
1384     $onerror->(type => 'wrong signature accessor',
1385     text => $xattr_name,
1386     node => $xattr,
1387     level => $levels->{fact});
1388     }
1389 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1390     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1391 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1392     text => $xattr_name,
1393     node => $xattr,
1394     level => $levels->{undefined});
1395     }
1396 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1397 wakaba 1.15 },
1398     },
1399     NameGetter => {
1400     #allow_id => 0,
1401     #allow_arglist => 0,
1402     allowed_type => {Operation => 1},
1403 wakaba 1.16 #allow_multiple => 0,
1404 wakaba 1.15 check => sub {
1405 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1406     $resolve, $constructors) = @_;
1407 wakaba 1.15
1408     if (@{$item->{node}->{child_nodes}} != 1 or
1409     $item->{node}->{child_nodes}->[0]->type_text ne 'DOMString') {
1410     $onerror->(type => 'wrong signature accessor',
1411     text => $xattr_name,
1412     node => $xattr,
1413     level => $levels->{fact});
1414     }
1415 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1416     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1417 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1418     text => $xattr_name,
1419     node => $xattr,
1420     level => $levels->{undefined});
1421     }
1422 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1423 wakaba 1.15 },
1424     },
1425     NameSetter => {
1426     #allow_id => 0,
1427     #allow_arglist => 0,
1428     allowed_type => {Operation => 1},
1429 wakaba 1.16 #allow_multiple => 0,
1430 wakaba 1.15 check => sub {
1431 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1432     $resolve, $constructors) = @_;
1433 wakaba 1.15
1434     if (@{$item->{node}->{child_nodes}} != 2 or
1435     $item->{node}->{child_nodes}->[0]->type ne '::DOMString::') {
1436     $onerror->(type => 'wrong signature accessor',
1437     text => $xattr_name,
1438     node => $xattr,
1439     level => $levels->{fact});
1440     }
1441 wakaba 1.16 if ($item->{defined_accessors}->{$xattr_name} and
1442     $item->{defined_accessors}->{$xattr_name} ne $item->{node}) {
1443 wakaba 1.15 $onerror->(type => 'duplicate accessor',
1444     text => $xattr_name,
1445     node => $xattr,
1446     level => $levels->{undefined});
1447     }
1448 wakaba 1.16 $item->{defined_accessors}->{$xattr_name} = $item->{node};
1449 wakaba 1.15 },
1450     },
1451     Null => {
1452     allow_id => 1,
1453     #allow_arglist => 0,
1454     allowed_type => {Argument => 1, Attribute => 1},
1455     ## ISSUE: Is this allwoed for extended attribute's arguments?
1456 wakaba 1.16 #allow_multiple => 0,
1457 wakaba 1.15 check => sub {
1458 wakaba 1.16 my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1459     $resolve, $constructors) = @_;
1460 wakaba 1.15
1461 wakaba 1.16 ## ISSUE: [Null=Empty] readonly attribute is not disallowed
1462 wakaba 1.15
1463     if ($item->{node}->type ne '::DOMString::') {
1464     $onerror->(type => 'xattr for wrong type',
1465     text => $xattr_name,
1466     node => $xattr,
1467     level => $levels->{fact});
1468     }
1469    
1470     my $id = $xattr->value;
1471     if (defined $id) {
1472     if ($id eq 'Null' or $id eq 'Empty') {
1473     #
1474     } else {
1475     $onerror->(type => 'xattr id value not allowed',
1476     text => $xattr_name,
1477     value => $id,
1478     node => $xattr,
1479     level => $levels->{must});
1480     }
1481     } else {
1482     $onerror->(type => 'xattr id missing',
1483     text => $xattr_name,
1484     node => $xattr,
1485     level => $levels->{must});
1486     }
1487     },
1488     },
1489 wakaba 1.16 PutForwards => {
1490     allow_id => 1,
1491     #allow_arglist => 0,
1492     allowed_type => {Attribute => 1},
1493     #allow_multiple => 0,
1494     check => sub {
1495     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1496     $resolve, $constructors) = @_;
1497    
1498     ## NOTE: Direct or indirect cirlic reference is not an error.
1499    
1500     unless ($item->{node}->readonly) {
1501     $onerror->(type => 'attr not readonly',
1502     text => $xattr_name,
1503     node => $xattr,
1504     level => $levels->{fact});
1505     }
1506    
1507     my $type_item = $resolve->($item->{node}->type, $item->{scope});
1508     if ($type_item and
1509     $type_item->{node}->isa ('Whatpm::WebIDL::Interface')) {
1510     my $id = $xattr->value;
1511     if (defined $id) {
1512     ## ISSUE: "attribute that exists on the interface and which
1513     ## has the same type as this attribute.": "same type"?
1514     ## ISSUE: must be read-write attribute?
1515    
1516     my $check = sub ($) {
1517     my $type_item = shift;
1518    
1519     A: {
1520     for my $attr (@{$type_item->{node}->{child_nodes}}) {
1521     next unless $attr->isa ('Whatpm::WebIDL::Attribute');
1522     if ($attr->node_name eq $id) {
1523     last A;
1524     }
1525     }
1526    
1527     $onerror->(type => 'referenced attr not defined',
1528     text => $xattr_name,
1529     value => $id,
1530     node => $xattr,
1531     level => $levels->{must});
1532     } # A
1533     }; # $check
1534    
1535     if ($type_item->{node}->is_forward_declaration) {
1536     ## NOTE: Checked later.
1537     push @$items, {code => sub {
1538     $check->($resolve->($item->{node}->type, $item->{scope}));
1539     }};
1540     } else {
1541     $check->($type_item);
1542     }
1543     } else {
1544     $onerror->(type => 'xattr id missing',
1545     text => $xattr_name,
1546     node => $xattr,
1547     level => $levels->{must});
1548     }
1549     } else {
1550     ## NOTE: Builtin types, or undefined interface
1551     $onerror->(type => 'attr type not interface',
1552     text => $xattr_name,
1553     node => $xattr,
1554     level => $levels->{fact});
1555     }
1556     },
1557     },
1558     Stringifies => {
1559     allow_id => 1,
1560     #allow_arglist => 0,
1561     allowed_type => {Interface => 1},
1562     #allow_multiple => 0,
1563     check => sub {
1564     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1565     $resolve, $constructors) = @_;
1566    
1567     my $id = $xattr->value;
1568     if (defined $id) {
1569     A: {
1570     for my $attr (@{$item->{node}->{child_nodes}}) {
1571     next unless $attr->isa ('Whatpm::WebIDL::Attribute');
1572     if ($attr->node_name eq $id) {
1573     last A;
1574     }
1575     }
1576    
1577     $onerror->(type => 'referenced attr not defined',
1578     text => $xattr_name,
1579     value => $id,
1580     node => $xattr,
1581     level => $levels->{must});
1582     } # A
1583     }
1584     },
1585     },
1586     Variadic => {
1587     #allow_id => 0,
1588     #allow_arglist => 0,
1589     allowed_type => {Argument => 1},
1590     #allow_multiple => 0,
1591     check => sub {
1592     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1593     $resolve, $constructors) = @_;
1594    
1595     ## ISSUE: is this allowed on extended attribute arguuments?
1596    
1597     ## NOTE: If this is not the final argument, then an error will
1598     ## be raised later.
1599     $item->{has_arg_xattr}->{variadic} = 1;
1600     },
1601     },
1602    
1603     ## ECMAScript specific extended attributes
1604     NamedConstructor => {
1605     allow_id => 1,
1606     allow_arglist => 1,
1607     allowed_type => {Interface => 1, Exception => 1},
1608     allow_multiple => 1,
1609     check => sub {
1610     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1611     $resolve, $constructors) = @_;
1612    
1613     ## NOTE: [NamedConstructor=a,NamedConstructor=a] is not disallowed.
1614    
1615     my $id = $xattr->value;
1616     if (defined $id) {
1617     if ($constructors->{$id} and
1618     $constructors->{$id}->{node} ne $item->{node}) {
1619     $onerror->(type => 'duplicate constructor name',
1620     value => $id,
1621     node => $xattr,
1622     level => $levels->{must});
1623     } else {
1624     $constructors->{$id} = {node => $item->{node},
1625     is_named_constructor => $xattr};
1626     }
1627     } else {
1628     $onerror->(type => 'xattr id missing',
1629     text => $xattr_name,
1630     node => $xattr,
1631     level => $levels->{must});
1632     }
1633     },
1634     },
1635     NativeObject => {
1636     allow_id => 1,
1637     #allow_arglist => 0,
1638     allowed_type => {Interface => 1},
1639     #allow_multiple => 0,
1640     check => sub {
1641     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1642     $resolve, $constructors) = @_;
1643    
1644     my $id = $xattr->value;
1645     if (defined $id and $id ne 'FunctionOnly') {
1646     $onerror->(type => 'xattr id value not allowed',
1647     text => $xattr_name,
1648     value => $id,
1649     node => $xattr,
1650     level => $levels->{must});
1651     }
1652    
1653     ## TODO: We should warn if the condition in the section 4.5 is not met.
1654     },
1655     },
1656     NoInterfaceObject => {
1657     #allow_id => 0,
1658     #allow_arglist => 0,
1659     allowed_type => {Interface => 1, Exception => 1},
1660     #allow_multiple => 0,
1661     check => sub {
1662     my ($self, $onerror, $levels, $items, $item, $xattr, $xattr_name,
1663     $resolve, $constructors) = @_;
1664    
1665     ## ISSUE: [Constructor, NoInterfaceObject]
1666     },
1667     },
1668     Undefined => {
1669     allow_id => 1,
1670     #allow_arglist => 0,
1671     allowed_type => {Argument => 1, Attribute => 1},
1672     ## ISSUE: Is this allwoed for extended attribute's arguments?
1673     #allow_multiple => 0,
1674     #check : is set later
1675     },
1676 wakaba 1.15 }; # $xattr_defs
1677 wakaba 1.16 $xattr_defs->{Undefined}->{check} = $xattr_defs->{Null}->{check};
1678 wakaba 1.15
1679     sub check ($$;$) {
1680     my ($self, $onerror, $levels) = @_;
1681    
1682     $levels ||= $default_levels;
1683 wakaba 1.8
1684 wakaba 1.11 my $check_const_value = sub ($) {
1685     my $item = shift;
1686    
1687     my $type = $item->{node}->type;
1688     my $value = $item->{node}->value;
1689    
1690     ## NOTE: Although it is not explicitly spelled out in the spec,
1691     ## it can be assumed, imho, that "any" type accepts all of these
1692     ## constant values.
1693     ## ISSUE: Should I ask the editor to clarify the spec about this?
1694    
1695 wakaba 1.18 if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
1696     if ($type eq '::boolean::') {
1697     #
1698     } elsif ($type eq '::any::') {
1699     #
1700     } else {
1701     $onerror->(type => 'const type mismatch',
1702     node => $item->{node},
1703     text => $item->{node}->type_text,
1704     value => $value->[0],
1705     level => $levels->{must});
1706 wakaba 1.11 }
1707     } elsif ($value->[0] eq 'integer') {
1708     if ($type eq '::octet::') {
1709     if ($value->[1] < 0 or 255 < $value->[1]) {
1710     $onerror->(type => 'const value out of range',
1711 wakaba 1.18 text => $item->{node}->type_text,
1712     value => $value->[1],
1713 wakaba 1.11 node => $item->{node},
1714 wakaba 1.18 level => $levels->{must});
1715 wakaba 1.11 }
1716     } elsif ($type eq '::short::') {
1717     if ($value->[1] < -32768 or 32767 < $value->[1]) {
1718     $onerror->(type => 'const value out of range',
1719 wakaba 1.18 text => $item->{node}->type_text,
1720     value => $value->[1],
1721 wakaba 1.11 node => $item->{node},
1722 wakaba 1.18 level => $levels->{must});
1723 wakaba 1.11 }
1724     } elsif ($type eq '::unsigned short::') {
1725     if ($value->[1] < 0 or 65535 < $value->[1]) {
1726     $onerror->(type => 'const value out of range',
1727 wakaba 1.18 text => $item->{node}->type_text,
1728     value => $value->[1],
1729 wakaba 1.11 node => $item->{node},
1730 wakaba 1.18 level => $levels->{must});
1731 wakaba 1.11 }
1732     } elsif ($type eq '::long::') {
1733     if ($value->[1] < -2147483648 or 2147483647 < $value->[1]) {
1734     $onerror->(type => 'const value out of range',
1735 wakaba 1.18 text => $item->{node}->type_text,
1736     value => $value->[1],
1737 wakaba 1.11 node => $item->{node},
1738 wakaba 1.18 level => $levels->{must});
1739 wakaba 1.11 }
1740     } elsif ($type eq '::unsigned long::') {
1741     if ($value->[1] < 0 or 4294967295 < $value->[1]) {
1742     $onerror->(type => 'const value out of range',
1743 wakaba 1.18 text => $item->{node}->type_text,
1744     value => $value->[1],
1745 wakaba 1.11 node => $item->{node},
1746 wakaba 1.18 level => $levels->{must});
1747 wakaba 1.11 }
1748     } elsif ($type eq '::long long::') {
1749     if ($value->[1] < -9223372036854775808 or
1750     9223372036854775807 < $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 '::unsigned long long::') {
1758     if ($value->[1] < 0 or 18446744073709551615 < $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 '::any::') {
1766     if ($value->[1] < -9223372036854775808 or
1767     18446744073709551615 < $value->[1]) {
1768     $onerror->(type => 'const value out of range',
1769 wakaba 1.18 text => $item->{node}->type_text,
1770     value => $value->[1],
1771 wakaba 1.11 node => $item->{node},
1772 wakaba 1.18 level => $levels->{must});
1773 wakaba 1.11 }
1774     } else {
1775     $onerror->(type => 'const type mismatch',
1776 wakaba 1.18 text => $item->{node}->type_text,
1777     value => $value->[1],
1778 wakaba 1.11 node => $item->{node},
1779 wakaba 1.18 level => $levels->{must});
1780 wakaba 1.11 }
1781     } elsif ($value->[0] eq 'float') {
1782     if ($type eq '::float::' or $type eq '::any::') {
1783     #
1784     } else {
1785     $onerror->(type => 'const type mismatch',
1786 wakaba 1.18 text => $item->{node}->type_text,
1787     value => $value->[1],
1788 wakaba 1.11 node => $item->{node},
1789 wakaba 1.18 level => $levels->{must});
1790 wakaba 1.11 }
1791     }
1792     ## NOTE: Otherwise, an error of the implementation or the application.
1793     }; # $check_const_value
1794    
1795 wakaba 1.12 my $defined_qnames = {};
1796     my $resolve = sub ($$) {
1797     my $i_sn = shift;
1798     my $scope = shift;
1799    
1800 wakaba 1.16 if ($i_sn =~ /\A::(?>[^:]+)::\z/ or
1801 wakaba 1.13 $i_sn =~ /^::::sequence::::/) {
1802     return undef;
1803     } elsif ($i_sn =~ /::DOMString\z/ or
1804     $i_sn =~ /::DOMString::::\z/) {
1805 wakaba 1.12 return undef;
1806     } elsif ($i_sn =~ /^::/) {
1807     if ($defined_qnames->{$i_sn}) {
1808     return $defined_qnames->{$i_sn};
1809     } else {
1810     return undef;
1811     }
1812     } else {
1813     if ($defined_qnames->{$scope . $i_sn}) {
1814     return $defined_qnames->{$scope . $i_sn};
1815     } elsif ($defined_qnames->{'::' . $i_sn}) {
1816     return $defined_qnames->{'::' . $i_sn};
1817     } else {
1818     return undef;
1819     }
1820     }
1821     }; # $resolve
1822    
1823 wakaba 1.10 my $items = [map { {node => $_, scope => '::'} } @{$self->{child_nodes}}];
1824 wakaba 1.9
1825 wakaba 1.16 my $constructors = {};
1826     ## NOTE: Items are: identifier => {node => $interface_or_exception,
1827     ## is_named_constructor => $named_constructor_xattr/undef}.
1828    
1829 wakaba 1.9 while (@$items) {
1830     my $item = shift @$items;
1831 wakaba 1.16 if (not $item->{node}) {
1832     $item->{code}->();
1833     next;
1834     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Definition') and
1835     not $item->{defined_members}) {
1836     ## NOTE: Const in Interface does not have this.
1837 wakaba 1.13 if ($item->{node}->isa ('Whatpm::WebIDL::Module')) {
1838     unshift @$items,
1839     map {
1840     {node => $_, parent => $item->{node},
1841     scope => $item->{scope} . $item->{node}->node_name . '::'}
1842     }
1843     @{$item->{node}->{child_nodes}};
1844     } else {
1845     unless ($item->{parent}) {
1846     $onerror->(type => 'non-module definition',
1847 wakaba 1.18 node => $item->{node},
1848     level => $levels->{should});
1849 wakaba 1.13 }
1850     }
1851    
1852 wakaba 1.9 if ($item->{node}->isa ('Whatpm::WebIDL::Interface')) {
1853 wakaba 1.10 for my $i_sn (@{$item->{node}->{inheritances}}) {
1854 wakaba 1.12 my $def = $resolve->($i_sn, $item->{scope});
1855    
1856     unless ($def and $def->{node}->isa ('Whatpm::WebIDL::Interface')) {
1857 wakaba 1.13 $i_sn =~ s/::DOMString::::\z/::DOMString/;
1858 wakaba 1.12 $onerror->(type => 'interface not defined',
1859     node => $item->{node},
1860 wakaba 1.18 text => $i_sn,
1861     level => $levels->{must});
1862 wakaba 1.10 }
1863     }
1864    
1865     my $defined_members = {};
1866 wakaba 1.15 my $defined_accessors = {};
1867 wakaba 1.9 unshift @$items,
1868 wakaba 1.12 map { {node => $_, defined_members => $defined_members,
1869 wakaba 1.15 defined_accessors => $defined_accessors,
1870 wakaba 1.12 scope => $item->{scope}} }
1871 wakaba 1.9 @{$item->{node}->{child_nodes}};
1872     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Exception')) {
1873 wakaba 1.13 my $defined_members = {};
1874 wakaba 1.9 unshift @$items,
1875 wakaba 1.13 map { {node => $_, defined_members => $defined_members,
1876 wakaba 1.12 scope => $item->{scope}} }
1877 wakaba 1.9 @{$item->{node}->{child_nodes}};
1878 wakaba 1.11 } elsif ($item->{node}->isa ('Whatpm::WebIDL::Const')) {
1879     $check_const_value->($item);
1880 wakaba 1.13 } elsif ($item->{node}->isa ('Whatpm::WebIDL::Typedef')) {
1881     my $name = $item->{node}->node_name;
1882     my $type = $item->{node}->type;
1883     if ($name eq '::DOMString::' or
1884     $type eq '::DOMString::' or
1885     $type =~ /::DOMString::::\z/) {
1886     $onerror->(type => 'typedef ignored',
1887 wakaba 1.18 node => $item->{node},
1888     level => $levels->{info});
1889 wakaba 1.11 }
1890 wakaba 1.13 ## ISSUE: Refernece to a non-defined interface is not non-conforming.
1891    
1892     ## ISSUE: What does "ignored" mean?
1893     ## "typedef dom::DOMString a; typedef long a;" is conforming?
1894     ## "typedef dom::DOMString b; interface c { attribute b d; };" is?
1895    
1896     ## ISSUE: Is "sequence<undefinedtype>" conforming?
1897    
1898     if ($type =~ /\A::([^:]+)::\z/) {
1899     $item->{allow_null} = {
1900     boolean => 1, octet => 1, short => 1, 'unsigned short' => 1,
1901     long => 1, 'unsigned long' => 1, 'long long' => 1,
1902     'unsigned long long' => 1, float => 1,
1903     }->{$1};
1904     } elsif ($type =~ /^::::sequence::::/) {
1905     $item->{allow_null} = 1;
1906     } else {
1907     my $def = $resolve->($type, $item->{scope});
1908     $item->{allow_null} = $def->{allow_null};
1909     }
1910     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Valuetype')) {
1911     my $name = $item->{node}->node_name;
1912     if ($name eq '::DOMString::') {
1913 wakaba 1.18 $onerror->(type => 'valuetype ignored',
1914     node => $item->{node},
1915     level => $levels->{info});
1916 wakaba 1.13 } else {
1917     my $type = $item->{node}->type;
1918     if ($type =~ /\A::[^:]+::\z/) {
1919     #
1920     } elsif ($type =~ /^::::sequence::::/) {
1921     ## ISSUE: Is "sequence<unknowntype>" conforming?
1922     } else {
1923     my $def = $resolve->($type, $item->{scope});
1924     if ($def and
1925     $def->{allow_null}) {
1926     #
1927     } else {
1928     ## ISSUE: It is not explicitly specified that ScopedName
1929     ## must refer a defined type.
1930     $onerror->(type => 'not boxable type',
1931 wakaba 1.18 text => $item->{node}->type_text,
1932 wakaba 1.13 node => $item->{node},
1933 wakaba 1.18 level => $levels->{must});
1934 wakaba 1.13 }
1935     }
1936 wakaba 1.9 }
1937     }
1938    
1939     my $qname = $item->{node}->qualified_name;
1940     if ($defined_qnames->{$qname}) {
1941     ## NOTE: "The identifier of a definition MUST be locally unique":
1942     ## Redundant with another requirement below.
1943    
1944 wakaba 1.10 ## ISSUE: |interface x; interface x {};| is non-conforming
1945     ## according to the current spec text.
1946    
1947     ## ISSUE: |interface x;| with no |interface x {};| is conforming
1948     ## according to the current spec text.
1949    
1950 wakaba 1.18 ## ISSUE: |interface x; exception x {}|
1951    
1952 wakaba 1.9 $onerror->(type => 'duplicate qname',
1953 wakaba 1.18 node => $item->{node},
1954     level => $levels->{must},
1955     text => $qname);
1956 wakaba 1.16
1957     if ($item->{node}->isa ('Whatpm::WebIDL::Interface') and
1958     $defined_qnames->{$qname}->{node}->isa
1959     ('Whatpm::WebIDL::Interface') and
1960     $defined_qnames->{$qname}->{node}->is_forward_declaration) {
1961     $defined_qnames->{$qname} = $item;
1962     }
1963 wakaba 1.9 } else {
1964 wakaba 1.10 $defined_qnames->{$qname} = $item;
1965     ## NOTE: This flag must be turned on AFTER inheritance check is
1966     ## performed (c.f. |interface x : x {};|).
1967 wakaba 1.9 }
1968     } elsif ($item->{node}->isa ('Whatpm::WebIDL::InterfaceMember')) {
1969     if ($item->{node}->isa ('Whatpm::WebIDL::Operation')) {
1970 wakaba 1.12 ## NOTE: Arguments
1971 wakaba 1.16 my $has_arg_xattr = {};
1972 wakaba 1.9 unshift @$items,
1973 wakaba 1.16 map { {node => $_, scope => $item->{scope},
1974     has_arg_xattr => $has_arg_xattr} }
1975 wakaba 1.9 @{$item->{node}->{child_nodes}};
1976 wakaba 1.10 } else {
1977     my $name = $item->{node}->node_name;
1978     if ($item->{defined_members}->{$name}) {
1979 wakaba 1.13 $onerror->(type => 'duplicate member',
1980 wakaba 1.18 node => $item->{node},
1981     text => $name,
1982     level => $levels->{must});
1983 wakaba 1.10 ## ISSUE: Whether the example below is conforming or not
1984     ## is ambigious:
1985     ## |interface a { attribute any b; any b (); };|
1986     } else {
1987     $item->{defined_members}->{$name} = 1;
1988     }
1989 wakaba 1.12 }
1990 wakaba 1.11
1991 wakaba 1.12 if ($item->{node}->isa ('Whatpm::WebIDL::Attribute') or
1992     $item->{node}->isa ('Whatpm::WebIDL::Operation')) {
1993     my $type = $item->{node}->type;
1994     if ($type =~ /\A::[^:]+::\z/) { # note that sequence<> not allowed
1995     #
1996     } else { # scoped name
1997     my $def = $resolve->($type, $item->{scope});
1998    
1999     unless ($def and
2000     ($def->{node}->isa ('Whatpm::WebIDL::Interface') or
2001     $def->{node}->isa ('Whatpm::WebIDL::Typedef') or
2002     $def->{node}->isa ('Whatpm::WebIDL::Valuetype'))) {
2003     $onerror->(type => 'type not defined',
2004     node => $item->{node},
2005 wakaba 1.18 text => $item->{node}->type_text,
2006     level => $levels->{must});
2007 wakaba 1.12 }
2008 wakaba 1.11 }
2009 wakaba 1.12
2010     for (@{$item->{node}->{raises} or []}, # for operations
2011     @{$item->{node}->{getraises} or []}, # for attributes
2012     @{$item->{node}->{setraises} or []}) { # for attributes
2013     my $def = $resolve->($_, $item->{scope});
2014    
2015     unless ($def and
2016     $def->{node}->isa ('Whatpm::WebIDL::Exception')) {
2017     $onerror->(type => 'exception not defined',
2018 wakaba 1.18 text => $_,
2019 wakaba 1.12 node => $item->{node},
2020 wakaba 1.18 level => $levels->{must});
2021 wakaba 1.12 }
2022     }
2023    
2024     ## ISSUE: readonly setraises is not disallowed
2025     ## ISSUE: raises (x,x) and raises (x,::x) and etc. are not disallowed
2026     } elsif ($item->{node}->isa ('Whatpm::WebIDL::Const')) {
2027     $check_const_value->($item);
2028 wakaba 1.9 }
2029 wakaba 1.13 } elsif ($item->{node}->isa ('Whatpm::WebIDL::Argument') or
2030     $item->{node}->isa ('Whatpm::WebIDL::ExceptionMember')) {
2031 wakaba 1.16 if ($item->{has_arg_xattr}->{variadic} and
2032     $item->{node}->isa ('Whatpm::WebIDL::Argument')) {
2033     $onerror->(type => 'argument after variadic',
2034     node => $item->{node},
2035     level => $levels->{fact});
2036     }
2037    
2038 wakaba 1.15 ## ISSUE: No uniqueness constraints for arguments in an operation,
2039     ## so we don't check it for arguments.
2040    
2041     ## ISSUE: For extended attributes, semantics of the argument
2042     ## (e.g. the identifier is given by the |identifier| in the |Argument|)
2043     ## is not explicitly defined. In addition, no uniqueness constraint
2044     ## is defined, so we don't check it for arguments.
2045 wakaba 1.12
2046 wakaba 1.13 my $name = $item->{node}->node_name;
2047     if ($item->{defined_members}->{$name}) {
2048     $onerror->(type => 'duplicate member',
2049 wakaba 1.18 text => $name,
2050     node => $item->{node},
2051     level => $levels->{must});
2052 wakaba 1.13 } else {
2053     $item->{defined_members}->{$name} = 1;
2054     }
2055    
2056 wakaba 1.12 my $type = $item->{node}->type;
2057     if ($type =~ /\A::[^:]+::\z/) { # note that sequence<> not allowed
2058     #
2059     } else { # scoped name
2060     my $def = $resolve->($type, $item->{scope});
2061    
2062     unless ($def and
2063     ($def->{node}->isa ('Whatpm::WebIDL::Interface') or
2064     $def->{node}->isa ('Whatpm::WebIDL::Typedef') or
2065     $def->{node}->isa ('Whatpm::WebIDL::Valuetype'))) {
2066     $onerror->(type => 'type not defined',
2067 wakaba 1.18 text => $item->{node}->type_text,
2068 wakaba 1.12 node => $item->{node},
2069 wakaba 1.18 level => $levels->{must});
2070 wakaba 1.12 }
2071 wakaba 1.13 }
2072 wakaba 1.9 }
2073    
2074     my $xattrs = $item->{node}->{xattrs} || [];
2075 wakaba 1.16 my $has_xattr;
2076 wakaba 1.15 X: for my $xattr (@$xattrs) {
2077 wakaba 1.9 my $xattr_name = $xattr->node_name;
2078 wakaba 1.15 my $xattr_def = $xattr_defs->{$xattr_name};
2079    
2080     unless ($xattr_def) {
2081     $onerror->(type => 'unknown xattr',
2082     text => $xattr_name,
2083     node => $xattr,
2084     level => $levels->{uncertain});
2085     next X;
2086     }
2087    
2088     A: {
2089     for my $cls (keys %{$xattr_def->{allowed_type} or {}}) {
2090     if ($item->{node}->isa ('Whatpm::WebIDL::' . $cls)) {
2091 wakaba 1.16 if ($cls eq 'Interface' and
2092     $item->{node}->is_forward_declaration) {
2093     #
2094     } else {
2095     last A;
2096     }
2097 wakaba 1.15 }
2098     }
2099    
2100     $onerror->(type => 'xattr not applicable',
2101     text => $xattr_name,
2102 wakaba 1.16 node => $xattr,
2103     level => $levels->{fact});
2104 wakaba 1.15 next X;
2105     } # A
2106    
2107 wakaba 1.16 if ($has_xattr->{$xattr_name} and not $xattr_def->{allow_multiple}) {
2108     ## ISSUE: Whether multiple extended attributes with the same
2109     ## name are allowed is not explicitly specified in the spec.
2110     ## It is, however, specified that some extended attributes may
2111     ## be specified more than once.
2112     $onerror->(type => 'duplicate xattr',
2113     text => $xattr_name,
2114     node => $xattr,
2115     level => $levels->{warn});
2116     }
2117     $has_xattr->{$xattr_name} = 1;
2118    
2119 wakaba 1.15 if (not $xattr_def->{allow_id} and defined $xattr->value) {
2120     $onerror->(type => 'xattr id not allowed',
2121     text => $xattr_name,
2122     node => $xattr,
2123     level => $levels->{must});
2124     }
2125     if (not $xattr_def->{allow_arglist} and $xattr->has_argument_list) {
2126     $onerror->(type => 'xattr arglist not allowed',
2127     text => $xattr_name,
2128     node => $xattr,
2129     level => $levels->{must});
2130     }
2131    
2132     $xattr_def->{check}->($self, $onerror, $levels, $items, $item,
2133 wakaba 1.16 $xattr, $xattr_name, $resolve, $constructors);
2134     }
2135 wakaba 1.15
2136 wakaba 1.16 if (not $has_xattr->{NoInterfaceObject} and
2137     (($item->{node}->isa ('Whatpm::WebIDL::Interface') and
2138     not $item->{node}->is_forward_declaration) or
2139     $item->{node}->isa ('Whatpm::WebIDL::Exception'))) {
2140     my $id = $item->{node}->node_name;
2141     if ($constructors->{$id} and
2142     $constructors->{$id}->{is_named_constructor}) {
2143     $onerror->(type => 'duplicate constructor name',
2144     value => $id,
2145     node => $constructors->{$id}->{is_named_constructor},
2146     level => $levels->{must});
2147     } else {
2148     ## NOTE: Duplication is not checked in this case, since any
2149     ## duplication of interface/exception identifiers are detected
2150     ## by the parser.
2151     $constructors->{$id} = {node => $item->{node}};
2152 wakaba 1.9 }
2153 wakaba 1.8 }
2154     }
2155     } # check
2156    
2157     package Whatpm::WebIDL::Definition;
2158     push our @ISA, 'Whatpm::WebIDL::Node';
2159    
2160     sub new ($$) {
2161     return bless {child_nodes => [], node_name => ''.$_[1]}, $_[0];
2162     } # new
2163    
2164 wakaba 1.4 sub set_extended_attribute_node ($$) {
2165     my $self = shift;
2166     ## TODO: check
2167     push @{$self->{xattrs} ||= []}, shift;
2168     } # set_extended_attribute_node
2169    
2170     sub _xattrs_text ($) {
2171     my $self = shift;
2172    
2173     unless ($self->{xattrs} and
2174     @{$self->{xattrs}}) {
2175     return '';
2176     }
2177    
2178     my $r = '[';
2179     $r .= join ', ', map {$_->idl_text} @{$self->{xattrs}};
2180     $r .= ']';
2181     return $r;
2182     } # _xattrs_text
2183    
2184 wakaba 1.9 sub qualified_name ($) {
2185     my $self = shift;
2186    
2187     my $parent = $self->{parent_node};
2188     if ($parent and $parent->isa ('Whatpm::WebIDL::Definition')) {
2189     return $parent->qualified_name . '::' . $self->{node_name};
2190     } else {
2191     return '::' . $self->{node_name};
2192     }
2193     } # qualified_name
2194    
2195 wakaba 1.1 sub type ($;$) {
2196     if (@_ > 1) {
2197     if (defined $_[1]) {
2198     $_[0]->{type} = $_[1];
2199     } else {
2200 wakaba 1.11 $_[0]->{type} = '::any::';
2201 wakaba 1.1 }
2202     }
2203     return $_[0]->{type};
2204     } # type
2205    
2206 wakaba 1.6 my $serialize_type;
2207     $serialize_type = sub ($) {
2208     my $type = shift;
2209 wakaba 1.11 if ($type =~ s/^::::sequence:::://) {
2210     return 'sequence<' . $serialize_type->($type) . '>';
2211     } elsif ($type =~ /\A::([^:]+)::\z/) {
2212     return $1;
2213 wakaba 1.6 } else {
2214 wakaba 1.13 $type =~ s/::DOMString::::\z/::DOMString/;
2215 wakaba 1.10 return $type; ## TODO: escape identifiers...
2216 wakaba 1.6 }
2217     }; # $serialize_type
2218    
2219 wakaba 1.1 sub type_text ($) {
2220     my $type = $_[0]->{type};
2221     return undef unless defined $type;
2222 wakaba 1.6
2223     return $serialize_type->($type);
2224 wakaba 1.1 } # type_text
2225 wakaba 1.6
2226 wakaba 1.1 package Whatpm::WebIDL::Module;
2227     push our @ISA, 'Whatpm::WebIDL::Definition';
2228    
2229     sub idl_text ($) {
2230 wakaba 1.4 my $self = shift;
2231     my $r = $self->_xattrs_text;
2232     $r .= ' ' if length $r;
2233 wakaba 1.8 $r .= 'module ' . $self->node_name . " {\x0A\x0A"; ## TODO: escape
2234 wakaba 1.4 for (@{$self->{child_nodes}}) {
2235 wakaba 1.1 $r .= $_->idl_text;
2236     }
2237     $r .= "\x0A};\x0A";
2238     return $r;
2239     } # idl_text
2240    
2241     package Whatpm::WebIDL::Interface;
2242     push our @ISA, 'Whatpm::WebIDL::Definition';
2243    
2244     sub new ($$) {
2245     my $self = shift->SUPER::new (@_);
2246     $self->{inheritances} = [];
2247     return $self;
2248     } # new
2249    
2250     sub append_inheritance ($$) {
2251     my $self = shift;
2252     my $scoped_name = shift;
2253     push @{$self->{inheritances}}, $scoped_name;
2254     } # append_inheritance
2255    
2256     sub idl_text ($) {
2257 wakaba 1.3 my $self = shift;
2258 wakaba 1.4 my $r = $self->_xattrs_text;
2259     $r .= ' ' if length $r;
2260 wakaba 1.9 $r .= 'interface ' . $self->node_name;
2261 wakaba 1.8
2262     if ($self->{is_forward_declaration}) {
2263     $r .= ";\x0A";
2264     return $r;
2265     }
2266    
2267 wakaba 1.3 if (@{$self->{inheritances}}) {
2268     $r .= ' : '; ## TODO: ...
2269 wakaba 1.10 $r .= join ', ', map {$serialize_type->($_)} @{$self->{inheritances}};
2270 wakaba 1.3 }
2271     $r .= " {\x0A"; ## TODO: escape
2272     for (@{$self->{child_nodes}}) {
2273 wakaba 1.1 $r .= ' ' . $_->idl_text;
2274     }
2275     $r .= "};\x0A";
2276     return $r;
2277     } # idl_text
2278    
2279 wakaba 1.8 sub is_forward_declaration ($;$) {
2280     if (@_ > 1) {
2281     if ($_[1]) {
2282     $_[0]->{is_forward_declaration} = 1;
2283     } else {
2284     delete $_[0]->{is_forward_declaration};
2285     }
2286     }
2287    
2288     return $_[0]->{is_forward_declaration};
2289     } # is_forward_declaration
2290    
2291 wakaba 1.1 package Whatpm::WebIDL::Exception;
2292     push our @ISA, 'Whatpm::WebIDL::Definition';
2293    
2294 wakaba 1.3 sub idl_text ($) {
2295 wakaba 1.4 my $self = shift;
2296     my $r = $self->_xattrs_text;
2297     $r .= ' ' if length $r;
2298 wakaba 1.9 $r .= 'exception ' . $self->node_name . " {\x0A"; ## TODO: escape
2299 wakaba 1.4 for (@{$self->{child_nodes}}) {
2300 wakaba 1.3 $r .= ' ' . $_->idl_text;
2301     }
2302     $r .= "};\x0A";
2303     return $r;
2304     } # idl_text
2305    
2306 wakaba 1.1 package Whatpm::WebIDL::Typedef;
2307     push our @ISA, 'Whatpm::WebIDL::Definition';
2308    
2309     sub new ($$) {
2310     my $self = shift->SUPER::new (@_);
2311 wakaba 1.11 $self->{type} = '::any::';
2312 wakaba 1.1 return $self;
2313     } # new
2314    
2315     sub idl_text ($) {
2316 wakaba 1.4 my $self = shift;
2317     my $r = $self->_xattrs_text;
2318     $r .= ' ' if length $r;
2319 wakaba 1.13 my $node_name = $self->node_name;
2320     $node_name = 'DOMString' if $node_name eq '::DOMString::';
2321 wakaba 1.1 ## TODO: escape
2322 wakaba 1.13 $r .= 'typedef ' . $self->type_text . ' ' . $node_name . ";\x0A";
2323 wakaba 1.4 return $r;
2324 wakaba 1.1 } # idl_text
2325    
2326     package Whatpm::WebIDL::Valuetype;
2327     push our @ISA, 'Whatpm::WebIDL::Definition';
2328    
2329     sub new ($$) {
2330     my $self = shift->SUPER::new (@_);
2331 wakaba 1.11 $self->{type} = '::boolean::';
2332 wakaba 1.1 return $self;
2333     } # new
2334    
2335     sub idl_text ($) {
2336 wakaba 1.4 my $self = shift;
2337     my $r = $self->_xattrs_text;
2338     $r .= ' ' if length $r;
2339 wakaba 1.14 my $name = $self->node_name;
2340     $name = 'DOMString' if $name eq '::DOMString::';
2341 wakaba 1.1 ## TODO: escape
2342 wakaba 1.14 $r .= 'valuetype ' . $name . ' ' . $self->type_text . ";\x0A";
2343 wakaba 1.4 return $r;
2344 wakaba 1.1 } # idl_text
2345    
2346     package Whatpm::WebIDL::InterfaceMember;
2347 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2348 wakaba 1.1
2349     sub new ($$) {
2350     return bless {node_name => ''.$_[1]}, $_[0];
2351     } # new
2352    
2353 wakaba 1.8 sub child_nodes ($) { return [] }
2354    
2355 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
2356    
2357     *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
2358    
2359 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
2360    
2361     *type_text = \&Whatpm::WebIDL::Definition::type_text;
2362    
2363     package Whatpm::WebIDL::Const;
2364     push our @ISA, 'Whatpm::WebIDL::Definition', 'Whatpm::WebIDL::InterfaceMember';
2365    
2366     sub new ($$) {
2367     my $self = shift->SUPER::new (@_); # Definition->new should be called
2368 wakaba 1.11 $self->{type} = '::boolean::';
2369 wakaba 1.1 $self->{value} = ['FALSE'];
2370     return $self;
2371     } # new
2372    
2373     sub value ($;$) {
2374     if (@_ > 1) {
2375 wakaba 1.11 if (defined $_[1]) {
2376     $_[0]->{value} = $_[1];
2377     } else {
2378     $_[0]->{value} = ['FALSE'];
2379     }
2380 wakaba 1.1 }
2381    
2382     return $_[0]->{value};
2383     } # value
2384    
2385     sub value_text ($) {
2386     my $value = $_[0]->{value};
2387    
2388     if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
2389     return $value->[0];
2390     } elsif ($value->[0] eq 'integer' or $value->[0] eq 'float') {
2391     ## TODO: format
2392     return $value->[1];
2393     } else {
2394     return undef;
2395     }
2396     } # value_text
2397    
2398     sub idl_text ($) {
2399 wakaba 1.4 my $self = shift;
2400     my $r = $self->_xattrs_text;
2401     $r .= ' ' if length $r;
2402     $r .= 'const ' . $self->type_text . ' ' . $self->node_name . ' = ' . $self->value_text . ";\x0A"; ## TODO: escape
2403     return $r;
2404 wakaba 1.1 } # idl_text
2405    
2406     package Whatpm::WebIDL::Attribute;
2407     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
2408    
2409     sub new ($$) {
2410     my $self = shift->SUPER::new (@_);
2411 wakaba 1.11 $self->{type} = '::any::';
2412 wakaba 1.2 $self->{getraises} = [];
2413     $self->{setraises} = [];
2414 wakaba 1.1 return $self;
2415     } # new
2416    
2417 wakaba 1.2 sub append_getraises ($$) {
2418     ## TODO: error check, etc.
2419     push @{$_[0]->{getraises}}, $_[1];
2420     } # append_getraises
2421    
2422     sub append_setraises ($$) {
2423     ## TODO: error check, etc.
2424     push @{$_[0]->{setraises}}, $_[1];
2425     } # append_setraises
2426    
2427 wakaba 1.1 sub readonly ($;$) {
2428     if (@_ > 1) {
2429     $_[0]->{readonly} = $_[1];
2430     }
2431    
2432     return $_[0]->{readonly};
2433     } # readonly
2434    
2435     sub idl_text ($) {
2436 wakaba 1.2 my $self = shift;
2437 wakaba 1.4 my $r = $self->_xattrs_text;
2438     $r .= ' ' if length $r;
2439     $r .= ($self->readonly ? 'readonly ' : '') . 'attribute ' . $self->type_text . ' ' . $self->node_name;
2440 wakaba 1.1 ## TODO: escape
2441 wakaba 1.2 if (@{$self->{getraises}}) {
2442     $r .= ' getraises (';
2443     ## todo: ...
2444 wakaba 1.12 $r .= join ', ', map {$serialize_type->($_)} @{$self->{getraises}};
2445 wakaba 1.2 $r .= ')';
2446     }
2447     if (@{$self->{setraises}}) {
2448     $r .= ' setraises (';
2449     ## todo: ...
2450 wakaba 1.12 $r .= join ', ', map {$serialize_type->($_)} @{$self->{setraises}};
2451 wakaba 1.2 $r .= ')';
2452     }
2453     $r .= ";\x0A";
2454     return $r;
2455 wakaba 1.1 } # idl_text
2456    
2457     package Whatpm::WebIDL::Operation;
2458     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
2459    
2460     sub new ($$) {
2461     my $self = shift->SUPER::new (@_);
2462 wakaba 1.11 $self->{type} = '::any::';
2463 wakaba 1.1 $self->{child_nodes} = [];
2464 wakaba 1.2 $self->{raises} = [];
2465 wakaba 1.1 return $self;
2466     } # new
2467    
2468 wakaba 1.2 sub append_raises ($$) {
2469     ## TODO: error check, etc.
2470     push @{$_[0]->{raises}}, $_[1];
2471     } # append_raises
2472    
2473 wakaba 1.1 sub idl_text ($) {
2474 wakaba 1.2 my $self = shift;
2475 wakaba 1.4 my $r = $self->_xattrs_text;
2476     $r .= ' ' if length $r;
2477     $r .= $self->type_text . ' ' . $self->node_name . ' ('; ## TODO: escape
2478 wakaba 1.2 $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
2479     $r .= ')';
2480     if (@{$self->{raises}}) {
2481     $r .= ' raises (';
2482     ## todo: ...
2483 wakaba 1.12 $r .= join ', ', map {$serialize_type->($_)} @{$self->{raises}};
2484 wakaba 1.2 $r .= ')';
2485     }
2486 wakaba 1.1 $r .= ";\x0A";
2487     return $r;
2488     } # idl_text
2489    
2490     package Whatpm::WebIDL::Argument;
2491 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2492 wakaba 1.1
2493     sub new ($$) {
2494 wakaba 1.11 return bless {node_name => ''.$_[1], type => '::any::'}, $_[0];
2495 wakaba 1.1 } # new
2496    
2497     sub idl_text ($) {
2498 wakaba 1.4 my $self = shift;
2499     my $r = $self->_xattrs_text;
2500     $r .= ' ' if length $r;
2501     $r .= 'in ' . $self->type_text . ' ' . $self->node_name; ## TODO: escape
2502     return $r;
2503 wakaba 1.3 } # idl_text
2504    
2505 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
2506    
2507     *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
2508    
2509 wakaba 1.3 *type = \&Whatpm::WebIDL::Definition::type;
2510    
2511     *type_text = \&Whatpm::WebIDL::Definition::type_text;
2512    
2513     package Whatpm::WebIDL::ExceptionMember;
2514 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2515 wakaba 1.3
2516     sub new ($$) {
2517 wakaba 1.11 return bless {node_name => ''.$_[1], type => '::any::'}, $_[0];
2518 wakaba 1.3 } # new
2519    
2520     sub idl_text ($) {
2521 wakaba 1.4 my $self = shift;
2522     my $r = $self->_xattrs_text;
2523     $r .= ' ' if length $r;
2524     $r .= $self->type_text . ' ' . $self->node_name . ";\x0A"; ## TODO: escape
2525     return $r;
2526 wakaba 1.1 } # idl_text
2527    
2528 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
2529    
2530     *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
2531    
2532 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
2533    
2534     *type_text = \&Whatpm::WebIDL::Definition::type_text;
2535 wakaba 1.9
2536 wakaba 1.4 package Whatpm::WebIDL::ExtendedAttribute;
2537 wakaba 1.8 push our @ISA, 'Whatpm::WebIDL::Node';
2538 wakaba 1.4
2539     sub new ($$) {
2540     return bless {child_nodes => [], node_name => ''.$_[1]};
2541     } # new
2542    
2543 wakaba 1.15 sub has_argument_list ($;$) {
2544     if (@_ > 1) {
2545     if ($_[1]) {
2546     $_[0]->{has_argument_list} = 1;
2547     } else {
2548     delete $_[0]->{has_argument_list};
2549     }
2550     }
2551    
2552     return ($_[0]->{has_argument_list} or scalar @{$_[0]->{child_nodes}});
2553     } # has_argument_list
2554    
2555 wakaba 1.4 sub idl_text ($) {
2556     my $self = shift;
2557     my $r = $self->node_name; ## TODO:] esceape
2558     if (defined $self->{value}) {
2559     $r .= '=' . $self->{value}; ## TODO: escape
2560     }
2561 wakaba 1.15 if ($self->has_argument_list) {
2562 wakaba 1.4 $r .= ' (';
2563     $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
2564     $r .= ')';
2565     }
2566     return $r;
2567     } # idl_text
2568    
2569     sub value ($;$) {
2570     if (@_ > 1) {
2571     if (defined $_[1]) {
2572     $_[0]->{value} = ''.$_[1];
2573     } else {
2574     delete $_[0]->{value};
2575     }
2576     }
2577    
2578     return $_[0]->{value};
2579     } # value
2580 wakaba 1.1
2581 wakaba 1.19 =head1 LICENSE
2582    
2583     Copyright 2008 Wakaba <w@suika.fam.cx>
2584    
2585     This library is free software; you can redistribute it
2586     and/or modify it under the same terms as Perl itself.
2587    
2588     =cut
2589    
2590 wakaba 1.1 1;
2591 wakaba 1.19 # $Date: 2008/08/30 14:37:46 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24