/[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.4 - (hide annotations) (download)
Sat Jul 19 11:48:23 2008 UTC (16 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.3: +181 -35 lines
++ whatpm/Whatpm/ChangeLog	19 Jul 2008 11:48:19 -0000
	* WebIDL.pm: Real support for extended attributes.
	Support for extended attributes with arguments.

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     $state = 'before semicolon';
254     $next_state = 'before definitions';
255     } elsif ($token->{type} eq 'eof') {
256     last;
257     } else {
258     $onerror->(type => 'before definitions', level => 'm',
259     token => $token);
260     # reconsume
261     $state = 'ignore';
262     $nest_level = 0;
263     $next_state = 'before definitions';
264     }
265     } elsif ($state eq 'before xattr') {
266    
267     ## TODO: methodType methodName ([broken xattr] ...); is not well
268     ## handled on forward-compatible parsing (i.e. pop @current).
269    
270     if ($token->{type} eq 'identifier') {
271     ## TODO: _escape
272     ## ISSUE: Duplicate attributes
273     ## ISSUE: Unkown attributes
274 wakaba 1.4 push @current, Whatpm::WebIDL::ExtendedAttribute->new ($token->{value});
275     push @$xattrs, $current[-1];
276 wakaba 1.1 $token = $get_next_token->();
277     $state = 'after xattr';
278     } else {
279     $onerror->(type => 'before xattr', level => 'm', token => $token);
280     # reconsume
281     $state = 'ignore';
282     $nest_level = 0;
283 wakaba 1.4 $next_state = 'before definitions'; ## TODO:
284 wakaba 1.1 }
285     } elsif ($state eq 'after xattr') {
286     if ($token->{type} eq '=') {
287     $token = $get_next_token->();
288     $state = 'before xattrarg';
289 wakaba 1.4 } elsif ($token->{type} eq '(') {
290     $token = $get_next_token->();
291     if ($token->{type} eq ')') {
292     $token = $get_next_token->();
293     push @$prev_xattrs, $xattrs;
294     $state = 'after xattrarg';
295     } else {
296     push @$prev_xattrs, $xattrs;
297     # reconsume
298     $state = 'before argument';
299     }
300 wakaba 1.1 } else {
301 wakaba 1.4 push @$prev_xattrs, $xattrs;
302 wakaba 1.1 # reconsume
303     $state = 'after xattrarg';
304     }
305     } elsif ($state eq 'before xattrarg') {
306     if ($token->{type} eq 'identifier') {
307     ## TODO: escape
308 wakaba 1.4 $current[-1]->value ($token->{value});
309 wakaba 1.1 $token = $get_next_token->();
310 wakaba 1.4 if ($token->{type} eq '(') {
311     $token = $get_next_token->();
312     if ($token->{type} eq ')') {
313     push @$prev_xattrs, $xattrs;
314     $token = $get_next_token->();
315     $state = 'after xattrarg';
316     } else {
317     push @$prev_xattrs, $xattrs;
318     # reconsume
319     $state = 'before argument';
320     }
321     } else {
322     push @$prev_xattrs, $xattrs;
323     # reconsume
324     $state = 'after xattrarg';
325     }
326 wakaba 1.1 } else {
327     $onerror->(type => 'after xattrarg', level => 'm', token => $token);
328     # reconsume
329     $state = 'ignore';
330     $nest_level = 0;
331     $next_state = 'before definitions';
332     }
333     } elsif ($state eq 'after xattrarg') {
334 wakaba 1.4 pop @current; # xattr
335     $xattrs = pop @$prev_xattrs;
336 wakaba 1.1 if ($token->{type} eq ',') {
337     $token = $get_next_token->();
338     $state = 'before xattr';
339     } elsif ($token->{type} eq ']') {
340     $token = $get_next_token->();
341 wakaba 1.4 if ($current[-1]->isa ('Whatpm::WebIDL::Definitions') or
342     $current[-1]->isa ('Whatpm::WebIDL::Module')) {
343     $state = 'before definitions';
344     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Interface')) {
345     $state = 'before interface member';
346     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Exception')) {
347     $state = 'before exception member';
348     } elsif ($current[-1]->isa ('Whatpm::WebIDL::Operation') or
349     $current[-1]->isa ('Whatpm::WebIDL::ExtendedAttribute')) {
350     $state = 'before argument in';
351     } else {
352     die "$0: Unknown xattr context: " . ref $current[-1];
353     }
354 wakaba 1.1 } else {
355     $onerror->(type => 'after xattr', level => 'm', token => $token);
356     # reconsume
357     $state = 'ignore';
358     $nest_level = 0;
359 wakaba 1.4 $next_state = 'before definitions'; ## TODO:
360 wakaba 1.1 }
361     } elsif ($state eq 'before def') {
362     if ($token->{type} eq 'module') {
363     $token = $get_next_token->();
364     if ($token->{type} eq 'identifier') {
365     ## TODO: escape
366     push @current, Whatpm::WebIDL::Module->new ($token->{value});
367 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
368 wakaba 1.1 $token = $get_next_token->();
369     $state = 'before module block';
370     next;
371     } else {
372     $onerror->(type => 'module identifier',
373     level => $self->{must_level});
374     #
375     }
376     } elsif ($token->{type} eq 'interface') {
377     $token = $get_next_token->();
378     if ($token->{type} eq 'identifier') {
379     ## TODO: escape
380     push @current, Whatpm::WebIDL::Interface->new ($token->{value});
381 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
382 wakaba 1.1 $token = $get_next_token->();
383     $state = 'before interface inheritance';
384     next;
385     } else {
386     $onerror->(type => 'interface identifier',
387     level => $self->{must_level});
388     #
389     }
390     } elsif ($token->{type} eq 'exception') {
391     $token = $get_next_token->();
392     if ($token->{type} eq 'identifier') {
393     ## TODO: escape
394     push @current, Whatpm::WebIDL::Exception->new ($token->{value});
395 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
396 wakaba 1.1 $token = $get_next_token->();
397     $state = 'before exception block';
398     next;
399     } else {
400     $onerror->(type => 'exception identifier',
401     level => $self->{must_level});
402     #
403     }
404     } elsif ($token->{type} eq 'typedef') {
405     $token = $get_next_token->();
406     $state = 'before typedef type';
407     next;
408     } elsif ($token->{type} eq 'valuetype') {
409     $token = $get_next_token->();
410     if ($token->{type} eq 'identifier') {
411     ## TODO: escape
412     push @current, Whatpm::WebIDL::Valuetype->new ($token->{value});
413 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
414 wakaba 1.1 $token = $get_next_token->();
415     $state = 'before boxed type';
416     next;
417     } elsif ($token->{type} eq 'DOMString') {
418     push @current, Whatpm::WebIDL::Valuetype->new ('::DOMString::');
419 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
420 wakaba 1.1 $token = $get_next_token->();
421     if ($token->{type} eq 'sequence') {
422     $token = $get_next_token->();
423     if ($token->{type} eq '<') {
424     $token = $get_next_token->();
425     if ($token->{type} eq 'unsigned') {
426     $token = $get_next_token->();
427     if ($token->{type} eq 'short') {
428     $token = $get_next_token->();
429     if ($token->{type} eq '>') {
430     $current[-1]->type
431     (['::sequence::', ['::unsigned short::']]);
432     $token = $get_next_token->();
433     $state = 'before semicolon';
434     $next_state = 'before definitions';
435     next;
436     } else {
437     $onerror->(type => 'valuetype DOMString sequence lt unsigned short gt',
438     level => $self->{must_level});
439     #
440     }
441     } else {
442     $onerror->(type => 'valuetype DOMString sequence lt unsigned short',
443     level => $self->{must_level});
444     #
445     }
446     } else {
447     $onerror->(type => 'valuetype DOMString sequence lt unsigned',
448     level => $self->{must_level});
449     #
450     }
451     } else {
452     $onerror->(type => 'valuetype DOMString sequence lt',
453     level => $self->{must_level});
454     #
455     }
456     } else {
457     $onerror->(type => 'valuetype DOMString sequence',
458     level => $self->{must_level});
459     #
460     }
461     shift @current; # valuetype
462     #
463     } else {
464     $onerror->(type => 'valuetype identifier',
465     level => $self->{must_level});
466     #
467     }
468     } elsif ($token->{type} eq 'const') {
469     $token = $get_next_token->();
470     $state = 'before const type';
471     $next_state = 'before definitions';
472     next;
473     } elsif ($token->{type} eq 'eof') {
474     ## NOTE: Any extended attributes are ignored.
475     $onerror->(type => 'before def:eof', level => 'm', token => $token);
476     last;
477     } else {
478     $onerror->(type => 'before definition', level => 'm',
479     token => $token);
480     # reconsume
481     #
482     }
483     $state = 'ignore';
484     $nest_level = 0;
485     $next_state = 'before definitions';
486     } elsif ($state eq 'before module block') {
487     if ($token->{type} eq '{') {
488     $token = $get_next_token->();
489     $state = 'before definitions';
490     } else {
491     $onerror->(type => 'before module block', level => 'm',
492     token => $token);
493     pop @current; # module
494     # reconsume
495     $state = 'ignore';
496     $nest_level = 0;
497     $next_state = 'before definitions';
498     }
499     } elsif ($state eq 'before interface inheritance') {
500     if ($token->{type} eq ':') {
501     $token = $get_next_token->();
502     $state = 'before parent interface name';
503     } else {
504     # reconsume
505     $state = 'before interface block';
506     }
507     } elsif ($state eq 'before parent interface name') {
508     my $name = $get_scoped_name->();
509     if (defined $name) {
510     $current[-1]->append_inheritance ($name);
511    
512     if ($token->{type} eq ',') {
513     $token = $get_next_token->();
514     # stay in the state
515     } else {
516     # reconsume
517     $state = 'before interface block';
518     }
519     } else {
520     $onerror->(type => 'scoped name', level => $self->{must_level});
521     pop @current; # interface
522     # reconsume
523     $state = 'ignore';
524     $nest_level = 0;
525     $next_state = 'before definitions';
526     }
527 wakaba 1.2 } elsif ($state eq 'before exception name') {
528     my $name = $get_scoped_name->();
529     if (defined $name) {
530     my $method = $next_state eq '*raises' ? 'append_raises' :
531     $next_state eq '*getraises' ? 'append_getraises' :
532     'append_setraises';
533     $current[-1]->$method ($name);
534    
535     if ($token->{type} eq ',') {
536     $token = $get_next_token->();
537     # stay in the state
538     } elsif ($token->{type} eq ')') {
539     $token = $get_next_token->();
540     if ($next_state eq '*getraises' and $token->{type} eq 'setraises') {
541     $token = $get_next_token->();
542     $state = 'after raises';
543     $next_state = '*setraises';
544     } else {
545     # reprocess
546     $state = 'before semicolon';
547     $next_state = 'before interface member';
548     }
549     } else {
550     $onerror->(type => 'after exception name',
551     level => $self->{must_level});
552     pop @current; # operation/attribute
553     # reconsume
554     $state = 'ignore';
555     $nest_level = 0;
556     $next_state = 'before interface member';
557     }
558     } else {
559     $onerror->(type => 'scoped name', level => $self->{must_level});
560     pop @current; # operation/attribute
561     # reconsume
562     $state = 'ignore';
563     $nest_level = 0;
564     $next_state = 'before interface member';
565     }
566 wakaba 1.1 } elsif ($state eq 'before interface block') {
567     if ($token->{type} eq '{') {
568     $token = $get_next_token->();
569     $state = 'before members';
570     $next_state = 'before interface member';
571     } else {
572     $onerror->(type => 'before interface block',
573     level => $self->{must_level});
574     # reconsume
575     pop @current; # interface
576     $state = 'ignore';
577     $nest_level = 0;
578     $next_state = 'before definitions';
579     }
580     } elsif ($state eq 'before exception block') {
581     if ($token->{type} eq '{') {
582     $token = $get_next_token->();
583     $state = 'before members';
584     $next_state = 'before exception member';
585     } else {
586     $onerror->(type => 'before exception block',
587     level => $self->{must_level});
588     # reconsume
589     pop @current; # exception
590     $state = 'ignore';
591     $nest_level = 0;
592     $next_state = 'before definitions';
593     }
594     } elsif ($state eq 'before members') {
595 wakaba 1.4 $xattrs = [];
596 wakaba 1.1 if ($token->{type} eq '[') {
597     $token = $get_next_token->();
598     $state = 'before xattr';
599     #$next_state = $next_state; # 'before interface member' or ...
600     } elsif ($token->{type} eq '}') {
601     $token = $get_next_token->();
602     $state = 'before semicolon';
603     $next_state = 'before definitions';
604     } else {
605     # reconsume
606     $state = $next_state; # ... 'before exception member'
607     }
608     } elsif ($state eq 'before interface member') {
609     if ($token->{type} eq 'const') {
610     $token = $get_next_token->();
611     $state = 'before const type';
612     $next_state = 'before definitions';
613     } elsif ($token->{type} eq 'readonly') {
614     $read_only = 1;
615     $token = $get_next_token->();
616     if ($token->{type} eq 'attribute') {
617     $token = $get_next_token->();
618     $state = 'after attribute';
619     } else {
620     # reconsume
621     $state = 'ignore';
622     $nest_level = 0;
623     $next_state = 'before interface member';
624     }
625     } elsif ($token->{type} eq 'attribute') {
626     $read_only = 0;
627     $token = $get_next_token->();
628     $state = 'after attribute';
629     } elsif ({
630     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
631     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
632     '::' => 1, identifier => 1,
633     }->{$token->{type}}) {
634     # reconsume
635     $state = 'before operation type';
636     } elsif ($token->{type} eq '}') {
637     $token = $get_next_token->();
638     $state = 'before semicolon';
639     $next_state = 'before definitions';
640     } elsif ($token->{type} eq 'eof') {
641     $onerror->(type => 'before interface member:eof',
642     level => $self->{must_level});
643     $current[-2]->append_child ($current[-1]);
644     last;
645     } else {
646     $onerror->(type => 'before interface member',
647     level => $self->{must_level});
648     # reconsume
649     pop @current; # interface
650     $state = 'ignore';
651     $nest_level = 0;
652     $next_state = 'before interface member';
653     }
654     } elsif ($state eq 'before exception member') {
655     if ({
656     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
657     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
658     '::' => 1, identifier => 1,
659     }->{$token->{type}}) {
660 wakaba 1.3 # reconsume
661     $state = 'before exception member type';
662 wakaba 1.1 } elsif ($token->{type} eq '}') {
663     $token = $get_next_token->();
664     $state = 'before semicolon';
665     $next_state = 'before definitions';
666     } elsif ($token->{type} eq 'eof') {
667     $onerror->(type => 'before exception member:eof',
668     level => $self->{must_level});
669     $current[-2]->append_child ($current[-1]);
670     last;
671     } else {
672     $onerror->(type => 'before exception member',
673     level => $self->{must_level});
674     # reconsume
675     pop @current; # interface
676     $state = 'ignore';
677     $nest_level = 0;
678     $next_state = 'before exception member';
679     }
680     } elsif ($state eq 'before typedef type') {
681     if ({
682     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
683     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
684     sequence => 1, '::' => 1, identifier => 1,
685     }->{$token->{type}}) {
686     $current_type = $get_type->();
687     if (defined $current_type) {
688     # next token
689     $state = 'before typedef rest';
690     } else {
691     # reconsume
692     $state = 'ignore';
693     $nest_level = 0;
694     $next_state = 'before definitions';
695     }
696     } else {
697     $onerror->(type => 'before type', level => $self->{must_level});
698     # reconsume
699     $state = 'ignore';
700     $nest_level = 0;
701     $next_state = 'before definitions';
702     }
703     } elsif ($state eq 'before boxed type') {
704     if ({
705     boolean => 1, octet => 1, float => 1,
706     short => 1, long => 1, unsigned => 1,
707     sequence => 1, '::' => 1, identifier => 1,
708     }->{$token->{type}}) {
709     $current_type = $get_type->();
710     if (defined $current_type) {
711     $current[-1]->type ($current_type);
712     # next token
713     $state = 'before semicolon';
714     $next_state = 'before definitions';
715     } else {
716     shift @current; # valuetype
717     # reconsume
718     $state = 'ignore';
719     $nest_level = 0;
720     $next_state = 'before definitions';
721     }
722     } else {
723     $onerror->(type => 'before boxed type', level => $self->{must_level});
724     shift @current; # valuetype
725     # reconsume
726     $state = 'ignore';
727     $nest_level = 0;
728     $next_state = 'before definitions';
729     }
730     } elsif ($state eq 'before const type') {
731     if ({
732     any => 1, boolean => 1, octet => 1, float => 1,
733     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
734     '::' => 1, identifier => 1,
735     }->{$token->{type}}) {
736     $current_type = $get_type->();
737     if (defined $current_type) {
738     # next token
739     $state = 'before const identifier';
740     } else {
741     # reconsume
742     $state = 'ignore';
743     $nest_level = 0;
744     #$next_state = $next_state;
745     }
746     } else {
747     $onerror->(type => 'before type', level => $self->{must_level});
748     # reconsume
749     $state = 'ignore';
750     $nest_level = 0;
751     #$next_state = $next_state;
752     }
753     } elsif ($state eq 'before typedef rest') {
754     if ($token->{type} eq 'identifier') {
755     ## TODO: unescape
756     push @current, Whatpm::WebIDL::Typedef->new ($token->{value});
757     $current[-1]->type ($current_type);
758 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
759 wakaba 1.1 $token = $get_next_token->();
760     $state = 'before semicolon';
761     $next_state = 'before definitions';
762     } elsif ($token->{type} eq 'DOMString') {
763     push @current, Whatpm::WebIDL::Typedef->new ('::DOMString::');
764     $current[-1]->type ($current_type);
765 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
766 wakaba 1.1 $token = $get_next_token->();
767     $state = 'before semicolon';
768     $next_state = 'before defnitions';
769     } else {
770     $onerror->(type => 'before typedef rest',
771     level => $self->{must_level});
772     # reconsume
773     $state = 'ignore';
774     $nest_level = 0;
775     $next_state = 'before definitions';
776     }
777     } elsif ($state eq 'before const identifier') {
778     if ($token->{type} eq 'identifier') {
779     ## TODO: unescape
780     push @current, Whatpm::WebIDL::Const->new ($token->{value});
781     $current[-1]->type ($current_type);
782 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
783 wakaba 1.1 $token = $get_next_token->();
784     if ($token->{type} eq '=') {
785     $token = $get_next_token->();
786     $state = 'before const expr';
787     next;
788     } else {
789     $onerror->(type => 'const eq', level => $self->{must_level});
790     #
791     }
792     } else {
793     $onerror->(type => 'const identifier', level => $self->{must_level});
794     #
795     }
796     # reconsume
797     $state = 'ignore';
798     $nest_level = 0;
799     #$next_state = $next_state;
800     } elsif ($state eq 'before const expr') {
801     if ($token->{type} eq 'TRUE' or $token->{type} eq 'FALSE') {
802     $current[-1]->value ([$token->{type}]);
803     #
804     } elsif ($token->{type} eq 'integer' or $token->{type} eq 'float') {
805     $current[-1]->value ([$token->{type}, $token->{value}]);
806     #
807     } else {
808     # reconsume
809     $state = 'ignore';
810     $nest_level = 0;
811     #$next_state = $next_state;
812     next;
813     }
814    
815     $token = $get_next_token->();
816     $state = 'before semicolon';
817     #$next_state = $next_state;
818     } elsif ($state eq 'after attribute') {
819     if ({
820     any => 1, boolean => 1, octet => 1, float => 1,
821     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
822     '::' => 1, identifier => 1,
823     }->{$token->{type}}) {
824     $current_type = $get_type->();
825     if (defined $current_type) {
826     # next token
827     $state = 'before attribute identifier';
828     } else {
829     # reconsume
830     $state = 'ignore';
831     $nest_level = 0;
832     $next_state = 'before interface member';
833     }
834     } else {
835     $onerror->(type => 'before type', level => $self->{must_level});
836     # reconsume
837     $state = 'ignore';
838     $nest_level = 0;
839     $next_state = 'before interface member';
840     }
841 wakaba 1.3 } elsif ($state eq 'before exception member type') {
842     if ({
843     any => 1, boolean => 1, octet => 1, float => 1,
844     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
845     '::' => 1, identifier => 1,
846     }->{$token->{type}}) {
847     $current_type = $get_type->();
848     if (defined $current_type) {
849     # next token
850     $state = 'before exception member identifier';
851     } else {
852     # reconsume
853     $state = 'ignore';
854     $nest_level = 0;
855     $next_state = 'before exception member';
856     }
857     } else {
858     $onerror->(type => 'before type', level => $self->{must_level});
859     # reconsume
860     $state = 'ignore';
861     $nest_level = 0;
862     $next_state = 'before exception member';
863     }
864 wakaba 1.1 } elsif ($state eq 'before operation type') {
865     if ({
866     any => 1, boolean => 1, octet => 1, float => 1,
867     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
868     '::' => 1, identifier => 1,
869     void => 1,
870     }->{$token->{type}}) {
871     $current_type = $get_type->();
872     if (defined $current_type) {
873     # next token
874     $state = 'before operation identifier';
875     } else {
876     # reconsume
877     $state = 'ignore';
878     $nest_level = 0;
879     $next_state = 'before interface member';
880     }
881     } else {
882     $onerror->(type => 'before type', level => $self->{must_level});
883     # reconsume
884     $state = 'ignore';
885     $nest_level = 0;
886     $next_state = 'before interface member';
887     }
888     } elsif ($state eq 'before argument type') {
889     if ({
890     any => 1, boolean => 1, octet => 1, float => 1,
891     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
892     '::' => 1, identifier => 1,
893     }->{$token->{type}}) {
894     $current_type = $get_type->();
895     if (defined $current_type) {
896     # next token
897     $state = 'before argument identifier';
898     } else {
899     # reconsume
900     pop @current; # operation
901     $state = 'ignore';
902     $nest_level = 0;
903     $next_state = 'before interface member';
904     }
905     } else {
906     $onerror->(type => 'before type', level => $self->{must_level});
907     pop @current; # operation
908     # reconsume
909     $state = 'ignore';
910     $nest_level = 0;
911     $next_state = 'before interface member';
912     }
913     } elsif ($state eq 'before attribute identifier') {
914     if ($token->{type} eq 'identifier') {
915     ## TODO: unescape
916     push @current, Whatpm::WebIDL::Attribute->new ($token->{value});
917     $current[-1]->readonly ($read_only);
918     $current[-1]->type ($current_type);
919 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
920 wakaba 1.1 $token = $get_next_token->();
921     if ($token->{type} eq 'getraises') {
922     $token = $get_next_token->();
923 wakaba 1.2 $state = 'after raises';
924     $next_state = '*getraises';
925 wakaba 1.1 next;
926     } elsif ($token->{type} eq 'setraises') {
927     $token = $get_next_token->();
928 wakaba 1.2 $state = 'after raises';
929     $next_state = '*setraises';
930 wakaba 1.1 next;
931     } else {
932     # reconsume
933     $state = 'before semicolon';
934     $next_state = 'before interface member';
935     next;
936     }
937     } else {
938     $onerror->(type => 'attribute identifier',
939     level => $self->{must_level});
940     #
941     }
942     # reconsume
943     $state = 'ignore';
944     $nest_level = 0;
945 wakaba 1.3 $next_state = 'before interface member';
946     } elsif ($state eq 'before exception member identifier') {
947     if ($token->{type} eq 'identifier') {
948     ## TODO: unescape
949     push @current, Whatpm::WebIDL::ExceptionMember->new ($token->{value});
950     $current[-1]->type ($current_type);
951 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
952 wakaba 1.3 $token = $get_next_token->();
953     $state = 'before semicolon';
954     $next_state = 'before exception member';
955     } else {
956     $onerror->(type => 'exception member identifier',
957     level => $self->{must_level});
958     # reconsume
959     $state = 'ignore';
960     $nest_level = 0;
961     $next_state = 'before exception member';
962     }
963 wakaba 1.1 } elsif ($state eq 'before operation identifier') {
964     if ($token->{type} eq 'identifier') {
965     ## TODO: unescape
966     push @current, Whatpm::WebIDL::Operation->new ($token->{value});
967     $current[-1]->type ($current_type);
968 wakaba 1.4 $current[-1]->set_extended_attribute_node ($_) for @$xattrs;
969 wakaba 1.1 $token = $get_next_token->();
970     if ($token->{type} eq '(') {
971     $token = $get_next_token->();
972     if ($token->{type} eq ')') {
973     $token = $get_next_token->();
974 wakaba 1.2 $state = 'before raises';
975     $next_state = '*raises';
976 wakaba 1.1 next;
977     } else {
978     # reconsume
979     $state = 'before argument';
980     next;
981     }
982     } else {
983     pop @current;
984     $onerror->(type => 'arguments lparen',
985     level => $self->{must_level});
986     #
987     }
988     } else {
989     $onerror->(type => 'operation identifier',
990     level => $self->{must_level});
991     #
992     }
993     # reconsume
994     $state = 'ignore';
995     $nest_level = 0;
996 wakaba 1.3 $next_state = 'before interface member';
997 wakaba 1.1 } elsif ($state eq 'before argument identifier') {
998     if ($token->{type} eq 'identifier') {
999     ## TODO: unescape
1000     my $arg = Whatpm::WebIDL::Argument->new ($token->{value});
1001     $arg->type ($current_type);
1002 wakaba 1.4 $arg->set_extended_attribute_node ($_) for @$xattrs;
1003 wakaba 1.1 $current[-1]->append_child ($arg);
1004     $token = $get_next_token->();
1005     if ($token->{type} eq ')') {
1006     $token = $get_next_token->();
1007 wakaba 1.4 if ($current[-1]->isa ('Whatpm::WebIDL::Operation')) {
1008     $state = 'before raises';
1009     } else {
1010     $state = 'after xattrarg';
1011     }
1012 wakaba 1.1 next;
1013     } elsif ($token->{type} eq ',') {
1014     $token = $get_next_token->();
1015     $state = 'before argument';
1016     next;
1017     } else {
1018     $onerror->(type => 'after argument',
1019     level => $self->{must_level});
1020     #
1021     }
1022     } else {
1023     $onerror->(type => 'argument identifier',
1024     level => $self->{must_level});
1025     #
1026     }
1027     pop @current; # operation
1028     # reconsume
1029     $state = 'ignore';
1030     $nest_level = 0;
1031 wakaba 1.3 $next_state = 'before interface member';
1032 wakaba 1.1 } elsif ($state eq 'before argument') {
1033 wakaba 1.4 $xattrs = [];
1034 wakaba 1.1 if ($token->{type} eq '[') {
1035     $token = $get_next_token->();
1036     $state = 'before xattr';
1037     $next_state = 'before argument in';
1038     } else {
1039     # reconsume
1040     $state = 'before argument in';
1041     }
1042     } elsif ($state eq 'before argument in') {
1043     if ($token->{type} eq 'in') {
1044     $token = $get_next_token->();
1045     $state = 'before argument type';
1046     } else {
1047     $onerror->(type => 'argument in',
1048     level => $self->{must_level});
1049     pop @current; # operation
1050     $state = 'ignore';
1051     $nest_level = 0;
1052     $next_state = 'before interface member';
1053     }
1054     } elsif ($state eq 'before raises') {
1055     if ($token->{type} eq 'raises') {
1056     $token = $get_next_token->();
1057     $state = 'after raises';
1058 wakaba 1.2 $next_state = '*raises';
1059 wakaba 1.1 } else {
1060     # reconsume
1061     $state = 'before semicolon';
1062     $next_state = 'before interface member';
1063     }
1064     } elsif ($state eq 'after raises') {
1065 wakaba 1.2 if ($token->{type} eq '(') {
1066     $token = $get_next_token->();
1067     $state = 'before exception name';
1068     } else {
1069     $onerror->(type => 'raises lparen',
1070     level => $self->{must_level});
1071     pop @current; # operation
1072     $state = 'ignore';
1073     $nest_level = 0;
1074     $next_state = 'before interface member';
1075     }
1076 wakaba 1.1 } elsif ($state eq 'before semicolon') {
1077     if ($token->{type} eq ';') {
1078     $current[-2]->append_child ($current[-1]);
1079     pop @current;
1080     $token = $get_next_token->();
1081     $state = {
1082     #'before definitions',
1083     'before interface member' => 'before members', # keep $next_state
1084     'before exception member' => 'before members', # as is
1085     }->{$next_state} || $next_state;
1086     } else {
1087     pop @current;
1088     $onerror->(type => 'before semicolon', level => 'm',
1089     token => $token);
1090     # reconsume
1091     $state = 'ignore';
1092     $nest_level = 0;
1093     $next_state = 'before definitions';
1094     }
1095     } elsif ($state eq 'ignore') {
1096     if (($nest_level == 0 and $token->{type} eq ';') or
1097     (@current > 1 and not $nest_level and $token->{type} eq '}')) {
1098     $token = $get_next_token->();
1099     $state = {
1100     #'before definitions',
1101     'before interface member' => 'before members', # keep $next_state
1102     'before exception member' => 'before members', # as is
1103     }->{$next_state} || $next_state;
1104     } elsif ($token->{type} eq '{') {
1105     $nest_level++;
1106     $token = $get_next_token->();
1107     # stay in the state
1108     } elsif ($nest_level and $token->{type} eq '}') {
1109     $nest_level--;
1110     $token = $get_next_token->();
1111     # stay in the state
1112     } elsif ($token->{type} eq 'eof') {
1113     last;
1114     } else {
1115     # ignore the token
1116     $token = $get_next_token->();
1117     # stay in the state
1118     }
1119     } else {
1120     die "parse_char_string: unkown state: $state";
1121     }
1122     }
1123    
1124     if (@current > 1) {
1125     $onerror->(type => 'block not closed', level => $self->{must_level});
1126     }
1127    
1128     $get_type = undef; # unlink loop
1129    
1130     return $defs;
1131     } # parse_char_string
1132    
1133     package Whatpm::WebIDL::Definitions;
1134    
1135     sub new ($) {
1136     return bless {child_nodes => []}, $_[0];
1137     } # new
1138    
1139     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1140    
1141     sub idl_text ($) {
1142     return join "\x0A", map {$_->idl_text} @{$_[0]->{child_nodes}};
1143     } # idl_text
1144    
1145     package Whatpm::WebIDL::Definition;
1146    
1147     sub new ($$) {
1148     return bless {child_nodes => [], node_name => ''.$_[1]}, $_[0];
1149     } # new
1150    
1151     sub append_child ($$) {
1152     my $self = shift;
1153     my $child = shift;
1154    
1155     ## TODO: child type
1156     ## TODO: parent check
1157    
1158     push @{$self->{child_nodes}}, $child;
1159    
1160     return $child;
1161     } # append_child
1162    
1163     sub node_name ($) {
1164     return $_[0]->{node_name};
1165     } # node_name
1166    
1167 wakaba 1.4 sub set_extended_attribute_node ($$) {
1168     my $self = shift;
1169     ## TODO: check
1170     push @{$self->{xattrs} ||= []}, shift;
1171     } # set_extended_attribute_node
1172    
1173 wakaba 1.1 sub idl_text ($) {
1174     return '[[ERROR: ' . (ref $_[0]) . '->idl_text]]';
1175     } # idl_text
1176    
1177 wakaba 1.4 sub _xattrs_text ($) {
1178     my $self = shift;
1179    
1180     unless ($self->{xattrs} and
1181     @{$self->{xattrs}}) {
1182     return '';
1183     }
1184    
1185     my $r = '[';
1186     $r .= join ', ', map {$_->idl_text} @{$self->{xattrs}};
1187     $r .= ']';
1188     return $r;
1189     } # _xattrs_text
1190    
1191 wakaba 1.1 sub type ($;$) {
1192     if (@_ > 1) {
1193     if (defined $_[1]) {
1194     $_[0]->{type} = $_[1];
1195     } else {
1196     $_[0]->{type} = ['::any::'];
1197     }
1198     }
1199     return $_[0]->{type};
1200     } # type
1201    
1202     sub type_text ($) {
1203     my $type = $_[0]->{type};
1204     return undef unless defined $type;
1205    
1206     if ($type->[0] eq '::sequence::') {
1207     return 'sequence<' . (join '::', @{$type->[1]}) . '>'; ## TODO: escape, nested
1208     } else {
1209     return join '::', @$type; ## TODO: escape
1210     }
1211     } # type_text
1212    
1213     package Whatpm::WebIDL::Module;
1214     push our @ISA, 'Whatpm::WebIDL::Definition';
1215    
1216     sub idl_text ($) {
1217 wakaba 1.4 my $self = shift;
1218     my $r = $self->_xattrs_text;
1219     $r .= ' ' if length $r;
1220     $r .= 'module ' . $self->node_name . "{\x0A\x0A"; ## TODO: escape
1221     for (@{$self->{child_nodes}}) {
1222 wakaba 1.1 $r .= $_->idl_text;
1223     }
1224     $r .= "\x0A};\x0A";
1225     return $r;
1226     } # idl_text
1227    
1228     package Whatpm::WebIDL::Interface;
1229     push our @ISA, 'Whatpm::WebIDL::Definition';
1230    
1231     sub new ($$) {
1232     my $self = shift->SUPER::new (@_);
1233     $self->{inheritances} = [];
1234     return $self;
1235     } # new
1236    
1237     sub append_inheritance ($$) {
1238     my $self = shift;
1239     my $scoped_name = shift;
1240     push @{$self->{inheritances}}, $scoped_name;
1241     } # append_inheritance
1242    
1243     sub idl_text ($) {
1244 wakaba 1.3 my $self = shift;
1245 wakaba 1.4 my $r = $self->_xattrs_text;
1246     $r .= ' ' if length $r;
1247     $r = 'interface ' . $self->node_name;
1248 wakaba 1.3 if (@{$self->{inheritances}}) {
1249     $r .= ' : '; ## TODO: ...
1250     $r .= join ', ', map {join '::', @{$_}} @{$self->{inheritances}};
1251     }
1252     $r .= " {\x0A"; ## TODO: escape
1253     for (@{$self->{child_nodes}}) {
1254 wakaba 1.1 $r .= ' ' . $_->idl_text;
1255     }
1256     $r .= "};\x0A";
1257     return $r;
1258     } # idl_text
1259    
1260     package Whatpm::WebIDL::Exception;
1261     push our @ISA, 'Whatpm::WebIDL::Definition';
1262    
1263 wakaba 1.3 sub idl_text ($) {
1264 wakaba 1.4 my $self = shift;
1265     my $r = $self->_xattrs_text;
1266     $r .= ' ' if length $r;
1267     $r = 'exception ' . $self->node_name . "{\x0A"; ## TODO: escape
1268     for (@{$self->{child_nodes}}) {
1269 wakaba 1.3 $r .= ' ' . $_->idl_text;
1270     }
1271     $r .= "};\x0A";
1272     return $r;
1273     } # idl_text
1274    
1275 wakaba 1.1 package Whatpm::WebIDL::Typedef;
1276     push our @ISA, 'Whatpm::WebIDL::Definition';
1277    
1278     sub new ($$) {
1279     my $self = shift->SUPER::new (@_);
1280     $self->{type} = ['::any::'];
1281     return $self;
1282     } # new
1283    
1284     sub idl_text ($) {
1285 wakaba 1.4 my $self = shift;
1286     my $r = $self->_xattrs_text;
1287     $r .= ' ' if length $r;
1288 wakaba 1.1 ## TODO: escape
1289 wakaba 1.4 $r .= 'typedef ' . $self->type_text . ' ' . $self->node_name . ";\x0A";
1290     return $r;
1291 wakaba 1.1 } # idl_text
1292    
1293     package Whatpm::WebIDL::Valuetype;
1294     push our @ISA, 'Whatpm::WebIDL::Definition';
1295    
1296     sub new ($$) {
1297     my $self = shift->SUPER::new (@_);
1298     $self->{type} = ['::boolean::'];
1299     return $self;
1300     } # new
1301    
1302     sub idl_text ($) {
1303 wakaba 1.4 my $self = shift;
1304     my $r = $self->_xattrs_text;
1305     $r .= ' ' if length $r;
1306 wakaba 1.1 ## TODO: escape
1307 wakaba 1.4 $r .= 'valuetype ' . $self->node_name . ' ' . $self->type_text . ";\x0A";
1308     return $r;
1309 wakaba 1.1 } # idl_text
1310    
1311     package Whatpm::WebIDL::InterfaceMember;
1312    
1313     sub new ($$) {
1314     return bless {node_name => ''.$_[1]}, $_[0];
1315     } # new
1316    
1317 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1318    
1319 wakaba 1.1 *idl_text = \&Whatpm::WebIDL::Definition::idl_text;
1320    
1321     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1322    
1323 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1324    
1325 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
1326    
1327     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1328    
1329     package Whatpm::WebIDL::Const;
1330     push our @ISA, 'Whatpm::WebIDL::Definition', 'Whatpm::WebIDL::InterfaceMember';
1331    
1332     sub new ($$) {
1333     my $self = shift->SUPER::new (@_); # Definition->new should be called
1334     $self->{type} = ['::boolean::'];
1335     $self->{value} = ['FALSE'];
1336     return $self;
1337     } # new
1338    
1339     sub value ($;$) {
1340     if (@_ > 1) {
1341     $_[0]->{value} = $_[1];
1342     }
1343    
1344     return $_[0]->{value};
1345     } # value
1346    
1347     sub value_text ($) {
1348     my $value = $_[0]->{value};
1349    
1350     if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
1351     return $value->[0];
1352     } elsif ($value->[0] eq 'integer' or $value->[0] eq 'float') {
1353     ## TODO: format
1354     return $value->[1];
1355     } else {
1356     return undef;
1357     }
1358     } # value_text
1359    
1360     sub idl_text ($) {
1361 wakaba 1.4 my $self = shift;
1362     my $r = $self->_xattrs_text;
1363     $r .= ' ' if length $r;
1364     $r .= 'const ' . $self->type_text . ' ' . $self->node_name . ' = ' . $self->value_text . ";\x0A"; ## TODO: escape
1365     return $r;
1366 wakaba 1.1 } # idl_text
1367    
1368     package Whatpm::WebIDL::Attribute;
1369     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1370    
1371     sub new ($$) {
1372     my $self = shift->SUPER::new (@_);
1373     $self->{type} = ['::any::'];
1374 wakaba 1.2 $self->{getraises} = [];
1375     $self->{setraises} = [];
1376 wakaba 1.1 return $self;
1377     } # new
1378    
1379 wakaba 1.2 sub append_getraises ($$) {
1380     ## TODO: error check, etc.
1381     push @{$_[0]->{getraises}}, $_[1];
1382     } # append_getraises
1383    
1384     sub append_setraises ($$) {
1385     ## TODO: error check, etc.
1386     push @{$_[0]->{setraises}}, $_[1];
1387     } # append_setraises
1388    
1389 wakaba 1.1 sub readonly ($;$) {
1390     if (@_ > 1) {
1391     $_[0]->{readonly} = $_[1];
1392     }
1393    
1394     return $_[0]->{readonly};
1395     } # readonly
1396    
1397     sub idl_text ($) {
1398 wakaba 1.2 my $self = shift;
1399 wakaba 1.4 my $r = $self->_xattrs_text;
1400     $r .= ' ' if length $r;
1401     $r .= ($self->readonly ? 'readonly ' : '') . 'attribute ' . $self->type_text . ' ' . $self->node_name;
1402 wakaba 1.1 ## TODO: escape
1403 wakaba 1.2 if (@{$self->{getraises}}) {
1404     $r .= ' getraises (';
1405     ## todo: ...
1406     $r .= join ', ', map {join '::', @{$_}} @{$self->{getraises}};
1407     $r .= ')';
1408     }
1409     if (@{$self->{setraises}}) {
1410     $r .= ' setraises (';
1411     ## todo: ...
1412     $r .= join ', ', map {join '::', @{$_}} @{$self->{setraises}};
1413     $r .= ')';
1414     }
1415     $r .= ";\x0A";
1416     return $r;
1417 wakaba 1.1 } # idl_text
1418    
1419     package Whatpm::WebIDL::Operation;
1420     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1421    
1422     sub new ($$) {
1423     my $self = shift->SUPER::new (@_);
1424     $self->{type} = ['::any::'];
1425     $self->{child_nodes} = [];
1426 wakaba 1.2 $self->{raises} = [];
1427 wakaba 1.1 return $self;
1428     } # new
1429    
1430     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1431    
1432 wakaba 1.2 sub append_raises ($$) {
1433     ## TODO: error check, etc.
1434     push @{$_[0]->{raises}}, $_[1];
1435     } # append_raises
1436    
1437 wakaba 1.1 sub idl_text ($) {
1438 wakaba 1.2 my $self = shift;
1439 wakaba 1.4 my $r = $self->_xattrs_text;
1440     $r .= ' ' if length $r;
1441     $r .= $self->type_text . ' ' . $self->node_name . ' ('; ## TODO: escape
1442 wakaba 1.2 $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
1443     $r .= ')';
1444     if (@{$self->{raises}}) {
1445     $r .= ' raises (';
1446     ## todo: ...
1447     $r .= join ', ', map {join '::', @{$_}} @{$self->{raises}};
1448     $r .= ')';
1449     }
1450 wakaba 1.1 $r .= ";\x0A";
1451     return $r;
1452     } # idl_text
1453    
1454     package Whatpm::WebIDL::Argument;
1455    
1456     sub new ($$) {
1457     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1458     } # new
1459    
1460     sub idl_text ($) {
1461 wakaba 1.4 my $self = shift;
1462     my $r = $self->_xattrs_text;
1463     $r .= ' ' if length $r;
1464     $r .= 'in ' . $self->type_text . ' ' . $self->node_name; ## TODO: escape
1465     return $r;
1466 wakaba 1.3 } # idl_text
1467    
1468 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1469    
1470 wakaba 1.3 *node_name = \&Whatpm::WebIDL::Definition::node_name;
1471    
1472 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1473    
1474 wakaba 1.3 *type = \&Whatpm::WebIDL::Definition::type;
1475    
1476     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1477    
1478     package Whatpm::WebIDL::ExceptionMember;
1479    
1480     sub new ($$) {
1481     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1482     } # new
1483    
1484     sub idl_text ($) {
1485 wakaba 1.4 my $self = shift;
1486     my $r = $self->_xattrs_text;
1487     $r .= ' ' if length $r;
1488     $r .= $self->type_text . ' ' . $self->node_name . ";\x0A"; ## TODO: escape
1489     return $r;
1490 wakaba 1.1 } # idl_text
1491    
1492 wakaba 1.4 *_xattrs_text = \&Whatpm::WebIDL::Definition::_xattrs_text;
1493    
1494 wakaba 1.1 *node_name = \&Whatpm::WebIDL::Definition::node_name;
1495    
1496 wakaba 1.4 *set_extended_attribute_node = \&Whatpm::WebIDL::Definition::set_extended_attribute_node;
1497    
1498 wakaba 1.1 *type = \&Whatpm::WebIDL::Definition::type;
1499    
1500     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1501 wakaba 1.4
1502     package Whatpm::WebIDL::ExtendedAttribute;
1503    
1504     sub new ($$) {
1505     return bless {child_nodes => [], node_name => ''.$_[1]};
1506     } # new
1507    
1508     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1509    
1510     sub idl_text ($) {
1511     my $self = shift;
1512     my $r = $self->node_name; ## TODO:] esceape
1513     if (defined $self->{value}) {
1514     $r .= '=' . $self->{value}; ## TODO: escape
1515     }
1516     if (@{$self->{child_nodes}}) {
1517     $r .= ' (';
1518     $r .= join ', ', map {$_->idl_text} @{$self->{child_nodes}};
1519     $r .= ')';
1520     }
1521     return $r;
1522     } # idl_text
1523    
1524     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1525    
1526     sub value ($;$) {
1527     if (@_ > 1) {
1528     if (defined $_[1]) {
1529     $_[0]->{value} = ''.$_[1];
1530     } else {
1531     delete $_[0]->{value};
1532     }
1533     }
1534    
1535     return $_[0]->{value};
1536     } # value
1537 wakaba 1.1
1538     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24