/[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.5 - (hide annotations) (download)
Sat Jul 19 13:11:30 2008 UTC (16 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.4: +68 -58 lines
++ whatpm/Whatpm/ChangeLog	19 Jul 2008 13:11:27 -0000
	* WebIDL.pm: Revise forward-compatible parsing so that
	it now can handle broken extended attributes and as such.

2008-07-19  Wakaba  <wakaba@suika.fam.cx>

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     sub type_text ($) {
1213     my $type = $_[0]->{type};
1214     return undef unless defined $type;
1215    
1216     if ($type->[0] eq '::sequence::') {
1217     return 'sequence<' . (join '::', @{$type->[1]}) . '>'; ## TODO: escape, nested
1218     } else {
1219     return join '::', @$type; ## TODO: escape
1220     }
1221     } # type_text
1222    
1223     package Whatpm::WebIDL::Module;
1224     push our @ISA, 'Whatpm::WebIDL::Definition';
1225    
1226     sub idl_text ($) {
1227 wakaba 1.4 my $self = shift;
1228     my $r = $self->_xattrs_text;
1229     $r .= ' ' if length $r;
1230     $r .= 'module ' . $self->node_name . "{\x0A\x0A"; ## TODO: escape
1231     for (@{$self->{child_nodes}}) {
1232 wakaba 1.1 $r .= $_->idl_text;
1233     }
1234     $r .= "\x0A};\x0A";
1235     return $r;
1236     } # idl_text
1237    
1238     package Whatpm::WebIDL::Interface;
1239     push our @ISA, 'Whatpm::WebIDL::Definition';
1240    
1241     sub new ($$) {
1242     my $self = shift->SUPER::new (@_);
1243     $self->{inheritances} = [];
1244     return $self;
1245     } # new
1246    
1247     sub append_inheritance ($$) {
1248     my $self = shift;
1249     my $scoped_name = shift;
1250     push @{$self->{inheritances}}, $scoped_name;
1251     } # append_inheritance
1252    
1253     sub idl_text ($) {
1254 wakaba 1.3 my $self = shift;
1255 wakaba 1.4 my $r = $self->_xattrs_text;
1256     $r .= ' ' if length $r;
1257     $r = 'interface ' . $self->node_name;
1258 wakaba 1.3 if (@{$self->{inheritances}}) {
1259     $r .= ' : '; ## TODO: ...
1260     $r .= join ', ', map {join '::', @{$_}} @{$self->{inheritances}};
1261     }
1262     $r .= " {\x0A"; ## TODO: escape
1263     for (@{$self->{child_nodes}}) {
1264 wakaba 1.1 $r .= ' ' . $_->idl_text;
1265     }
1266     $r .= "};\x0A";
1267     return $r;
1268     } # idl_text
1269    
1270     package Whatpm::WebIDL::Exception;
1271     push our @ISA, 'Whatpm::WebIDL::Definition';
1272    
1273 wakaba 1.3 sub idl_text ($) {
1274 wakaba 1.4 my $self = shift;
1275     my $r = $self->_xattrs_text;
1276     $r .= ' ' if length $r;
1277     $r = 'exception ' . $self->node_name . "{\x0A"; ## TODO: escape
1278     for (@{$self->{child_nodes}}) {
1279 wakaba 1.3 $r .= ' ' . $_->idl_text;
1280     }
1281     $r .= "};\x0A";
1282     return $r;
1283     } # idl_text
1284    
1285 wakaba 1.1 package Whatpm::WebIDL::Typedef;
1286     push our @ISA, 'Whatpm::WebIDL::Definition';
1287    
1288     sub new ($$) {
1289     my $self = shift->SUPER::new (@_);
1290     $self->{type} = ['::any::'];
1291     return $self;
1292     } # new
1293    
1294     sub idl_text ($) {
1295 wakaba 1.4 my $self = shift;
1296     my $r = $self->_xattrs_text;
1297     $r .= ' ' if length $r;
1298 wakaba 1.1 ## TODO: escape
1299 wakaba 1.4 $r .= 'typedef ' . $self->type_text . ' ' . $self->node_name . ";\x0A";
1300     return $r;
1301 wakaba 1.1 } # idl_text
1302    
1303     package Whatpm::WebIDL::Valuetype;
1304     push our @ISA, 'Whatpm::WebIDL::Definition';
1305    
1306     sub new ($$) {
1307     my $self = shift->SUPER::new (@_);
1308     $self->{type} = ['::boolean::'];
1309     return $self;
1310     } # new
1311    
1312     sub idl_text ($) {
1313 wakaba 1.4 my $self = shift;
1314     my $r = $self->_xattrs_text;
1315     $r .= ' ' if length $r;
1316 wakaba 1.1 ## TODO: escape
1317 wakaba 1.4 $r .= 'valuetype ' . $self->node_name . ' ' . $self->type_text . ";\x0A";
1318     return $r;
1319 wakaba 1.1 } # idl_text
1320    
1321     package Whatpm::WebIDL::InterfaceMember;
1322    
1323     sub new ($$) {
1324     return bless {node_name => ''.$_[1]}, $_[0];
1325     } # new
1326    
1327 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1328    
1329 wakaba 1.1 *idl_text = \&Whatpm::WebIDL::Definition::idl_text;
1330    
1331     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1332    
1333 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1334    
1335 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
1336    
1337     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1338    
1339     package Whatpm::WebIDL::Const;
1340     push our @ISA, 'Whatpm::WebIDL::Definition', 'Whatpm::WebIDL::InterfaceMember';
1341    
1342     sub new ($$) {
1343     my $self = shift->SUPER::new (@_); # Definition->new should be called
1344     $self->{type} = ['::boolean::'];
1345     $self->{value} = ['FALSE'];
1346     return $self;
1347     } # new
1348    
1349     sub value ($;$) {
1350     if (@_ > 1) {
1351     $_[0]->{value} = $_[1];
1352     }
1353    
1354     return $_[0]->{value};
1355     } # value
1356    
1357     sub value_text ($) {
1358     my $value = $_[0]->{value};
1359    
1360     if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
1361     return $value->[0];
1362     } elsif ($value->[0] eq 'integer' or $value->[0] eq 'float') {
1363     ## TODO: format
1364     return $value->[1];
1365     } else {
1366     return undef;
1367     }
1368     } # value_text
1369    
1370     sub idl_text ($) {
1371 wakaba 1.4 my $self = shift;
1372     my $r = $self->_xattrs_text;
1373     $r .= ' ' if length $r;
1374     $r .= 'const ' . $self->type_text . ' ' . $self->node_name . ' = ' . $self->value_text . ";\x0A"; ## TODO: escape
1375     return $r;
1376 wakaba 1.1 } # idl_text
1377    
1378     package Whatpm::WebIDL::Attribute;
1379     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1380    
1381     sub new ($$) {
1382     my $self = shift->SUPER::new (@_);
1383     $self->{type} = ['::any::'];
1384 wakaba 1.2 $self->{getraises} = [];
1385     $self->{setraises} = [];
1386 wakaba 1.1 return $self;
1387     } # new
1388    
1389 wakaba 1.2 sub append_getraises ($$) {
1390     ## TODO: error check, etc.
1391     push @{$_[0]->{getraises}}, $_[1];
1392     } # append_getraises
1393    
1394     sub append_setraises ($$) {
1395     ## TODO: error check, etc.
1396     push @{$_[0]->{setraises}}, $_[1];
1397     } # append_setraises
1398    
1399 wakaba 1.1 sub readonly ($;$) {
1400     if (@_ > 1) {
1401     $_[0]->{readonly} = $_[1];
1402     }
1403    
1404     return $_[0]->{readonly};
1405     } # readonly
1406    
1407     sub idl_text ($) {
1408 wakaba 1.2 my $self = shift;
1409 wakaba 1.4 my $r = $self->_xattrs_text;
1410     $r .= ' ' if length $r;
1411     $r .= ($self->readonly ? 'readonly ' : '') . 'attribute ' . $self->type_text . ' ' . $self->node_name;
1412 wakaba 1.1 ## TODO: escape
1413 wakaba 1.2 if (@{$self->{getraises}}) {
1414     $r .= ' getraises (';
1415     ## todo: ...
1416     $r .= join ', ', map {join '::', @{$_}} @{$self->{getraises}};
1417     $r .= ')';
1418     }
1419     if (@{$self->{setraises}}) {
1420     $r .= ' setraises (';
1421     ## todo: ...
1422     $r .= join ', ', map {join '::', @{$_}} @{$self->{setraises}};
1423     $r .= ')';
1424     }
1425     $r .= ";\x0A";
1426     return $r;
1427 wakaba 1.1 } # idl_text
1428    
1429     package Whatpm::WebIDL::Operation;
1430     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1431    
1432     sub new ($$) {
1433     my $self = shift->SUPER::new (@_);
1434     $self->{type} = ['::any::'];
1435     $self->{child_nodes} = [];
1436 wakaba 1.2 $self->{raises} = [];
1437 wakaba 1.1 return $self;
1438     } # new
1439    
1440     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1441    
1442 wakaba 1.2 sub append_raises ($$) {
1443     ## TODO: error check, etc.
1444     push @{$_[0]->{raises}}, $_[1];
1445     } # append_raises
1446    
1447 wakaba 1.1 sub idl_text ($) {
1448 wakaba 1.2 my $self = shift;
1449 wakaba 1.4 my $r = $self->_xattrs_text;
1450     $r .= ' ' if length $r;
1451     $r .= $self->type_text . ' ' . $self->node_name . ' ('; ## TODO: escape
1452 wakaba 1.2 $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
1453     $r .= ')';
1454     if (@{$self->{raises}}) {
1455     $r .= ' raises (';
1456     ## todo: ...
1457     $r .= join ', ', map {join '::', @{$_}} @{$self->{raises}};
1458     $r .= ')';
1459     }
1460 wakaba 1.1 $r .= ";\x0A";
1461     return $r;
1462     } # idl_text
1463    
1464     package Whatpm::WebIDL::Argument;
1465    
1466     sub new ($$) {
1467     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1468     } # new
1469    
1470     sub idl_text ($) {
1471 wakaba 1.4 my $self = shift;
1472     my $r = $self->_xattrs_text;
1473     $r .= ' ' if length $r;
1474     $r .= 'in ' . $self->type_text . ' ' . $self->node_name; ## TODO: escape
1475     return $r;
1476 wakaba 1.3 } # idl_text
1477    
1478 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1479    
1480 wakaba 1.3 *node_name = \&Whatpm::WebIDL::Definition::node_name;
1481    
1482 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1483    
1484 wakaba 1.3 *type = \&Whatpm::WebIDL::Definition::type;
1485    
1486     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1487    
1488     package Whatpm::WebIDL::ExceptionMember;
1489    
1490     sub new ($$) {
1491     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1492     } # new
1493    
1494     sub idl_text ($) {
1495 wakaba 1.4 my $self = shift;
1496     my $r = $self->_xattrs_text;
1497     $r .= ' ' if length $r;
1498     $r .= $self->type_text . ' ' . $self->node_name . ";\x0A"; ## TODO: escape
1499     return $r;
1500 wakaba 1.1 } # idl_text
1501    
1502 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1503    
1504 wakaba 1.1 *node_name = \&Whatpm::WebIDL::Definition::node_name;
1505    
1506 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1507    
1508 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
1509    
1510     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1511 wakaba 1.4
1512     package Whatpm::WebIDL::ExtendedAttribute;
1513    
1514     sub new ($$) {
1515     return bless {child_nodes => [], node_name => ''.$_[1]};
1516     } # new
1517    
1518     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1519    
1520     sub idl_text ($) {
1521     my $self = shift;
1522     my $r = $self->node_name; ## TODO:] esceape
1523     if (defined $self->{value}) {
1524     $r .= '=' . $self->{value}; ## TODO: escape
1525     }
1526     if (@{$self->{child_nodes}}) {
1527     $r .= ' (';
1528     $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
1529     $r .= ')';
1530     }
1531     return $r;
1532     } # idl_text
1533    
1534     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1535    
1536     sub value ($;$) {
1537     if (@_ > 1) {
1538     if (defined $_[1]) {
1539     $_[0]->{value} = ''.$_[1];
1540     } else {
1541     delete $_[0]->{value};
1542     }
1543     }
1544    
1545     return $_[0]->{value};
1546     } # value
1547 wakaba 1.1
1548     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24