/[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.7 - (hide annotations) (download)
Sat Jul 19 14:47:23 2008 UTC (16 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.6: +1 -1 lines
++ ChangeLog	19 Jul 2008 14:47:12 -0000
2008-07-19  Wakaba  <wakaba@suika.fam.cx>

	* readme.en.html: Link to Whatpm::WebIDL module.

1 wakaba 1.1 package Whatpm::WebIDL;
2     use strict;
3    
4     package Whatpm::WebIDL::Parser;
5    
6     my $integer = qr/-?0([0-7]*|[Xx][0-9A-Fa-f]+)|[1-9][0-9]*/;
7     my $float = qr/-?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+/;
8     my $identifier = qr/[A-Z_a-z][0-9A-Z_a-z]*/;
9     my $whitespace = qr<[\t\n\r ]+|[\t\n\r ]*((//.*|/\*.*?\*/)[\t\n\r ]*)+>;
10    
11     sub new ($) {
12     my $self = bless {
13     must_level => 'm',
14     should_level => 's',
15     warn_level => 'w',
16     info_level => 'i',
17     }, $_[0];
18     return $self;
19     } # new
20    
21     sub parse_char_string ($$;$) {
22     my $self = shift;
23     my $s = ref $_[0] ? $_[0] : \($_[0]);
24    
25     my $defs = Whatpm::WebIDL::Definitions->new;
26    
27     pos ($$s) = 0;
28     my $line = 1;
29     my $column = 0;
30    
31     my $get_next_token = sub {
32     if (length $$s <= pos $$s) {
33     return {type => 'eof'};
34     }
35    
36     while ($$s =~ /\G($whitespace)/gc) {
37     my $v = $1;
38     while ($v =~ s/^[^\x0D\x0A]*(?>\x0D\x0A?|\x0A)//) {
39     $line++;
40     $column = 0;
41     }
42     $column += length $v;
43     }
44    
45     if (length $$s <= pos $$s) {
46     return {type => 'eof'};
47     }
48    
49     ## ISSUE: "must"s in "A. IDL grammer" are not "MUST"s.
50    
51     if ($$s =~ /\G($identifier)/gc) {
52     my $v = $1;
53     $column += length $v;
54     if ({
55     module => 1, interface => 1, exception => 1, typedef => 1,
56     valuetype => 1, DOMString => 1, sequence => 1, unsigned => 1,
57     short => 1, const => 1, TRUE => 1, FALSE => 1, readonly => 1,
58     attribute => 1, getraises => 1, setraises => 1, raises => 1, in => 1,
59     any => 1, boolean => 1, octet => 1, float => 1, Object => 1,
60     short => 1, long => 1, void => 1,
61     }->{$v}) {
62     return {type => $v};
63     } else {
64     return {type => 'identifier', value => $v};
65     }
66     } elsif ($$s =~ /\G($float)/gc) { ## ISSUE: negative number
67     $column += length $1;
68     return {type => 'float', value => $1};
69     } elsif ($$s =~ /\G($integer)/gc) { ## ISSUE: negative nmber
70     $column += length $1;
71     return {type => 'integer', value => $1};
72     } elsif ($$s =~ /\G::/gcs) {
73     $column += 2;
74     return {type => '::'};
75     } elsif ($$s =~ /\G(.)/gcs) { ## NOTE: Should never be a newline char.
76     $column++;
77     return {type => $1};
78     } else {
79     die "get_next_token: non-possible case: " . substr ($$s, pos $$s, 20);
80     }
81     }; # $get_next_token
82    
83     my $state = 'before definitions';
84     my $token = $get_next_token->();
85     my $nest_level = 0;
86     my $next_state;
87     my $xattrs;
88 wakaba 1.4 my $prev_xattrs = [];
89 wakaba 1.1 my $last_xattr;
90     my $read_only;
91     my $current_type;
92     my @current = ($defs);
93    
94     my $_onerror = $_[1] || sub {
95     my %opt = @_;
96     my $r = 'Line ' . $opt{line} . ' column ' . $opt{column} . ': ';
97    
98     if ($opt{token}) {
99     $r .= 'Token ' . (defined $opt{token}->{value} ? $opt{token}->{value} : $opt{token}->{type}) . ': ';
100     }
101    
102     $r .= $opt{type} . ';' . $opt{level};
103    
104     warn $r . "\n";
105     }; # $_onerror
106     my $onerror = sub {
107     $_onerror->(line => $line, column => $column, token => $token, @_);
108     }; # $onerror
109    
110     my $get_scoped_name = sub {
111     my $name = [];
112    
113     ## NOTE: "DOMString" is not a scoped name, while "::DOMString"
114     ## and "x::DOMString" are.
115    
116     if ($token->{type} eq 'identifier') {
117     ## TODO: unescape
118     push @$name, $token->{value};
119     $token = $get_next_token->();
120     while ($token->{type} eq '::') {
121 wakaba 1.2 $token = $get_next_token->();
122 wakaba 1.1 if ($token->{type} eq 'identifier') {
123     ## TODO: unescape
124     push @$name, $token->{value};
125     $token = $get_next_token->();
126     } elsif ($token->{type} eq 'DOMString') {
127     push @$name, '::DOMString::';
128     $token = $get_next_token->();
129     last;
130     }
131     }
132     } elsif ($token->{type} eq '::') {
133     push @$name, '';
134     while ($token->{type} eq '::') {
135 wakaba 1.2 $token = $get_next_token->();
136 wakaba 1.1 if ($token->{type} eq 'identifier') {
137     ## TODO: unescape
138     push @$name, $token->{value};
139     $token = $get_next_token->();
140     } elsif ($token->{type} eq 'DOMString') {
141     push @$name, '::DOMString::';
142     $token = $get_next_token->();
143     last;
144     } else {
145     last;
146     }
147     }
148    
149     if (@$name == 1) {
150     return undef;
151     }
152     } else {
153     # reconsume
154     return undef;
155     }
156     return $name;
157     }; # $get_scoped_name
158    
159     my $get_type;
160     $get_type = sub {
161     my $r;
162     if ({
163     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
164     DOMString => 1, Object => 1, short => 1,
165     }->{$token->{type}}) {
166     $r = ['::'.$token->{type}.'::'];
167     $token = $get_next_token->();
168     } elsif ($token->{type} eq 'unsigned') {
169     $token = $get_next_token->();
170     if ($token->{type} eq 'short') {
171     $r = ['::unsigned '.$token->{type}.'::'];
172     $token = $get_next_token->();
173     } elsif ($token->{type} eq 'long') {
174     $token = $get_next_token->();
175     if ($token->{type} eq 'long') {
176     $r = ['::unsigned long long::'];
177     $token = $get_next_token->();
178     } else {
179     $r = ['::unsigned long::'];
180     # reconsume
181     }
182     } else {
183     $onerror->(type => 'unsigned', level => $self->{must_level});
184     return undef;
185     }
186     } elsif ($token->{type} eq 'long') {
187     $token = $get_next_token->();
188     if ($token->{type} eq 'long') {
189     $r = ['::long long::'];
190     $token = $get_next_token->();
191     } else {
192     $r = ['::long::'];
193     # reconsume
194     }
195     } elsif ($token->{type} eq '::' or $token->{type} eq 'identifier') {
196     $r = $get_scoped_name->();
197     if (defined $r) {
198     # next token
199     } else { # "::" not followed by identifier or "DOMString"
200     $onerror->(type => 'scoped name', level => $self->{must_level});
201     return undef;
202     }
203     } elsif ($token->{type} eq 'sequence') {
204     $token = $get_next_token->();
205     if ($token->{type} eq '<') {
206     $token = $get_next_token->();
207     if ({
208     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
209     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
210     sequence => 1, '::' => 1, identifier => 1,
211     }->{$token->{type}}) {
212     my $type = $get_type->();
213     if (defined $type) {
214     if ($token->{type} eq '>') {
215     $r = ['::sequence::', $type];
216     $token = $get_next_token->();
217     } else {
218     $onerror->(type => 'sequence gt', level => $self->{must_level});
219     return undef;
220     }
221     } else {
222     # error reported
223     return undef;
224     }
225     } else {
226     $onerror->(type => 'sequence type', level => $self->{must_level});
227     return undef;
228     }
229     } else {
230     $onerror->(type => 'sequence lt', level => $self->{must_level});
231     return undef;
232     }
233     } else {
234     die "get_type: bad token: $token->{type}";
235     }
236    
237     return $r;
238     }; # $get_type
239    
240     while (1) {
241     if ($state eq 'before definitions') {
242 wakaba 1.4 $xattrs = [];
243 wakaba 1.1 if ($token->{type} eq '[') {
244     $token = $get_next_token->();
245     $state = 'before xattr';
246     $next_state = 'before def';
247     } elsif ({module => 1, interface => 1, exception => 1,
248     typedef => 1, valuetype => 1, const => 1}->{$token->{type}}) {
249     # reconsume
250     $state = 'before def';
251     } elsif ($token->{type} eq '}' and @current > 1) {
252     $token = $get_next_token->();
253 wakaba 1.5 $state = 'before block semicolon';
254 wakaba 1.1 } elsif ($token->{type} eq 'eof') {
255     last;
256     } else {
257     $onerror->(type => 'before definitions', level => 'm',
258     token => $token);
259     # reconsume
260     $state = 'ignore';
261     $nest_level = 0;
262     $next_state = 'before definitions';
263     }
264     } elsif ($state eq 'before xattr') {
265     if ($token->{type} eq 'identifier') {
266     ## TODO: _escape
267     ## ISSUE: Duplicate attributes
268     ## ISSUE: Unkown attributes
269 wakaba 1.4 push @current, Whatpm::WebIDL::ExtendedAttribute->new ($token->{value});
270     push @$xattrs, $current[-1];
271 wakaba 1.1 $token = $get_next_token->();
272     $state = 'after xattr';
273     } else {
274     $onerror->(type => 'before xattr', level => 'm', token => $token);
275     # reconsume
276     $state = 'ignore';
277     $nest_level = 0;
278 wakaba 1.4 $next_state = 'before definitions'; ## TODO:
279 wakaba 1.1 }
280     } elsif ($state eq 'after xattr') {
281     if ($token->{type} eq '=') {
282     $token = $get_next_token->();
283     $state = 'before xattrarg';
284 wakaba 1.4 } elsif ($token->{type} eq '(') {
285     $token = $get_next_token->();
286     if ($token->{type} eq ')') {
287     $token = $get_next_token->();
288     push @$prev_xattrs, $xattrs;
289     $state = 'after xattrarg';
290     } else {
291     push @$prev_xattrs, $xattrs;
292     # reconsume
293     $state = 'before argument';
294     }
295 wakaba 1.1 } else {
296 wakaba 1.4 push @$prev_xattrs, $xattrs;
297 wakaba 1.1 # reconsume
298     $state = 'after xattrarg';
299     }
300     } elsif ($state eq 'before xattrarg') {
301     if ($token->{type} eq 'identifier') {
302     ## TODO: escape
303 wakaba 1.4 $current[-1]->value ($token->{value});
304 wakaba 1.1 $token = $get_next_token->();
305 wakaba 1.4 if ($token->{type} eq '(') {
306     $token = $get_next_token->();
307     if ($token->{type} eq ')') {
308     push @$prev_xattrs, $xattrs;
309     $token = $get_next_token->();
310     $state = 'after xattrarg';
311     } else {
312     push @$prev_xattrs, $xattrs;
313     # reconsume
314     $state = 'before argument';
315     }
316     } else {
317     push @$prev_xattrs, $xattrs;
318     # reconsume
319     $state = 'after xattrarg';
320     }
321 wakaba 1.1 } else {
322     $onerror->(type => 'after xattrarg', level => 'm', token => $token);
323     # reconsume
324     $state = 'ignore';
325     $nest_level = 0;
326     $next_state = 'before definitions';
327     }
328     } elsif ($state eq 'after xattrarg') {
329 wakaba 1.4 pop @current; # xattr
330     $xattrs = pop @$prev_xattrs;
331 wakaba 1.1 if ($token->{type} eq ',') {
332     $token = $get_next_token->();
333     $state = 'before xattr';
334     } elsif ($token->{type} eq ']') {
335     $token = $get_next_token->();
336 wakaba 1.4 if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
337     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
338     $state = 'before definitions';
339     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
340     $state = 'before interface member';
341     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Exception')) {
342     $state = 'before exception member';
343     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Operation') or
344     $current[-1]->isa ('Whatpm::WebIDL::ExtendedAttribute')) {
345     $state = 'before argument in';
346     } else {
347     die "$0: Unknown xattr context: " . ref $current[-1];
348     }
349 wakaba 1.1 } else {
350     $onerror->(type => 'after xattr', level => 'm', token => $token);
351     # reconsume
352     $state = 'ignore';
353     $nest_level = 0;
354 wakaba 1.4 $next_state = 'before definitions'; ## TODO:
355 wakaba 1.1 }
356     } elsif ($state eq 'before def') {
357     if ($token->{type} eq 'module') {
358     $token = $get_next_token->();
359     if ($token->{type} eq 'identifier') {
360     ## TODO: escape
361     push @current, Whatpm::WebIDL::Module->new ($token->{value});
362 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
363 wakaba 1.1 $token = $get_next_token->();
364     $state = 'before module block';
365     next;
366     } else {
367     $onerror->(type => 'module identifier',
368     level => $self->{must_level});
369     #
370     }
371     } elsif ($token->{type} eq 'interface') {
372     $token = $get_next_token->();
373     if ($token->{type} eq 'identifier') {
374     ## TODO: escape
375     push @current, Whatpm::WebIDL::Interface->new ($token->{value});
376 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
377 wakaba 1.1 $token = $get_next_token->();
378     $state = 'before interface inheritance';
379     next;
380     } else {
381     $onerror->(type => 'interface identifier',
382     level => $self->{must_level});
383     #
384     }
385     } elsif ($token->{type} eq 'exception') {
386     $token = $get_next_token->();
387     if ($token->{type} eq 'identifier') {
388     ## TODO: escape
389     push @current, Whatpm::WebIDL::Exception->new ($token->{value});
390 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
391 wakaba 1.1 $token = $get_next_token->();
392     $state = 'before exception block';
393     next;
394     } else {
395     $onerror->(type => 'exception identifier',
396     level => $self->{must_level});
397     #
398     }
399     } elsif ($token->{type} eq 'typedef') {
400     $token = $get_next_token->();
401     $state = 'before typedef type';
402     next;
403     } elsif ($token->{type} eq 'valuetype') {
404     $token = $get_next_token->();
405     if ($token->{type} eq 'identifier') {
406     ## TODO: escape
407     push @current, Whatpm::WebIDL::Valuetype->new ($token->{value});
408 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
409 wakaba 1.1 $token = $get_next_token->();
410     $state = 'before boxed type';
411     next;
412     } elsif ($token->{type} eq 'DOMString') {
413     push @current, Whatpm::WebIDL::Valuetype->new ('::DOMString::');
414 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
415 wakaba 1.1 $token = $get_next_token->();
416     if ($token->{type} eq 'sequence') {
417     $token = $get_next_token->();
418     if ($token->{type} eq '<') {
419     $token = $get_next_token->();
420     if ($token->{type} eq 'unsigned') {
421     $token = $get_next_token->();
422     if ($token->{type} eq 'short') {
423     $token = $get_next_token->();
424     if ($token->{type} eq '>') {
425     $current[-1]->type
426     (['::sequence::', ['::unsigned short::']]);
427     $token = $get_next_token->();
428     $state = 'before semicolon';
429     $next_state = 'before definitions';
430     next;
431     } else {
432     $onerror->(type => 'valuetype DOMString sequence lt unsigned short gt',
433     level => $self->{must_level});
434     #
435     }
436     } else {
437     $onerror->(type => 'valuetype DOMString sequence lt unsigned short',
438     level => $self->{must_level});
439     #
440     }
441     } else {
442     $onerror->(type => 'valuetype DOMString sequence lt unsigned',
443     level => $self->{must_level});
444     #
445     }
446     } else {
447     $onerror->(type => 'valuetype DOMString sequence lt',
448     level => $self->{must_level});
449     #
450     }
451     } else {
452     $onerror->(type => 'valuetype DOMString sequence',
453     level => $self->{must_level});
454     #
455     }
456     shift @current; # valuetype
457     #
458     } else {
459     $onerror->(type => 'valuetype identifier',
460     level => $self->{must_level});
461     #
462     }
463     } elsif ($token->{type} eq 'const') {
464     $token = $get_next_token->();
465     $state = 'before const type';
466     $next_state = 'before definitions';
467     next;
468     } else {
469     $onerror->(type => 'before definition', level => 'm',
470     token => $token);
471     # reconsume
472     #
473     }
474     $state = 'ignore';
475     $nest_level = 0;
476     $next_state = 'before definitions';
477     } elsif ($state eq 'before module block') {
478     if ($token->{type} eq '{') {
479     $token = $get_next_token->();
480     $state = 'before definitions';
481     } else {
482     $onerror->(type => 'before module block', level => 'm',
483     token => $token);
484     pop @current; # module
485     # reconsume
486     $state = 'ignore';
487     $nest_level = 0;
488     $next_state = 'before definitions';
489     }
490     } elsif ($state eq 'before interface inheritance') {
491     if ($token->{type} eq ':') {
492     $token = $get_next_token->();
493     $state = 'before parent interface name';
494     } else {
495     # reconsume
496     $state = 'before interface block';
497     }
498     } elsif ($state eq 'before parent interface name') {
499     my $name = $get_scoped_name->();
500     if (defined $name) {
501     $current[-1]->append_inheritance ($name);
502    
503     if ($token->{type} eq ',') {
504     $token = $get_next_token->();
505     # stay in the state
506     } else {
507     # reconsume
508     $state = 'before interface block';
509     }
510     } else {
511     $onerror->(type => 'scoped name', level => $self->{must_level});
512     # reconsume
513     $state = 'ignore';
514     $nest_level = 0;
515     }
516 wakaba 1.2 } elsif ($state eq 'before exception name') {
517     my $name = $get_scoped_name->();
518     if (defined $name) {
519     my $method = $next_state eq '*raises' ? 'append_raises' :
520     $next_state eq '*getraises' ? 'append_getraises' :
521     'append_setraises';
522     $current[-1]->$method ($name);
523    
524     if ($token->{type} eq ',') {
525     $token = $get_next_token->();
526     # stay in the state
527     } elsif ($token->{type} eq ')') {
528     $token = $get_next_token->();
529     if ($next_state eq '*getraises' and $token->{type} eq 'setraises') {
530     $token = $get_next_token->();
531     $state = 'after raises';
532     $next_state = '*setraises';
533     } else {
534     # reprocess
535     $state = 'before semicolon';
536     $next_state = 'before interface member';
537     }
538     } else {
539     $onerror->(type => 'after exception name',
540     level => $self->{must_level});
541     # reconsume
542     $state = 'ignore';
543     $nest_level = 0;
544     }
545     } else {
546     $onerror->(type => 'scoped name', level => $self->{must_level});
547     # reconsume
548     $state = 'ignore';
549     $nest_level = 0;
550     }
551 wakaba 1.1 } elsif ($state eq 'before interface block') {
552     if ($token->{type} eq '{') {
553     $token = $get_next_token->();
554     $state = 'before members';
555     $next_state = 'before interface member';
556     } else {
557     $onerror->(type => 'before interface block',
558     level => $self->{must_level});
559     # reconsume
560     $state = 'ignore';
561     $nest_level = 0;
562     }
563     } elsif ($state eq 'before exception block') {
564     if ($token->{type} eq '{') {
565     $token = $get_next_token->();
566     $state = 'before members';
567     $next_state = 'before exception member';
568     } else {
569     $onerror->(type => 'before exception block',
570     level => $self->{must_level});
571     # reconsume
572     $state = 'ignore';
573     $nest_level = 0;
574     }
575     } elsif ($state eq 'before members') {
576 wakaba 1.4 $xattrs = [];
577 wakaba 1.1 if ($token->{type} eq '[') {
578     $token = $get_next_token->();
579     $state = 'before xattr';
580     #$next_state = $next_state; # 'before interface member' or ...
581     } elsif ($token->{type} eq '}') {
582     $token = $get_next_token->();
583 wakaba 1.5 $state = 'before block semicolon';
584 wakaba 1.1 } else {
585     # reconsume
586     $state = $next_state; # ... 'before exception member'
587     }
588     } elsif ($state eq 'before interface member') {
589     if ($token->{type} eq 'const') {
590     $token = $get_next_token->();
591     $state = 'before const type';
592     $next_state = 'before definitions';
593     } elsif ($token->{type} eq 'readonly') {
594     $read_only = 1;
595     $token = $get_next_token->();
596     if ($token->{type} eq 'attribute') {
597     $token = $get_next_token->();
598     $state = 'after attribute';
599     } else {
600     # reconsume
601     $state = 'ignore';
602     $nest_level = 0;
603     $next_state = 'before interface member';
604     }
605     } elsif ($token->{type} eq 'attribute') {
606     $read_only = 0;
607     $token = $get_next_token->();
608     $state = 'after attribute';
609     } elsif ({
610     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
611     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
612     '::' => 1, identifier => 1,
613     }->{$token->{type}}) {
614     # reconsume
615     $state = 'before operation type';
616     } elsif ($token->{type} eq '}') {
617     $token = $get_next_token->();
618     $state = 'before semicolon';
619     $next_state = 'before definitions';
620     } elsif ($token->{type} eq 'eof') {
621     last;
622     } else {
623     $onerror->(type => 'before interface member',
624     level => $self->{must_level});
625     # reconsume
626     $state = 'ignore';
627     $nest_level = 0;
628     }
629     } elsif ($state eq 'before exception member') {
630     if ({
631     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
632     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
633     '::' => 1, identifier => 1,
634     }->{$token->{type}}) {
635 wakaba 1.3 # reconsume
636     $state = 'before exception member type';
637 wakaba 1.1 } elsif ($token->{type} eq '}') {
638     $token = $get_next_token->();
639     $state = 'before semicolon';
640     $next_state = 'before definitions';
641     } elsif ($token->{type} eq 'eof') {
642     last;
643     } else {
644     $onerror->(type => 'before exception member',
645     level => $self->{must_level});
646     # reconsume
647     $state = 'ignore';
648     $nest_level = 0;
649     }
650     } elsif ($state eq 'before typedef type') {
651     if ({
652     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
653     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
654     sequence => 1, '::' => 1, identifier => 1,
655     }->{$token->{type}}) {
656     $current_type = $get_type->();
657     if (defined $current_type) {
658     # next token
659     $state = 'before typedef rest';
660     } else {
661     # reconsume
662     $state = 'ignore';
663     $nest_level = 0;
664     $next_state = 'before definitions';
665     }
666     } else {
667     $onerror->(type => 'before type', level => $self->{must_level});
668     # reconsume
669     $state = 'ignore';
670     $nest_level = 0;
671     $next_state = 'before definitions';
672     }
673     } elsif ($state eq 'before boxed type') {
674     if ({
675     boolean => 1, octet => 1, float => 1,
676     short => 1, long => 1, unsigned => 1,
677     sequence => 1, '::' => 1, identifier => 1,
678     }->{$token->{type}}) {
679     $current_type = $get_type->();
680     if (defined $current_type) {
681     $current[-1]->type ($current_type);
682     # next token
683     $state = 'before semicolon';
684     $next_state = 'before definitions';
685     } else {
686     shift @current; # valuetype
687     # reconsume
688     $state = 'ignore';
689     $nest_level = 0;
690     $next_state = 'before definitions';
691     }
692     } else {
693     $onerror->(type => 'before boxed type', level => $self->{must_level});
694     shift @current; # valuetype
695     # reconsume
696     $state = 'ignore';
697     $nest_level = 0;
698     $next_state = 'before definitions';
699     }
700     } elsif ($state eq 'before const type') {
701     if ({
702     any => 1, boolean => 1, octet => 1, float => 1,
703     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
704     '::' => 1, identifier => 1,
705     }->{$token->{type}}) {
706     $current_type = $get_type->();
707     if (defined $current_type) {
708     # next token
709     $state = 'before const identifier';
710     } else {
711     # reconsume
712     $state = 'ignore';
713     $nest_level = 0;
714     #$next_state = $next_state;
715     }
716     } else {
717     $onerror->(type => 'before type', level => $self->{must_level});
718     # reconsume
719     $state = 'ignore';
720     $nest_level = 0;
721     #$next_state = $next_state;
722     }
723     } elsif ($state eq 'before typedef rest') {
724     if ($token->{type} eq 'identifier') {
725     ## TODO: unescape
726     push @current, Whatpm::WebIDL::Typedef->new ($token->{value});
727     $current[-1]->type ($current_type);
728 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
729 wakaba 1.1 $token = $get_next_token->();
730     $state = 'before semicolon';
731     $next_state = 'before definitions';
732     } elsif ($token->{type} eq 'DOMString') {
733     push @current, Whatpm::WebIDL::Typedef->new ('::DOMString::');
734     $current[-1]->type ($current_type);
735 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
736 wakaba 1.1 $token = $get_next_token->();
737     $state = 'before semicolon';
738     $next_state = 'before defnitions';
739     } else {
740     $onerror->(type => 'before typedef rest',
741     level => $self->{must_level});
742     # reconsume
743     $state = 'ignore';
744     $nest_level = 0;
745     $next_state = 'before definitions';
746     }
747     } elsif ($state eq 'before const identifier') {
748     if ($token->{type} eq 'identifier') {
749     ## TODO: unescape
750     push @current, Whatpm::WebIDL::Const->new ($token->{value});
751     $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     if ($token->{type} eq '=') {
755     $token = $get_next_token->();
756     $state = 'before const expr';
757     next;
758     } else {
759     $onerror->(type => 'const eq', level => $self->{must_level});
760     #
761     }
762     } else {
763     $onerror->(type => 'const identifier', level => $self->{must_level});
764     #
765     }
766     # reconsume
767     $state = 'ignore';
768     $nest_level = 0;
769     #$next_state = $next_state;
770     } elsif ($state eq 'before const expr') {
771     if ($token->{type} eq 'TRUE' or $token->{type} eq 'FALSE') {
772     $current[-1]->value ([$token->{type}]);
773     #
774     } elsif ($token->{type} eq 'integer' or $token->{type} eq 'float') {
775     $current[-1]->value ([$token->{type}, $token->{value}]);
776     #
777     } else {
778     # reconsume
779     $state = 'ignore';
780     $nest_level = 0;
781     #$next_state = $next_state;
782     next;
783     }
784    
785     $token = $get_next_token->();
786     $state = 'before semicolon';
787     #$next_state = $next_state;
788     } elsif ($state eq 'after attribute') {
789     if ({
790     any => 1, boolean => 1, octet => 1, float => 1,
791     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
792     '::' => 1, identifier => 1,
793     }->{$token->{type}}) {
794     $current_type = $get_type->();
795     if (defined $current_type) {
796     # next token
797     $state = 'before attribute identifier';
798     } else {
799     # reconsume
800     $state = 'ignore';
801     $nest_level = 0;
802     $next_state = 'before interface member';
803     }
804     } else {
805     $onerror->(type => 'before type', level => $self->{must_level});
806     # reconsume
807     $state = 'ignore';
808     $nest_level = 0;
809     $next_state = 'before interface member';
810     }
811 wakaba 1.3 } elsif ($state eq 'before exception member type') {
812     if ({
813     any => 1, boolean => 1, octet => 1, float => 1,
814     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
815     '::' => 1, identifier => 1,
816     }->{$token->{type}}) {
817     $current_type = $get_type->();
818     if (defined $current_type) {
819     # next token
820     $state = 'before exception member identifier';
821     } else {
822     # reconsume
823     $state = 'ignore';
824     $nest_level = 0;
825     $next_state = 'before exception member';
826     }
827     } else {
828     $onerror->(type => 'before type', level => $self->{must_level});
829     # reconsume
830     $state = 'ignore';
831     $nest_level = 0;
832     $next_state = 'before exception member';
833     }
834 wakaba 1.1 } elsif ($state eq 'before operation type') {
835     if ({
836     any => 1, boolean => 1, octet => 1, float => 1,
837     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
838     '::' => 1, identifier => 1,
839     void => 1,
840     }->{$token->{type}}) {
841     $current_type = $get_type->();
842     if (defined $current_type) {
843     # next token
844     $state = 'before operation identifier';
845     } else {
846     # reconsume
847     $state = 'ignore';
848     $nest_level = 0;
849     $next_state = 'before interface member';
850     }
851     } else {
852     $onerror->(type => 'before type', level => $self->{must_level});
853     # reconsume
854     $state = 'ignore';
855     $nest_level = 0;
856     $next_state = 'before interface member';
857     }
858     } elsif ($state eq 'before argument type') {
859     if ({
860     any => 1, boolean => 1, octet => 1, float => 1,
861     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
862     '::' => 1, identifier => 1,
863     }->{$token->{type}}) {
864     $current_type = $get_type->();
865     if (defined $current_type) {
866     # next token
867     $state = 'before argument identifier';
868     } else {
869     # reconsume
870     $state = 'ignore';
871     $nest_level = 0;
872     }
873     } else {
874     $onerror->(type => 'before type', level => $self->{must_level});
875     # reconsume
876     $state = 'ignore';
877     $nest_level = 0;
878     }
879     } elsif ($state eq 'before attribute identifier') {
880     if ($token->{type} eq 'identifier') {
881     ## TODO: unescape
882     push @current, Whatpm::WebIDL::Attribute->new ($token->{value});
883     $current[-1]->readonly ($read_only);
884     $current[-1]->type ($current_type);
885 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
886 wakaba 1.1 $token = $get_next_token->();
887     if ($token->{type} eq 'getraises') {
888     $token = $get_next_token->();
889 wakaba 1.2 $state = 'after raises';
890     $next_state = '*getraises';
891 wakaba 1.1 next;
892     } elsif ($token->{type} eq 'setraises') {
893     $token = $get_next_token->();
894 wakaba 1.2 $state = 'after raises';
895     $next_state = '*setraises';
896 wakaba 1.1 next;
897     } else {
898     # reconsume
899     $state = 'before semicolon';
900     $next_state = 'before interface member';
901     next;
902     }
903     } else {
904     $onerror->(type => 'attribute identifier',
905     level => $self->{must_level});
906     #
907     }
908     # reconsume
909     $state = 'ignore';
910     $nest_level = 0;
911 wakaba 1.3 $next_state = 'before interface member';
912     } elsif ($state eq 'before exception member identifier') {
913     if ($token->{type} eq 'identifier') {
914     ## TODO: unescape
915     push @current, Whatpm::WebIDL::ExceptionMember->new ($token->{value});
916     $current[-1]->type ($current_type);
917 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
918 wakaba 1.3 $token = $get_next_token->();
919     $state = 'before semicolon';
920     $next_state = 'before exception member';
921     } else {
922     $onerror->(type => 'exception member identifier',
923     level => $self->{must_level});
924     # reconsume
925     $state = 'ignore';
926     $nest_level = 0;
927     }
928 wakaba 1.1 } elsif ($state eq 'before operation identifier') {
929     if ($token->{type} eq 'identifier') {
930     ## TODO: unescape
931     push @current, Whatpm::WebIDL::Operation->new ($token->{value});
932     $current[-1]->type ($current_type);
933 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
934 wakaba 1.1 $token = $get_next_token->();
935     if ($token->{type} eq '(') {
936     $token = $get_next_token->();
937     if ($token->{type} eq ')') {
938     $token = $get_next_token->();
939 wakaba 1.2 $state = 'before raises';
940     $next_state = '*raises';
941 wakaba 1.1 next;
942     } else {
943     # reconsume
944     $state = 'before argument';
945     next;
946     }
947     } else {
948     $onerror->(type => 'arguments lparen',
949     level => $self->{must_level});
950     #
951     }
952     } else {
953     $onerror->(type => 'operation identifier',
954     level => $self->{must_level});
955     #
956     }
957     # reconsume
958     $state = 'ignore';
959     $nest_level = 0;
960 wakaba 1.3 $next_state = 'before interface member';
961 wakaba 1.1 } elsif ($state eq 'before argument identifier') {
962     if ($token->{type} eq 'identifier') {
963     ## TODO: unescape
964     my $arg = Whatpm::WebIDL::Argument->new ($token->{value});
965     $arg->type ($current_type);
966 wakaba 1.4 $arg->set_extended_attribute_node ($_) for @$xattrs;
967 wakaba 1.1 $current[-1]->append_child ($arg);
968     $token = $get_next_token->();
969     if ($token->{type} eq ')') {
970     $token = $get_next_token->();
971 wakaba 1.4 if ($current[-1]->isa ('Whatpm::WebIDL::Operation')) {
972     $state = 'before raises';
973     } else {
974     $state = 'after xattrarg';
975     }
976 wakaba 1.1 next;
977     } elsif ($token->{type} eq ',') {
978     $token = $get_next_token->();
979     $state = 'before argument';
980     next;
981     } else {
982     $onerror->(type => 'after argument',
983     level => $self->{must_level});
984     #
985     }
986     } else {
987     $onerror->(type => 'argument identifier',
988     level => $self->{must_level});
989     #
990     }
991     # reconsume
992     $state = 'ignore';
993     $nest_level = 0;
994     } elsif ($state eq 'before argument') {
995 wakaba 1.4 $xattrs = [];
996 wakaba 1.1 if ($token->{type} eq '[') {
997     $token = $get_next_token->();
998     $state = 'before xattr';
999     $next_state = 'before argument in';
1000     } else {
1001     # reconsume
1002     $state = 'before argument in';
1003     }
1004     } elsif ($state eq 'before argument in') {
1005     if ($token->{type} eq 'in') {
1006     $token = $get_next_token->();
1007     $state = 'before argument type';
1008     } else {
1009     $onerror->(type => 'argument in',
1010     level => $self->{must_level});
1011     $state = 'ignore';
1012     $nest_level = 0;
1013     }
1014     } elsif ($state eq 'before raises') {
1015     if ($token->{type} eq 'raises') {
1016     $token = $get_next_token->();
1017     $state = 'after raises';
1018 wakaba 1.2 $next_state = '*raises';
1019 wakaba 1.1 } else {
1020     # reconsume
1021     $state = 'before semicolon';
1022     $next_state = 'before interface member';
1023     }
1024     } elsif ($state eq 'after raises') {
1025 wakaba 1.2 if ($token->{type} eq '(') {
1026     $token = $get_next_token->();
1027     $state = 'before exception name';
1028     } else {
1029     $onerror->(type => 'raises lparen',
1030     level => $self->{must_level});
1031     $state = 'ignore';
1032     $nest_level = 0;
1033     }
1034 wakaba 1.1 } elsif ($state eq 'before semicolon') {
1035     if ($token->{type} eq ';') {
1036     $current[-2]->append_child ($current[-1]);
1037     pop @current;
1038     $token = $get_next_token->();
1039 wakaba 1.5 if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
1040     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1041     $state = 'before definitions';
1042     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
1043     $state = 'before members';
1044     $next_state = 'before interface member';
1045     } else {
1046     $state = 'before members';
1047     $next_state = 'before exception member';
1048     }
1049 wakaba 1.1 } else {
1050 wakaba 1.5 $onerror->(type => 'before semicolon', level => 'm',
1051     token => $token);
1052     # reconsume
1053     $state = 'ignore';
1054     $nest_level = 0;
1055     }
1056     } elsif ($state eq 'before block semicolon') {
1057     if ($token->{type} eq ';') {
1058     $current[-2]->append_child ($current[-1]);
1059 wakaba 1.1 pop @current;
1060 wakaba 1.5 $token = $get_next_token->();
1061     if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
1062     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1063     $state = 'before definitions';
1064     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
1065     $state = 'before members';
1066     $next_state = 'before interface member';
1067     } else {
1068     $state = 'before members';
1069     $next_state = 'before exception member';
1070     }
1071     } else {
1072 wakaba 1.1 $onerror->(type => 'before semicolon', level => 'm',
1073     token => $token);
1074 wakaba 1.5 pop @current; # avoid appended by 'ignore'
1075 wakaba 1.1 # reconsume
1076     $state = 'ignore';
1077     $nest_level = 0;
1078     }
1079     } elsif ($state eq 'ignore') {
1080 wakaba 1.5 if ($nest_level == 0 and $token->{type} eq ';') {
1081     while (@current > 1) {
1082     if ($current[-1]->isa ('Whatpm::WebIDL::Interface') or
1083     $current[-1]->isa ('Whatpm::WebIDL::Exception') or
1084     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1085     last;
1086     }
1087     pop @current;
1088     }
1089    
1090 wakaba 1.1 $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 } elsif ($token->{type} eq '{') {
1102     $nest_level++;
1103     $token = $get_next_token->();
1104     # stay in the state
1105     } elsif ($nest_level and $token->{type} eq '}') {
1106     $nest_level--;
1107     $token = $get_next_token->();
1108     # stay in the state
1109     } elsif ($token->{type} eq 'eof') {
1110 wakaba 1.5 while (@current > 1) {
1111     if ($current[-1]->isa ('Whatpm::WebIDL::Interface') or
1112     $current[-1]->isa ('Whatpm::WebIDL::Exception') or
1113     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
1114     last;
1115     }
1116     pop @current;
1117     }
1118    
1119 wakaba 1.1 last;
1120     } else {
1121     # ignore the token
1122     $token = $get_next_token->();
1123     # stay in the state
1124     }
1125     } else {
1126     die "parse_char_string: unkown state: $state";
1127     }
1128     }
1129    
1130     if (@current > 1) {
1131 wakaba 1.5 $onerror->(type => 'premature end of file', level => $self->{must_level});
1132     while (@current > 1) {
1133     $current[-2]->append_child ($current[-1]);
1134     pop @current;
1135     }
1136 wakaba 1.1 }
1137    
1138     $get_type = undef; # unlink loop
1139    
1140     return $defs;
1141     } # parse_char_string
1142    
1143     package Whatpm::WebIDL::Definitions;
1144    
1145     sub new ($) {
1146     return bless {child_nodes => []}, $_[0];
1147     } # new
1148    
1149     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1150    
1151     sub idl_text ($) {
1152     return join "\x0A", map {$_->idl_text} @{$_[0]->{child_nodes}};
1153     } # idl_text
1154    
1155     package Whatpm::WebIDL::Definition;
1156    
1157     sub new ($$) {
1158     return bless {child_nodes => [], node_name => ''.$_[1]}, $_[0];
1159     } # new
1160    
1161     sub append_child ($$) {
1162     my $self = shift;
1163     my $child = shift;
1164    
1165     ## TODO: child type
1166     ## TODO: parent check
1167    
1168     push @{$self->{child_nodes}}, $child;
1169    
1170     return $child;
1171     } # append_child
1172    
1173     sub node_name ($) {
1174     return $_[0]->{node_name};
1175     } # node_name
1176    
1177 wakaba 1.4 sub set_extended_attribute_node ($$) {
1178     my $self = shift;
1179     ## TODO: check
1180     push @{$self->{xattrs} ||= []}, shift;
1181     } # set_extended_attribute_node
1182    
1183 wakaba 1.1 sub idl_text ($) {
1184     return '[[ERROR: ' . (ref $_[0]) . '->idl_text]]';
1185     } # idl_text
1186    
1187 wakaba 1.4 sub _xattrs_text ($) {
1188     my $self = shift;
1189    
1190     unless ($self->{xattrs} and
1191     @{$self->{xattrs}}) {
1192     return '';
1193     }
1194    
1195     my $r = '[';
1196     $r .= join ', ', map {$_->idl_text} @{$self->{xattrs}};
1197     $r .= ']';
1198     return $r;
1199     } # _xattrs_text
1200    
1201 wakaba 1.1 sub type ($;$) {
1202     if (@_ > 1) {
1203     if (defined $_[1]) {
1204     $_[0]->{type} = $_[1];
1205     } else {
1206     $_[0]->{type} = ['::any::'];
1207     }
1208     }
1209     return $_[0]->{type};
1210     } # type
1211    
1212 wakaba 1.6 {
1213     my $serialize_type;
1214     my $serialize_type_depth = 0;
1215     $serialize_type = sub ($) {
1216     my $type = shift;
1217     if ($type->[0] eq '::sequence::') {
1218     if ($serialize_type_depth++ == 1024) {
1219     return 'sequence<<<sequence too deep>>>';
1220     } else {
1221     return 'sequence<' . $serialize_type->($type->[1]) . '>';
1222     }
1223     } else {
1224     return join '::', map {
1225     /^::([^:]+)::$/ ? $1 : $_ ## TODO: escape
1226     } @{$type};
1227     }
1228     }; # $serialize_type
1229    
1230 wakaba 1.1 sub type_text ($) {
1231     my $type = $_[0]->{type};
1232     return undef unless defined $type;
1233 wakaba 1.6
1234     return $serialize_type->($type);
1235 wakaba 1.1 } # type_text
1236 wakaba 1.6
1237     }
1238 wakaba 1.1
1239     package Whatpm::WebIDL::Module;
1240     push our @ISA, 'Whatpm::WebIDL::Definition';
1241    
1242     sub idl_text ($) {
1243 wakaba 1.4 my $self = shift;
1244     my $r = $self->_xattrs_text;
1245     $r .= ' ' if length $r;
1246     $r .= 'module ' . $self->node_name . "{\x0A\x0A"; ## TODO: escape
1247     for (@{$self->{child_nodes}}) {
1248 wakaba 1.1 $r .= $_->idl_text;
1249     }
1250     $r .= "\x0A};\x0A";
1251     return $r;
1252     } # idl_text
1253    
1254     package Whatpm::WebIDL::Interface;
1255     push our @ISA, 'Whatpm::WebIDL::Definition';
1256    
1257     sub new ($$) {
1258     my $self = shift->SUPER::new (@_);
1259     $self->{inheritances} = [];
1260     return $self;
1261     } # new
1262    
1263     sub append_inheritance ($$) {
1264     my $self = shift;
1265     my $scoped_name = shift;
1266     push @{$self->{inheritances}}, $scoped_name;
1267     } # append_inheritance
1268    
1269     sub idl_text ($) {
1270 wakaba 1.3 my $self = shift;
1271 wakaba 1.4 my $r = $self->_xattrs_text;
1272     $r .= ' ' if length $r;
1273     $r = 'interface ' . $self->node_name;
1274 wakaba 1.3 if (@{$self->{inheritances}}) {
1275     $r .= ' : '; ## TODO: ...
1276     $r .= join ', ', map {join '::', @{$_}} @{$self->{inheritances}};
1277     }
1278     $r .= " {\x0A"; ## TODO: escape
1279     for (@{$self->{child_nodes}}) {
1280 wakaba 1.1 $r .= ' ' . $_->idl_text;
1281     }
1282     $r .= "};\x0A";
1283     return $r;
1284     } # idl_text
1285    
1286     package Whatpm::WebIDL::Exception;
1287     push our @ISA, 'Whatpm::WebIDL::Definition';
1288    
1289 wakaba 1.3 sub idl_text ($) {
1290 wakaba 1.4 my $self = shift;
1291     my $r = $self->_xattrs_text;
1292     $r .= ' ' if length $r;
1293 wakaba 1.7 $r = 'exception ' . $self->node_name . " {\x0A"; ## TODO: escape
1294 wakaba 1.4 for (@{$self->{child_nodes}}) {
1295 wakaba 1.3 $r .= ' ' . $_->idl_text;
1296     }
1297     $r .= "};\x0A";
1298     return $r;
1299     } # idl_text
1300    
1301 wakaba 1.1 package Whatpm::WebIDL::Typedef;
1302     push our @ISA, 'Whatpm::WebIDL::Definition';
1303    
1304     sub new ($$) {
1305     my $self = shift->SUPER::new (@_);
1306     $self->{type} = ['::any::'];
1307     return $self;
1308     } # new
1309    
1310     sub idl_text ($) {
1311 wakaba 1.4 my $self = shift;
1312     my $r = $self->_xattrs_text;
1313     $r .= ' ' if length $r;
1314 wakaba 1.1 ## TODO: escape
1315 wakaba 1.4 $r .= 'typedef ' . $self->type_text . ' ' . $self->node_name . ";\x0A";
1316     return $r;
1317 wakaba 1.1 } # idl_text
1318    
1319     package Whatpm::WebIDL::Valuetype;
1320     push our @ISA, 'Whatpm::WebIDL::Definition';
1321    
1322     sub new ($$) {
1323     my $self = shift->SUPER::new (@_);
1324     $self->{type} = ['::boolean::'];
1325     return $self;
1326     } # new
1327    
1328     sub idl_text ($) {
1329 wakaba 1.4 my $self = shift;
1330     my $r = $self->_xattrs_text;
1331     $r .= ' ' if length $r;
1332 wakaba 1.1 ## TODO: escape
1333 wakaba 1.4 $r .= 'valuetype ' . $self->node_name . ' ' . $self->type_text . ";\x0A";
1334     return $r;
1335 wakaba 1.1 } # idl_text
1336    
1337     package Whatpm::WebIDL::InterfaceMember;
1338    
1339     sub new ($$) {
1340     return bless {node_name => ''.$_[1]}, $_[0];
1341     } # new
1342    
1343 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1344    
1345 wakaba 1.1 *idl_text = \&Whatpm::WebIDL::Definition::idl_text;
1346    
1347     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1348    
1349 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1350    
1351 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
1352    
1353     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1354    
1355     package Whatpm::WebIDL::Const;
1356     push our @ISA, 'Whatpm::WebIDL::Definition', 'Whatpm::WebIDL::InterfaceMember';
1357    
1358     sub new ($$) {
1359     my $self = shift->SUPER::new (@_); # Definition->new should be called
1360     $self->{type} = ['::boolean::'];
1361     $self->{value} = ['FALSE'];
1362     return $self;
1363     } # new
1364    
1365     sub value ($;$) {
1366     if (@_ > 1) {
1367     $_[0]->{value} = $_[1];
1368     }
1369    
1370     return $_[0]->{value};
1371     } # value
1372    
1373     sub value_text ($) {
1374     my $value = $_[0]->{value};
1375    
1376     if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
1377     return $value->[0];
1378     } elsif ($value->[0] eq 'integer' or $value->[0] eq 'float') {
1379     ## TODO: format
1380     return $value->[1];
1381     } else {
1382     return undef;
1383     }
1384     } # value_text
1385    
1386     sub idl_text ($) {
1387 wakaba 1.4 my $self = shift;
1388     my $r = $self->_xattrs_text;
1389     $r .= ' ' if length $r;
1390     $r .= 'const ' . $self->type_text . ' ' . $self->node_name . ' = ' . $self->value_text . ";\x0A"; ## TODO: escape
1391     return $r;
1392 wakaba 1.1 } # idl_text
1393    
1394     package Whatpm::WebIDL::Attribute;
1395     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1396    
1397     sub new ($$) {
1398     my $self = shift->SUPER::new (@_);
1399     $self->{type} = ['::any::'];
1400 wakaba 1.2 $self->{getraises} = [];
1401     $self->{setraises} = [];
1402 wakaba 1.1 return $self;
1403     } # new
1404    
1405 wakaba 1.2 sub append_getraises ($$) {
1406     ## TODO: error check, etc.
1407     push @{$_[0]->{getraises}}, $_[1];
1408     } # append_getraises
1409    
1410     sub append_setraises ($$) {
1411     ## TODO: error check, etc.
1412     push @{$_[0]->{setraises}}, $_[1];
1413     } # append_setraises
1414    
1415 wakaba 1.1 sub readonly ($;$) {
1416     if (@_ > 1) {
1417     $_[0]->{readonly} = $_[1];
1418     }
1419    
1420     return $_[0]->{readonly};
1421     } # readonly
1422    
1423     sub idl_text ($) {
1424 wakaba 1.2 my $self = shift;
1425 wakaba 1.4 my $r = $self->_xattrs_text;
1426     $r .= ' ' if length $r;
1427     $r .= ($self->readonly ? 'readonly ' : '') . 'attribute ' . $self->type_text . ' ' . $self->node_name;
1428 wakaba 1.1 ## TODO: escape
1429 wakaba 1.2 if (@{$self->{getraises}}) {
1430     $r .= ' getraises (';
1431     ## todo: ...
1432     $r .= join ', ', map {join '::', @{$_}} @{$self->{getraises}};
1433     $r .= ')';
1434     }
1435     if (@{$self->{setraises}}) {
1436     $r .= ' setraises (';
1437     ## todo: ...
1438     $r .= join ', ', map {join '::', @{$_}} @{$self->{setraises}};
1439     $r .= ')';
1440     }
1441     $r .= ";\x0A";
1442     return $r;
1443 wakaba 1.1 } # idl_text
1444    
1445     package Whatpm::WebIDL::Operation;
1446     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1447    
1448     sub new ($$) {
1449     my $self = shift->SUPER::new (@_);
1450     $self->{type} = ['::any::'];
1451     $self->{child_nodes} = [];
1452 wakaba 1.2 $self->{raises} = [];
1453 wakaba 1.1 return $self;
1454     } # new
1455    
1456     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1457    
1458 wakaba 1.2 sub append_raises ($$) {
1459     ## TODO: error check, etc.
1460     push @{$_[0]->{raises}}, $_[1];
1461     } # append_raises
1462    
1463 wakaba 1.1 sub idl_text ($) {
1464 wakaba 1.2 my $self = shift;
1465 wakaba 1.4 my $r = $self->_xattrs_text;
1466     $r .= ' ' if length $r;
1467     $r .= $self->type_text . ' ' . $self->node_name . ' ('; ## TODO: escape
1468 wakaba 1.2 $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
1469     $r .= ')';
1470     if (@{$self->{raises}}) {
1471     $r .= ' raises (';
1472     ## todo: ...
1473     $r .= join ', ', map {join '::', @{$_}} @{$self->{raises}};
1474     $r .= ')';
1475     }
1476 wakaba 1.1 $r .= ";\x0A";
1477     return $r;
1478     } # idl_text
1479    
1480     package Whatpm::WebIDL::Argument;
1481    
1482     sub new ($$) {
1483     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1484     } # new
1485    
1486     sub idl_text ($) {
1487 wakaba 1.4 my $self = shift;
1488     my $r = $self->_xattrs_text;
1489     $r .= ' ' if length $r;
1490     $r .= 'in ' . $self->type_text . ' ' . $self->node_name; ## TODO: escape
1491     return $r;
1492 wakaba 1.3 } # idl_text
1493    
1494 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1495    
1496 wakaba 1.3 *node_name = \&Whatpm::WebIDL::Definition::node_name;
1497    
1498 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1499    
1500 wakaba 1.3 *type = \&Whatpm::WebIDL::Definition::type;
1501    
1502     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1503    
1504     package Whatpm::WebIDL::ExceptionMember;
1505    
1506     sub new ($$) {
1507     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1508     } # new
1509    
1510     sub idl_text ($) {
1511 wakaba 1.4 my $self = shift;
1512     my $r = $self->_xattrs_text;
1513     $r .= ' ' if length $r;
1514     $r .= $self->type_text . ' ' . $self->node_name . ";\x0A"; ## TODO: escape
1515     return $r;
1516 wakaba 1.1 } # idl_text
1517    
1518 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1519    
1520 wakaba 1.1 *node_name = \&Whatpm::WebIDL::Definition::node_name;
1521    
1522 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1523    
1524 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
1525    
1526     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1527 wakaba 1.4
1528     package Whatpm::WebIDL::ExtendedAttribute;
1529    
1530     sub new ($$) {
1531     return bless {child_nodes => [], node_name => ''.$_[1]};
1532     } # new
1533    
1534     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1535    
1536     sub idl_text ($) {
1537     my $self = shift;
1538     my $r = $self->node_name; ## TODO:] esceape
1539     if (defined $self->{value}) {
1540     $r .= '=' . $self->{value}; ## TODO: escape
1541     }
1542     if (@{$self->{child_nodes}}) {
1543     $r .= ' (';
1544     $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
1545     $r .= ')';
1546     }
1547     return $r;
1548     } # idl_text
1549    
1550     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1551    
1552     sub value ($;$) {
1553     if (@_ > 1) {
1554     if (defined $_[1]) {
1555     $_[0]->{value} = ''.$_[1];
1556     } else {
1557     delete $_[0]->{value};
1558     }
1559     }
1560    
1561     return $_[0]->{value};
1562     } # value
1563 wakaba 1.1
1564     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24