/[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.1 - (hide annotations) (download)
Fri Jul 18 14:46:11 2008 UTC (16 years, 3 months ago) by wakaba
Branch: MAIN
++ whatpm/Whatpm/ChangeLog	18 Jul 2008 14:46:07 -0000
2008-07-18  Wakaba  <wakaba@suika.fam.cx>

	* WebIDL.pm: Support for |idl_text| attribute, version 1 (no
	proper support for types, extended attributes, and exceptions yet).
	WebIDL parser, version 1 (no support for exceptions yet,
	no proper support for extended attributes yet).

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     my $last_xattr;
89     my $read_only;
90     my $current_type;
91     my @current = ($defs);
92    
93     my $_onerror = $_[1] || sub {
94     my %opt = @_;
95     my $r = 'Line ' . $opt{line} . ' column ' . $opt{column} . ': ';
96    
97     if ($opt{token}) {
98     $r .= 'Token ' . (defined $opt{token}->{value} ? $opt{token}->{value} : $opt{token}->{type}) . ': ';
99     }
100    
101     $r .= $opt{type} . ';' . $opt{level};
102    
103     warn $r . "\n";
104     }; # $_onerror
105     my $onerror = sub {
106     $_onerror->(line => $line, column => $column, token => $token, @_);
107     }; # $onerror
108    
109     my $get_scoped_name = sub {
110     my $name = [];
111    
112     ## NOTE: "DOMString" is not a scoped name, while "::DOMString"
113     ## and "x::DOMString" are.
114    
115     if ($token->{type} eq 'identifier') {
116     ## TODO: unescape
117     push @$name, $token->{value};
118     $token = $get_next_token->();
119     while ($token->{type} eq '::') {
120     if ($token->{type} eq 'identifier') {
121     ## TODO: unescape
122     push @$name, $token->{value};
123     $token = $get_next_token->();
124     } elsif ($token->{type} eq 'DOMString') {
125     push @$name, '::DOMString::';
126     $token = $get_next_token->();
127     last;
128     }
129     }
130     } elsif ($token->{type} eq '::') {
131     push @$name, '';
132     while ($token->{type} eq '::') {
133     if ($token->{type} eq 'identifier') {
134     ## TODO: unescape
135     push @$name, $token->{value};
136     $token = $get_next_token->();
137     } elsif ($token->{type} eq 'DOMString') {
138     push @$name, '::DOMString::';
139     $token = $get_next_token->();
140     last;
141     } else {
142     last;
143     }
144     }
145    
146     if (@$name == 1) {
147     return undef;
148     }
149     } else {
150     # reconsume
151     return undef;
152     }
153     return $name;
154     }; # $get_scoped_name
155    
156     my $get_type;
157     $get_type = sub {
158     my $r;
159     if ({
160     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
161     DOMString => 1, Object => 1, short => 1,
162     }->{$token->{type}}) {
163     $r = ['::'.$token->{type}.'::'];
164     $token = $get_next_token->();
165     } elsif ($token->{type} eq 'unsigned') {
166     $token = $get_next_token->();
167     if ($token->{type} eq 'short') {
168     $r = ['::unsigned '.$token->{type}.'::'];
169     $token = $get_next_token->();
170     } elsif ($token->{type} eq 'long') {
171     $token = $get_next_token->();
172     if ($token->{type} eq 'long') {
173     $r = ['::unsigned long long::'];
174     $token = $get_next_token->();
175     } else {
176     $r = ['::unsigned long::'];
177     # reconsume
178     }
179     } else {
180     $onerror->(type => 'unsigned', level => $self->{must_level});
181     return undef;
182     }
183     } elsif ($token->{type} eq 'long') {
184     $token = $get_next_token->();
185     if ($token->{type} eq 'long') {
186     $r = ['::long long::'];
187     $token = $get_next_token->();
188     } else {
189     $r = ['::long::'];
190     # reconsume
191     }
192     } elsif ($token->{type} eq '::' or $token->{type} eq 'identifier') {
193     $r = $get_scoped_name->();
194     if (defined $r) {
195     # next token
196     } else { # "::" not followed by identifier or "DOMString"
197     $onerror->(type => 'scoped name', level => $self->{must_level});
198     return undef;
199     }
200     } elsif ($token->{type} eq 'sequence') {
201     $token = $get_next_token->();
202     if ($token->{type} eq '<') {
203     $token = $get_next_token->();
204     if ({
205     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
206     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
207     sequence => 1, '::' => 1, identifier => 1,
208     }->{$token->{type}}) {
209     my $type = $get_type->();
210     if (defined $type) {
211     if ($token->{type} eq '>') {
212     $r = ['::sequence::', $type];
213     $token = $get_next_token->();
214     } else {
215     $onerror->(type => 'sequence gt', level => $self->{must_level});
216     return undef;
217     }
218     } else {
219     # error reported
220     return undef;
221     }
222     } else {
223     $onerror->(type => 'sequence type', level => $self->{must_level});
224     return undef;
225     }
226     } else {
227     $onerror->(type => 'sequence lt', level => $self->{must_level});
228     return undef;
229     }
230     } else {
231     die "get_type: bad token: $token->{type}";
232     }
233    
234     return $r;
235     }; # $get_type
236    
237     while (1) {
238     if ($state eq 'before definitions') {
239     if ($token->{type} eq '[') {
240     $xattrs = {};
241     $token = $get_next_token->();
242     $state = 'before xattr';
243     $next_state = 'before def';
244     } elsif ({module => 1, interface => 1, exception => 1,
245     typedef => 1, valuetype => 1, const => 1}->{$token->{type}}) {
246     $xattrs = {};
247     # reconsume
248     $state = 'before def';
249     } elsif ($token->{type} eq '}' and @current > 1) {
250     $token = $get_next_token->();
251     $state = 'before semicolon';
252     $next_state = 'before definitions';
253     } elsif ($token->{type} eq 'eof') {
254     last;
255     } else {
256     $onerror->(type => 'before definitions', level => 'm',
257     token => $token);
258     # reconsume
259     $state = 'ignore';
260     $nest_level = 0;
261     $next_state = 'before definitions';
262     }
263     } elsif ($state eq 'before xattr') {
264    
265     ## TODO: methodType methodName ([broken xattr] ...); is not well
266     ## handled on forward-compatible parsing (i.e. pop @current).
267    
268     if ($token->{type} eq 'identifier') {
269     ## TODO: _escape
270     ## ISSUE: Duplicate attributes
271     ## ISSUE: Unkown attributes
272     $xattrs->{$token->{value}} = '';
273     $last_xattr = $token->{value};
274     $token = $get_next_token->();
275     $state = 'after xattr';
276     } elsif ($token->{type} eq 'eof') {
277     $onerror->(type => 'before xattr:eof', level => 'm', token => $token);
278     $token = $get_next_token->();
279     $state = 'after xattrlist';
280     } else {
281     $onerror->(type => 'before xattr', level => 'm', token => $token);
282     # reconsume
283     $state = 'ignore';
284     $nest_level = 0;
285     $next_state = 'before definitions';
286     }
287     } elsif ($state eq 'after xattr') {
288     if ($token->{type} eq '=') {
289     $token = $get_next_token->();
290     $state = 'before xattrarg';
291     } else {
292     # reconsume
293     $state = 'after xattrarg';
294     }
295     } elsif ($state eq 'before xattrarg') {
296     if ($token->{type} eq 'identifier') {
297     ## TODO: escape
298     $xattrs->{$last_xattr} = $token->{value};
299     $token = $get_next_token->();
300     $state = 'after xattrarg';
301     } elsif ($token->{type} eq 'eof') {
302     # any extended attributes are ignored
303     $onerror->(type => 'after xattrarg:eof', level => 'm',
304     token => $token);
305     last;
306     } else {
307     $onerror->(type => 'after xattrarg', level => 'm', token => $token);
308     # reconsume
309     $state = 'ignore';
310     $nest_level = 0;
311     $next_state = 'before definitions';
312     }
313     } elsif ($state eq 'after xattrarg') {
314     if ($token->{type} eq ',') {
315     $token = $get_next_token->();
316     $state = 'before xattr';
317     } elsif ($token->{type} eq ']') {
318     $token = $get_next_token->();
319     $state = $next_state; # 'before def' or 'before interface member'
320     } elsif ($token->{type} eq 'eof') {
321     # any extended attributes are ignored
322     $onerror->(type => 'after xattr:eof', level => 'm', token => $token);
323     last;
324     } else {
325     $onerror->(type => 'after xattr', level => 'm', token => $token);
326     # reconsume
327     $state = 'ignore';
328     $nest_level = 0;
329     $next_state = 'before definitions';
330     }
331     } elsif ($state eq 'before def') {
332     if ($token->{type} eq 'module') {
333     $token = $get_next_token->();
334     if ($token->{type} eq 'identifier') {
335     ## TODO: escape
336     push @current, Whatpm::WebIDL::Module->new ($token->{value});
337     $token = $get_next_token->();
338     $state = 'before module block';
339     next;
340     } else {
341     $onerror->(type => 'module identifier',
342     level => $self->{must_level});
343     #
344     }
345     } elsif ($token->{type} eq 'interface') {
346     $token = $get_next_token->();
347     if ($token->{type} eq 'identifier') {
348     ## TODO: escape
349     push @current, Whatpm::WebIDL::Interface->new ($token->{value});
350     $token = $get_next_token->();
351     $state = 'before interface inheritance';
352     next;
353     } else {
354     $onerror->(type => 'interface identifier',
355     level => $self->{must_level});
356     #
357     }
358     } elsif ($token->{type} eq 'exception') {
359     $token = $get_next_token->();
360     if ($token->{type} eq 'identifier') {
361     ## TODO: escape
362     push @current, Whatpm::WebIDL::Exception->new ($token->{value});
363     $token = $get_next_token->();
364     $state = 'before exception block';
365     next;
366     } else {
367     $onerror->(type => 'exception identifier',
368     level => $self->{must_level});
369     #
370     }
371     } elsif ($token->{type} eq 'typedef') {
372     $token = $get_next_token->();
373     $state = 'before typedef type';
374     next;
375     } elsif ($token->{type} eq 'valuetype') {
376     $token = $get_next_token->();
377     if ($token->{type} eq 'identifier') {
378     ## TODO: escape
379     push @current, Whatpm::WebIDL::Valuetype->new ($token->{value});
380     $token = $get_next_token->();
381     $state = 'before boxed type';
382     next;
383     } elsif ($token->{type} eq 'DOMString') {
384     push @current, Whatpm::WebIDL::Valuetype->new ('::DOMString::');
385     $token = $get_next_token->();
386     if ($token->{type} eq 'sequence') {
387     $token = $get_next_token->();
388     if ($token->{type} eq '<') {
389     $token = $get_next_token->();
390     if ($token->{type} eq 'unsigned') {
391     $token = $get_next_token->();
392     if ($token->{type} eq 'short') {
393     $token = $get_next_token->();
394     if ($token->{type} eq '>') {
395     $current[-1]->type
396     (['::sequence::', ['::unsigned short::']]);
397     $token = $get_next_token->();
398     $state = 'before semicolon';
399     $next_state = 'before definitions';
400     next;
401     } else {
402     $onerror->(type => 'valuetype DOMString sequence lt unsigned short gt',
403     level => $self->{must_level});
404     #
405     }
406     } else {
407     $onerror->(type => 'valuetype DOMString sequence lt unsigned short',
408     level => $self->{must_level});
409     #
410     }
411     } else {
412     $onerror->(type => 'valuetype DOMString sequence lt unsigned',
413     level => $self->{must_level});
414     #
415     }
416     } else {
417     $onerror->(type => 'valuetype DOMString sequence lt',
418     level => $self->{must_level});
419     #
420     }
421     } else {
422     $onerror->(type => 'valuetype DOMString sequence',
423     level => $self->{must_level});
424     #
425     }
426     shift @current; # valuetype
427     #
428     } else {
429     $onerror->(type => 'valuetype identifier',
430     level => $self->{must_level});
431     #
432     }
433     } elsif ($token->{type} eq 'const') {
434     $token = $get_next_token->();
435     $state = 'before const type';
436     $next_state = 'before definitions';
437     next;
438     } elsif ($token->{type} eq 'eof') {
439     ## NOTE: Any extended attributes are ignored.
440     $onerror->(type => 'before def:eof', level => 'm', token => $token);
441     last;
442     } else {
443     $onerror->(type => 'before definition', level => 'm',
444     token => $token);
445     # reconsume
446     #
447     }
448     $state = 'ignore';
449     $nest_level = 0;
450     $next_state = 'before definitions';
451     } elsif ($state eq 'before module block') {
452     if ($token->{type} eq '{') {
453     $token = $get_next_token->();
454     $state = 'before definitions';
455     } else {
456     $onerror->(type => 'before module block', level => 'm',
457     token => $token);
458     pop @current; # module
459     # reconsume
460     $state = 'ignore';
461     $nest_level = 0;
462     $next_state = 'before definitions';
463     }
464     } elsif ($state eq 'before interface inheritance') {
465     if ($token->{type} eq ':') {
466     $token = $get_next_token->();
467     $state = 'before parent interface name';
468     } else {
469     # reconsume
470     $state = 'before interface block';
471     }
472     } elsif ($state eq 'before parent interface name') {
473     my $name = $get_scoped_name->();
474     if (defined $name) {
475     $current[-1]->append_inheritance ($name);
476    
477     if ($token->{type} eq ',') {
478     $token = $get_next_token->();
479     # stay in the state
480     } else {
481     # reconsume
482     $state = 'before interface block';
483     }
484     } else {
485     $onerror->(type => 'scoped name', level => $self->{must_level});
486     pop @current; # interface
487     # reconsume
488     $state = 'ignore';
489     $nest_level = 0;
490     $next_state = 'before definitions';
491     }
492     } elsif ($state eq 'before interface block') {
493     if ($token->{type} eq '{') {
494     $token = $get_next_token->();
495     $state = 'before members';
496     $next_state = 'before interface member';
497     } else {
498     $onerror->(type => 'before interface block',
499     level => $self->{must_level});
500     # reconsume
501     pop @current; # interface
502     $state = 'ignore';
503     $nest_level = 0;
504     $next_state = 'before definitions';
505     }
506     } elsif ($state eq 'before exception block') {
507     if ($token->{type} eq '{') {
508     $token = $get_next_token->();
509     $state = 'before members';
510     $next_state = 'before exception member';
511     } else {
512     $onerror->(type => 'before exception block',
513     level => $self->{must_level});
514     # reconsume
515     pop @current; # exception
516     $state = 'ignore';
517     $nest_level = 0;
518     $next_state = 'before definitions';
519     }
520     } elsif ($state eq 'before members') {
521     if ($token->{type} eq '[') {
522     $token = $get_next_token->();
523     $state = 'before xattr';
524     #$next_state = $next_state; # 'before interface member' or ...
525     } elsif ($token->{type} eq '}') {
526     $token = $get_next_token->();
527     $state = 'before semicolon';
528     $next_state = 'before definitions';
529     } else {
530     # reconsume
531     $state = $next_state; # ... 'before exception member'
532     }
533     } elsif ($state eq 'before interface member') {
534     if ($token->{type} eq 'const') {
535     $token = $get_next_token->();
536     $state = 'before const type';
537     $next_state = 'before definitions';
538     } elsif ($token->{type} eq 'readonly') {
539     $read_only = 1;
540     $token = $get_next_token->();
541     if ($token->{type} eq 'attribute') {
542     $token = $get_next_token->();
543     $state = 'after attribute';
544     } else {
545     # reconsume
546     $state = 'ignore';
547     $nest_level = 0;
548     $next_state = 'before interface member';
549     }
550     } elsif ($token->{type} eq 'attribute') {
551     $read_only = 0;
552     $token = $get_next_token->();
553     $state = 'after attribute';
554     } elsif ({
555     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
556     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
557     '::' => 1, identifier => 1,
558     }->{$token->{type}}) {
559     # reconsume
560     $state = 'before operation type';
561     } elsif ($token->{type} eq '}') {
562     $token = $get_next_token->();
563     $state = 'before semicolon';
564     $next_state = 'before definitions';
565     } elsif ($token->{type} eq 'eof') {
566     $onerror->(type => 'before interface member:eof',
567     level => $self->{must_level});
568     $current[-2]->append_child ($current[-1]);
569     last;
570     } else {
571     $onerror->(type => 'before interface member',
572     level => $self->{must_level});
573     # reconsume
574     pop @current; # interface
575     $state = 'ignore';
576     $nest_level = 0;
577     $next_state = 'before interface member';
578     }
579     } elsif ($state eq 'before exception member') {
580     if ({
581     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
582     DOMString => 1, Object => 1, unsigned => 1, short => 1, long => 1,
583     '::' => 1, identifier => 1,
584     }->{$token->{type}}) {
585    
586     } elsif ($token->{type} eq '}') {
587     $token = $get_next_token->();
588     $state = 'before semicolon';
589     $next_state = 'before definitions';
590     } elsif ($token->{type} eq 'eof') {
591     $onerror->(type => 'before exception member:eof',
592     level => $self->{must_level});
593     $current[-2]->append_child ($current[-1]);
594     last;
595     } else {
596     $onerror->(type => 'before exception member',
597     level => $self->{must_level});
598     # reconsume
599     pop @current; # interface
600     $state = 'ignore';
601     $nest_level = 0;
602     $next_state = 'before exception member';
603     }
604     } elsif ($state eq 'before typedef type') {
605     if ({
606     void => 1, any => 1, boolean => 1, octet => 1, float => 1,
607     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
608     sequence => 1, '::' => 1, identifier => 1,
609     }->{$token->{type}}) {
610     $current_type = $get_type->();
611     if (defined $current_type) {
612     # next token
613     $state = 'before typedef rest';
614     } else {
615     # reconsume
616     $state = 'ignore';
617     $nest_level = 0;
618     $next_state = 'before definitions';
619     }
620     } else {
621     $onerror->(type => 'before type', level => $self->{must_level});
622     # reconsume
623     $state = 'ignore';
624     $nest_level = 0;
625     $next_state = 'before definitions';
626     }
627     } elsif ($state eq 'before boxed type') {
628     if ({
629     boolean => 1, octet => 1, float => 1,
630     short => 1, long => 1, unsigned => 1,
631     sequence => 1, '::' => 1, identifier => 1,
632     }->{$token->{type}}) {
633     $current_type = $get_type->();
634     if (defined $current_type) {
635     $current[-1]->type ($current_type);
636     # next token
637     $state = 'before semicolon';
638     $next_state = 'before definitions';
639     } else {
640     shift @current; # valuetype
641     # reconsume
642     $state = 'ignore';
643     $nest_level = 0;
644     $next_state = 'before definitions';
645     }
646     } else {
647     $onerror->(type => 'before boxed type', level => $self->{must_level});
648     shift @current; # valuetype
649     # reconsume
650     $state = 'ignore';
651     $nest_level = 0;
652     $next_state = 'before definitions';
653     }
654     } elsif ($state eq 'before const type') {
655     if ({
656     any => 1, boolean => 1, octet => 1, float => 1,
657     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
658     '::' => 1, identifier => 1,
659     }->{$token->{type}}) {
660     $current_type = $get_type->();
661     if (defined $current_type) {
662     # next token
663     $state = 'before const identifier';
664     } else {
665     # reconsume
666     $state = 'ignore';
667     $nest_level = 0;
668     #$next_state = $next_state;
669     }
670     } else {
671     $onerror->(type => 'before type', level => $self->{must_level});
672     # reconsume
673     $state = 'ignore';
674     $nest_level = 0;
675     #$next_state = $next_state;
676     }
677     } elsif ($state eq 'before typedef rest') {
678     if ($token->{type} eq 'identifier') {
679     ## TODO: unescape
680     push @current, Whatpm::WebIDL::Typedef->new ($token->{value});
681     $current[-1]->type ($current_type);
682     $token = $get_next_token->();
683     $state = 'before semicolon';
684     $next_state = 'before definitions';
685     } elsif ($token->{type} eq 'DOMString') {
686     push @current, Whatpm::WebIDL::Typedef->new ('::DOMString::');
687     $current[-1]->type ($current_type);
688     $token = $get_next_token->();
689     $state = 'before semicolon';
690     $next_state = 'before defnitions';
691     } else {
692     $onerror->(type => 'before typedef rest',
693     level => $self->{must_level});
694     # reconsume
695     $state = 'ignore';
696     $nest_level = 0;
697     $next_state = 'before definitions';
698     }
699     } elsif ($state eq 'before const identifier') {
700     if ($token->{type} eq 'identifier') {
701     ## TODO: unescape
702     push @current, Whatpm::WebIDL::Const->new ($token->{value});
703     $current[-1]->type ($current_type);
704     $token = $get_next_token->();
705     if ($token->{type} eq '=') {
706     $token = $get_next_token->();
707     $state = 'before const expr';
708     next;
709     } else {
710     $onerror->(type => 'const eq', level => $self->{must_level});
711     #
712     }
713     } else {
714     $onerror->(type => 'const identifier', level => $self->{must_level});
715     #
716     }
717     # reconsume
718     $state = 'ignore';
719     $nest_level = 0;
720     #$next_state = $next_state;
721     } elsif ($state eq 'before const expr') {
722     if ($token->{type} eq 'TRUE' or $token->{type} eq 'FALSE') {
723     $current[-1]->value ([$token->{type}]);
724     #
725     } elsif ($token->{type} eq 'integer' or $token->{type} eq 'float') {
726     $current[-1]->value ([$token->{type}, $token->{value}]);
727     #
728     } else {
729     # reconsume
730     $state = 'ignore';
731     $nest_level = 0;
732     #$next_state = $next_state;
733     next;
734     }
735    
736     $token = $get_next_token->();
737     $state = 'before semicolon';
738     #$next_state = $next_state;
739     } elsif ($state eq 'after attribute') {
740     if ({
741     any => 1, boolean => 1, octet => 1, float => 1,
742     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
743     '::' => 1, identifier => 1,
744     }->{$token->{type}}) {
745     $current_type = $get_type->();
746     if (defined $current_type) {
747     # next token
748     $state = 'before attribute identifier';
749     } else {
750     # reconsume
751     $state = 'ignore';
752     $nest_level = 0;
753     $next_state = 'before interface member';
754     }
755     } else {
756     $onerror->(type => 'before type', level => $self->{must_level});
757     # reconsume
758     $state = 'ignore';
759     $nest_level = 0;
760     $next_state = 'before interface member';
761     }
762     } elsif ($state eq 'before operation type') {
763     if ({
764     any => 1, boolean => 1, octet => 1, float => 1,
765     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
766     '::' => 1, identifier => 1,
767     void => 1,
768     }->{$token->{type}}) {
769     $current_type = $get_type->();
770     if (defined $current_type) {
771     # next token
772     $state = 'before operation identifier';
773     } else {
774     # reconsume
775     $state = 'ignore';
776     $nest_level = 0;
777     $next_state = 'before interface member';
778     }
779     } else {
780     $onerror->(type => 'before type', level => $self->{must_level});
781     # reconsume
782     $state = 'ignore';
783     $nest_level = 0;
784     $next_state = 'before interface member';
785     }
786     } elsif ($state eq 'before argument type') {
787     if ({
788     any => 1, boolean => 1, octet => 1, float => 1,
789     DOMString => 1, Object => 1, short => 1, long => 1, unsigned => 1,
790     '::' => 1, identifier => 1,
791     }->{$token->{type}}) {
792     $current_type = $get_type->();
793     if (defined $current_type) {
794     # next token
795     $state = 'before argument identifier';
796     } else {
797     # reconsume
798     pop @current; # operation
799     $state = 'ignore';
800     $nest_level = 0;
801     $next_state = 'before interface member';
802     }
803     } else {
804     $onerror->(type => 'before type', level => $self->{must_level});
805     pop @current; # operation
806     # reconsume
807     $state = 'ignore';
808     $nest_level = 0;
809     $next_state = 'before interface member';
810     }
811     } elsif ($state eq 'before attribute identifier') {
812     if ($token->{type} eq 'identifier') {
813     ## TODO: unescape
814     push @current, Whatpm::WebIDL::Attribute->new ($token->{value});
815     $current[-1]->readonly ($read_only);
816     $current[-1]->type ($current_type);
817     $token = $get_next_token->();
818     if ($token->{type} eq 'getraises') {
819     $token = $get_next_token->();
820     $state = 'after getraises';
821     next;
822     } elsif ($token->{type} eq 'setraises') {
823     $token = $get_next_token->();
824     $state = 'after setraises';
825     next;
826     } else {
827     # reconsume
828     $state = 'before semicolon';
829     $next_state = 'before interface member';
830     next;
831     }
832     } else {
833     $onerror->(type => 'attribute identifier',
834     level => $self->{must_level});
835     #
836     }
837     # reconsume
838     $state = 'ignore';
839     $nest_level = 0;
840     #$next_state = $next_state;
841     } elsif ($state eq 'before operation identifier') {
842     if ($token->{type} eq 'identifier') {
843     ## TODO: unescape
844     push @current, Whatpm::WebIDL::Operation->new ($token->{value});
845     $current[-1]->type ($current_type);
846     $token = $get_next_token->();
847     if ($token->{type} eq '(') {
848     $token = $get_next_token->();
849     if ($token->{type} eq ')') {
850     $token = $get_next_token->();
851     $state = 'before semicolon';
852     $next_state = 'before interface member';
853     next;
854     } else {
855     # reconsume
856     $state = 'before argument';
857     next;
858     }
859     } else {
860     pop @current;
861     $onerror->(type => 'arguments lparen',
862     level => $self->{must_level});
863     #
864     }
865     } else {
866     $onerror->(type => 'operation identifier',
867     level => $self->{must_level});
868     #
869     }
870     # reconsume
871     $state = 'ignore';
872     $nest_level = 0;
873     #$next_state = $next_state;
874     } elsif ($state eq 'before argument identifier') {
875     if ($token->{type} eq 'identifier') {
876     ## TODO: unescape
877     my $arg = Whatpm::WebIDL::Argument->new ($token->{value});
878     $arg->type ($current_type);
879     $current[-1]->append_child ($arg);
880     $token = $get_next_token->();
881     if ($token->{type} eq ')') {
882     $token = $get_next_token->();
883     $state = 'before raises';
884     next;
885     } elsif ($token->{type} eq ',') {
886     $token = $get_next_token->();
887     $state = 'before argument';
888     next;
889     } else {
890     $onerror->(type => 'after argument',
891     level => $self->{must_level});
892     #
893     }
894     } else {
895     $onerror->(type => 'argument identifier',
896     level => $self->{must_level});
897     #
898     }
899     pop @current; # operation
900     # reconsume
901     $state = 'ignore';
902     $nest_level = 0;
903     #$next_state = $next_state;
904     } elsif ($state eq 'before argument') {
905     if ($token->{type} eq '[') {
906     $token = $get_next_token->();
907     $state = 'before xattr';
908     $next_state = 'before argument in';
909     } else {
910     # reconsume
911     $state = 'before argument in';
912     }
913     } elsif ($state eq 'before argument in') {
914     if ($token->{type} eq 'in') {
915     $token = $get_next_token->();
916     $state = 'before argument type';
917     } else {
918     $onerror->(type => 'argument in',
919     level => $self->{must_level});
920     pop @current; # operation
921     $state = 'ignore';
922     $nest_level = 0;
923     $next_state = 'before interface member';
924     }
925     } elsif ($state eq 'before raises') {
926     if ($token->{type} eq 'raises') {
927     $token = $get_next_token->();
928     $state = 'after raises';
929     } else {
930     # reconsume
931     $state = 'before semicolon';
932     $next_state = 'before interface member';
933     }
934     } elsif ($state eq 'after raises') {
935    
936     } elsif ($state eq 'after getraises') {
937    
938     } elsif ($state eq 'after setraises') {
939    
940     } elsif ($state eq 'before semicolon') {
941     if ($token->{type} eq ';') {
942     $current[-2]->append_child ($current[-1]);
943     pop @current;
944     $token = $get_next_token->();
945     $state = {
946     #'before definitions',
947     'before interface member' => 'before members', # keep $next_state
948     'before exception member' => 'before members', # as is
949     }->{$next_state} || $next_state;
950     } else {
951     pop @current;
952     $onerror->(type => 'before semicolon', level => 'm',
953     token => $token);
954     # reconsume
955     $state = 'ignore';
956     $nest_level = 0;
957     $next_state = 'before definitions';
958     }
959     } elsif ($state eq 'ignore') {
960     if (($nest_level == 0 and $token->{type} eq ';') or
961     (@current > 1 and not $nest_level and $token->{type} eq '}')) {
962     $token = $get_next_token->();
963     $state = {
964     #'before definitions',
965     'before interface member' => 'before members', # keep $next_state
966     'before exception member' => 'before members', # as is
967     }->{$next_state} || $next_state;
968     } elsif ($token->{type} eq '{') {
969     $nest_level++;
970     $token = $get_next_token->();
971     # stay in the state
972     } elsif ($nest_level and $token->{type} eq '}') {
973     $nest_level--;
974     $token = $get_next_token->();
975     # stay in the state
976     } elsif ($token->{type} eq 'eof') {
977     last;
978     } else {
979     # ignore the token
980     $token = $get_next_token->();
981     # stay in the state
982     }
983     } else {
984     die "parse_char_string: unkown state: $state";
985     }
986     }
987    
988     if (@current > 1) {
989     $onerror->(type => 'block not closed', level => $self->{must_level});
990     }
991    
992     $get_type = undef; # unlink loop
993    
994     return $defs;
995     } # parse_char_string
996    
997     package Whatpm::WebIDL::Definitions;
998    
999     sub new ($) {
1000     return bless {child_nodes => []}, $_[0];
1001     } # new
1002    
1003     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1004    
1005     sub idl_text ($) {
1006     return join "\x0A", map {$_->idl_text} @{$_[0]->{child_nodes}};
1007     } # idl_text
1008    
1009     package Whatpm::WebIDL::Definition;
1010    
1011     sub new ($$) {
1012     return bless {child_nodes => [], node_name => ''.$_[1]}, $_[0];
1013     } # new
1014    
1015     sub append_child ($$) {
1016     my $self = shift;
1017     my $child = shift;
1018    
1019     ## TODO: child type
1020     ## TODO: parent check
1021    
1022     push @{$self->{child_nodes}}, $child;
1023    
1024     return $child;
1025     } # append_child
1026    
1027     sub node_name ($) {
1028     return $_[0]->{node_name};
1029     } # node_name
1030    
1031     sub idl_text ($) {
1032     return '[[ERROR: ' . (ref $_[0]) . '->idl_text]]';
1033     } # idl_text
1034    
1035     sub type ($;$) {
1036     if (@_ > 1) {
1037     if (defined $_[1]) {
1038     $_[0]->{type} = $_[1];
1039     } else {
1040     $_[0]->{type} = ['::any::'];
1041     }
1042     }
1043     return $_[0]->{type};
1044     } # type
1045    
1046     sub type_text ($) {
1047     my $type = $_[0]->{type};
1048     return undef unless defined $type;
1049    
1050     if ($type->[0] eq '::sequence::') {
1051     return 'sequence<' . (join '::', @{$type->[1]}) . '>'; ## TODO: escape, nested
1052     } else {
1053     return join '::', @$type; ## TODO: escape
1054     }
1055     } # type_text
1056    
1057     package Whatpm::WebIDL::Module;
1058     push our @ISA, 'Whatpm::WebIDL::Definition';
1059    
1060     sub idl_text ($) {
1061     my $r = 'module ' . $_[0]->node_name . "{\x0A\x0A"; ## TODO: escape
1062     for (@{$_[0]->{child_nodes}}) {
1063     $r .= $_->idl_text;
1064     }
1065     $r .= "\x0A};\x0A";
1066     return $r;
1067     } # idl_text
1068    
1069     package Whatpm::WebIDL::Interface;
1070     push our @ISA, 'Whatpm::WebIDL::Definition';
1071    
1072     sub new ($$) {
1073     my $self = shift->SUPER::new (@_);
1074     $self->{inheritances} = [];
1075     return $self;
1076     } # new
1077    
1078     sub append_inheritance ($$) {
1079     my $self = shift;
1080     my $scoped_name = shift;
1081     push @{$self->{inheritances}}, $scoped_name;
1082     } # append_inheritance
1083    
1084     sub idl_text ($) {
1085     my $r = 'interface ' . $_[0]->node_name . "{\x0A"; ## TODO: escape
1086     for (@{$_[0]->{child_nodes}}) { ## TODO: inheritances
1087     $r .= ' ' . $_->idl_text;
1088     }
1089     $r .= "};\x0A";
1090     return $r;
1091     } # idl_text
1092    
1093     package Whatpm::WebIDL::Exception;
1094     push our @ISA, 'Whatpm::WebIDL::Definition';
1095    
1096     package Whatpm::WebIDL::Typedef;
1097     push our @ISA, 'Whatpm::WebIDL::Definition';
1098    
1099     sub new ($$) {
1100     my $self = shift->SUPER::new (@_);
1101     $self->{type} = ['::any::'];
1102     return $self;
1103     } # new
1104    
1105     sub idl_text ($) {
1106     ## TODO: escape
1107     return 'typedef ' . $_[0]->type_text . ' ' . $_[0]->node_name . ";\x0A";
1108     } # idl_text
1109    
1110     package Whatpm::WebIDL::Valuetype;
1111     push our @ISA, 'Whatpm::WebIDL::Definition';
1112    
1113     sub new ($$) {
1114     my $self = shift->SUPER::new (@_);
1115     $self->{type} = ['::boolean::'];
1116     return $self;
1117     } # new
1118    
1119     sub idl_text ($) {
1120     ## TODO: escape
1121     return 'valuetype ' . $_[0]->node_name . ' ' . $_[0]->type_text . ";\x0A";
1122     } # idl_text
1123    
1124     package Whatpm::WebIDL::InterfaceMember;
1125    
1126     sub new ($$) {
1127     return bless {node_name => ''.$_[1]}, $_[0];
1128     } # new
1129    
1130     *idl_text = \&Whatpm::WebIDL::Definition::idl_text;
1131    
1132     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1133    
1134     *type = \&Whatpm::WebIDL::Definition::type;
1135    
1136     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1137    
1138     package Whatpm::WebIDL::Const;
1139     push our @ISA, 'Whatpm::WebIDL::Definition', 'Whatpm::WebIDL::InterfaceMember';
1140    
1141     sub new ($$) {
1142     my $self = shift->SUPER::new (@_); # Definition->new should be called
1143     $self->{type} = ['::boolean::'];
1144     $self->{value} = ['FALSE'];
1145     return $self;
1146     } # new
1147    
1148     sub value ($;$) {
1149     if (@_ > 1) {
1150     $_[0]->{value} = $_[1];
1151     }
1152    
1153     return $_[0]->{value};
1154     } # value
1155    
1156     sub value_text ($) {
1157     my $value = $_[0]->{value};
1158    
1159     if ($value->[0] eq 'TRUE' or $value->[0] eq 'FALSE') {
1160     return $value->[0];
1161     } elsif ($value->[0] eq 'integer' or $value->[0] eq 'float') {
1162     ## TODO: format
1163     return $value->[1];
1164     } else {
1165     return undef;
1166     }
1167     } # value_text
1168    
1169     sub idl_text ($) {
1170     return 'const ' . $_[0]->type_text . ' ' . $_[0]->node_name . ' = ' . $_[0]->value_text . ";\x0A"; ## TODO: escape
1171     } # idl_text
1172    
1173     package Whatpm::WebIDL::Attribute;
1174     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1175    
1176     sub new ($$) {
1177     my $self = shift->SUPER::new (@_);
1178     $self->{type} = ['::any::'];
1179     return $self;
1180     } # new
1181    
1182     sub readonly ($;$) {
1183     if (@_ > 1) {
1184     $_[0]->{readonly} = $_[1];
1185     }
1186    
1187     return $_[0]->{readonly};
1188     } # readonly
1189    
1190     sub idl_text ($) {
1191     return (($_[0]->readonly ? 'readonly ' : '') . 'attribute ' . $_[0]->type_text . ' ' . $_[0]->node_name . ";\x0A");
1192     ## TODO: escape
1193     ## TODO: raises
1194     } # idl_text
1195    
1196     package Whatpm::WebIDL::Operation;
1197     push our @ISA, 'Whatpm::WebIDL::InterfaceMember';
1198    
1199     sub new ($$) {
1200     my $self = shift->SUPER::new (@_);
1201     $self->{type} = ['::any::'];
1202     $self->{child_nodes} = [];
1203     return $self;
1204     } # new
1205    
1206     *append_child = \&Whatpm::WebIDL::Definition::append_child;
1207    
1208     sub idl_text ($) {
1209     my $r = $_[0]->type_text . ' ' . $_[0]->node_name . ' ('; ## TODO: escape
1210     $r .= join ', ', map {$_->idl_text} @{$_[0]->{child_nodes}};
1211     $r .= ')'; ## TODO: raises
1212     $r .= ";\x0A";
1213     return $r;
1214     } # idl_text
1215    
1216     package Whatpm::WebIDL::Argument;
1217    
1218     sub new ($$) {
1219     return bless {node_name => ''.$_[1], type => ['::any::']}, $_[0];
1220     } # new
1221    
1222     sub idl_text ($) {
1223     return 'in ' . $_[0]->type_text . ' ' . $_[0]->node_name; ## TODO: escape
1224     } # idl_text
1225    
1226     *node_name = \&Whatpm::WebIDL::Definition::node_name;
1227    
1228     *type = \&Whatpm::WebIDL::Definition::type;
1229    
1230     *type_text = \&Whatpm::WebIDL::Definition::type_text;
1231    
1232     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24