/[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.14 - (hide annotations) (download)
Sun Aug 3 07:24:15 2008 UTC (16 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.13: +5 -11 lines
++ whatpm/t/webidl/ChangeLog	3 Aug 2008 07:24:09 -0000
	* webidl-valuetype.dat: Test data for ignored DOMString
	valuetype are added.

2008-08-03  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/Whatpm/ChangeLog	3 Aug 2008 07:23:42 -0000
	* WebIDL.pm (parse_char_string): Simplified error
	reporting process for broken ignored valuetype definition.
	(Valuetype idl_text): Support for special "DOMString" name.

2008-08-03  Wakaba  <wakaba@suika.fam.cx>

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24