/[suikacvs]/messaging/manakai/bin/dis2pm.pl
Suika

Contents of /messaging/manakai/bin/dis2pm.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download)
Mon Nov 1 07:58:34 2004 UTC (20 years ago) by wakaba
Branch: MAIN
CVS Tags: before-dis2-200411
Changes since 1.3: +65 -29 lines
File MIME type: text/plain
Make pod separatable

1 wakaba 1.1 #!/usr/bin/perl -w
2    
3     =head1 NAME
4    
5     dis2pm.pl - Manakai DOM Perl Module Generator
6    
7     =head1 SYNOPSIS
8    
9     perl dis2pm.pl Foo.dis > Foo.pm
10    
11     =head1 DESCRIPTION
12    
13     B<dis2pm> generates a Perl module file (*.pm) that implements
14     DOM (Document Object Model) interfaces from a "dis"
15     (DOM implementation source) file.
16    
17     This script is part of manakai.
18    
19     =cut
20    
21     use strict;
22     use lib qw<lib ../lib>;
23     use Message::Markup::SuikaWikiConfig20::Parser;
24     use Message::Markup::XML::QName qw/DEFAULT_PFX/;
25     use Message::Util::QName::General [qw/ExpandedURI/], {
26     DOMCore => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/dom-core#>,
27     DOMMain => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/dom-core#>,
28     infoset => q<http://www.w3.org/2001/04/infoset#>,
29     lang => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#>,
30     Perl => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#Perl-->,
31     license => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/license#>,
32     ManakaiDOM => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/manakai-dom#>,
33     MDOM_EXCEPTION => q<http://suika.fam.cx/~wakaba/archive/2004/8/4/manakai-dom-exception#>,
34     xml => q<http://www.w3.org/XML/1998/namespace>,
35     xmlns => q<http://www.w3.org/2000/xmlns/>,
36     };
37     my $ManakaiDOMModulePrefix = q<Message::DOM>;
38     my $MAX_DOM_LEVEL = 3;
39    
40 wakaba 1.4 use Getopt::Long;
41     my %Opt;
42     GetOptions (
43     'help' => \$Opt{help},
44     'output-pod=s' => \$Opt{output_pod},
45     'output-pod-file=s' => \$Opt{output_pod_file},
46     ) or pod2usage (2);
47     if ($Opt{help}) {
48     pod2usage (0);
49     exit;
50     } elsif (($Opt{output_pod} ||= 'no') eq 'file' and
51     not defined $Opt{output_pod_file}) {
52     pod2usage (2);
53     exit 2;
54     }
55    
56 wakaba 1.1 my $s;
57     {
58     local $/ = undef;
59     $s = <>;
60     }
61     my $source = Message::Markup::SuikaWikiConfig20::Parser->parse_text ($s);
62     my $Info = {};
63     my $Status = {package => 'main', depth => 0, generated_fragment => 0};
64     our $result = '';
65 wakaba 1.4 my $result_pod;
66 wakaba 1.1
67     BEGIN {
68     require 'manakai/genlib.pl';
69     }
70    
71 wakaba 1.4 if ($Opt{output_pod} eq 'no') {
72     eval q{
73     sub pod_block (@) {
74     return '';
75     }
76     };
77     } elsif ($Opt{output_pod} eq 'only' or
78     $Opt{output_pod} eq 'file') {
79     eval q{
80     sub pod_block (@) {
81     my @v = grep ((defined and length), @_);
82     $result_pod .= join "\n\n", '', ($v[0] =~ /^=/ ? () : '=pod'), @v,
83     '=cut', '';
84     return '';
85     }
86     };
87     }
88    
89 wakaba 1.1 sub perl_package_name (%) {
90     my %opt = @_;
91     my $r;
92     if ($opt{if}) {
93     $r = $ManakaiDOMModulePrefix . q<::IF::> . perl_name $opt{if};
94     } elsif ($opt{iif}) {
95     $r = $ManakaiDOMModulePrefix . q<::IIF::> . perl_name $opt{iif};
96     } elsif ($opt{name} or $opt{name_with_condition}) {
97     if ($opt{name_with_condition}) {
98     if ($opt{name_with_condition} =~ /^([^:]+)::([^:]+)$/) {
99     $opt{name} = $1;
100     $opt{condition} = $2;
101     } else {
102     $opt{name} = $opt{name_with_condition};
103     }
104     }
105     $opt{name} = perl_name $opt{name};
106     $opt{name} = $opt{prefix} . '::' . $opt{name} if $opt{prefix};
107     $r = $ManakaiDOMModulePrefix . q<::> . $opt{name};
108     } elsif ($opt{qname} or $opt{qname_with_condition}) {
109     if ($opt{qname_with_condition}) {
110     if ($opt{qname_with_condition} =~ /^(.+)::([^:]*)$/) {
111     $opt{qname} = $1;
112     $opt{condition} = $2;
113     } else {
114     $opt{qname} = $opt{qname_with_condition};
115     }
116     }
117     if ($opt{qname} =~ /^([^:]*):(.*)$/) {
118     $opt{ns_prefix} = $1;
119     $opt{name} = $2;
120     } else {
121     $opt{ns_prefix} = DEFAULT_PFX;
122     $opt{name} = $opt{qname};
123     }
124     ## ISSUE: Prefix to ...
125     #$r = ns_uri_to_perl_package_name (ns_prefix_to_uri ($opt{ns_prefix})) .
126     # '::' . $opt{name};
127     $r = $ManakaiDOMModulePrefix . '::' . $opt{name};
128     } elsif ($opt{if_qname} or $opt{if_qname_with_condition}) {
129     if ($opt{if_qname_with_condition}) {
130     if ($opt{if_qname_with_condition} =~ /^(.+)::([^:]*)$/) {
131     $opt{if_qname} = $1;
132     $opt{condition} = $2;
133     } else {
134     $opt{if_qname} = $opt{if_qname_with_condition};
135     }
136     }
137     if ($opt{if_qname} =~ /^([^:]*):(.*)$/) {
138     $opt{ns_prefix} = $1;
139     $opt{name} = $2;
140     } else {
141     $opt{ns_prefix} = DEFAULT_PFX;
142     $opt{name} = $opt{if_qname};
143     }
144     ## ISSUE: Prefix to ...
145     #$r = ns_uri_to_perl_package_name (ns_prefix_to_uri ($opt{ns_prefix})) .
146     # '::' . $opt{name};
147     $r = $ManakaiDOMModulePrefix . '::IF::' . $opt{name};
148     } elsif ($opt{full_name}) {
149     $r = $opt{full_name};
150     } else {
151     valid_err q<$opt{name} is false>;
152     }
153     if ($opt{condition}) {
154     $r = $r . '::' . perl_name $opt{condition};
155     }
156     if ($opt{is_internal}) {
157     $r .= '::_internal';
158     $r .= '_inherit' if $opt{is_for_inheriting};
159     }
160     $r;
161     }
162    
163     sub perl_package (%) {
164     my $fn = perl_package_name @_;
165     unless ($fn eq $Status->{package}) {
166     $Status->{package} = $fn;
167     return perl_statement qq<package $fn>;
168     } else {
169     return '';
170     }
171     }
172    
173     sub perl_exception (@) {
174     my %opt = @_;
175     if ($opt{class} !~ /:/) {
176     $opt{class} = perl_package_name name => $opt{class};
177     } else {
178     $opt{class} = perl_package_name full_name => $opt{class};
179     }
180     my @param = (-type => $opt{type},
181     -object => perl_code_literal ('$self'));
182     if (ref $opt{param}) {
183     push @param, %{$opt{param}};
184     } elsif ($opt{param}) {
185     push @param, perl_code_literal ($opt{param});
186     }
187     if ($opt{subtype} or $opt{subtype_uri}) {
188     my $uri = $opt{subtype_uri} || expanded_uri ($opt{subtype});
189     push @param, ExpandedURI q<MDOM_EXCEPTION:subtype> => $uri;
190     }
191     q<report > . $opt{class} . q< > . perl_list @param;
192     }
193    
194    
195     {
196     use re 'eval';
197     my $RegBlockContent;
198     $RegBlockContent = qr/(?>[^{}\\]*)(?>(?>[^{}\\]+|\\.|\{(??{$RegBlockContent})\})*)/s;
199     ## Defined by genlib.pl but overridden.
200     sub perl_code ($;%) {
201     my ($s, %opt) = @_;
202     valid_err q<Uninitialized value in perl_code>,
203     node => $opt{node} unless defined $s;
204     $s =~ s[<Q:([^<>]+)>|\b(null|true|false)\b][
205     my ($q, $l) = ($1, $2);
206     if (defined $q) {
207     if ($q =~ /\}/) {
208     valid_warn qq<Possible typo in the QName: "$q">;
209     }
210     perl_literal (expanded_uri ($q));
211     } else {
212     {true => 1, false => 0, null => 'undef'}->{$l};
213     }
214     ]ge;
215     ## TODO: Ensure Message::Util::Error imported if try.
216     ## ISSUE: __FILE__ & __LINE__ will break if multiline substition happens.
217     $s =~ s{
218     \b__([A-Z]+)
219     (?:\{($RegBlockContent)\})?
220     __\b
221     }{
222     my ($name, $data) = ($1, $2);
223     my $r;
224     if ($name eq 'CLASS' or ## Manakai DOM Class
225     $name eq 'SUPER' or ## Manakai DOM Class (internal)
226     $name eq 'IIF' or ## DOM Interface + Internal interface & prop
227     $name eq 'IF') { ## DOM Interface
228     local $Status->{condition} = $Status->{condition};
229     if ($data =~ s/::([^:]*)$//) {
230     $Status->{condition} = $1;
231     }
232     $r = perl_package_name {qw/CLASS name SUPER name IIF iif IF if/}->{$name}
233     => $data,
234     is_internal => {qw/SUPER 1/}->{$name},
235     condition => $Status->{condition};
236     } elsif ($name eq 'INT') { ## Internal Method / Attr Name
237     if (defined $data) {
238     if ($data =~ /^{($RegBlockContent)}$/o) {
239     $data = $1;
240     my $name = $1 if $data =~ s/^\s*(\w+)\s*(?:$|:\s*)// or
241     valid_err qq<Syntax of preprocessing macro "INT" is invalid>,
242     node => $opt{node};
243     local $Status->{preprocess_variable}
244     = {%{$Status->{preprocess_variable}||{}}};
245     while ($data =~ /\G(\S+)\s*(?:=>\s*(\S+)\s*)?(?:,\s*|$)/g) {
246     my ($n, $v) = ($1, defined $2 ? $2 : 1);
247     for ($n, $v) {
248     s/^'([^']+)'$/$1/; ## ISSUE: Doesn't support quoted-'
249     }
250     $Status->{preprocess_variable}->{$n} = $v;
251     }
252     valid_err q<Preprocessing macro INT{} cannot be used here>
253     unless $opt{internal};
254     $r = perl_comment ("INT: $name").
255     $opt{internal}->($name);
256     } elsif ($data =~ s/^SP://) {
257     $r = '___'.$data;
258     } else {
259     $r = perl_internal_name $data;
260     }
261     } else {
262     valid_err q<Preprocessing macro INT cannot be used here>
263     unless $opt{internal};
264     $r = $opt{internal}->();
265     }
266     } elsif ($name eq 'DEEP') { ## Deep Method Call
267     $r = 'do { local $Error::Depth = $Error::Depth + 1;' . perl_code ($data) .
268     '}';
269     } elsif ($name eq 'EXCEPTION' or $name eq 'WARNING') {
270     ## Raising an Exception or Warning
271     if ($data =~ s/^\s*(\w+)\s*\.\s*(\w+)\s*(?:\.\s*([\w:]+)\s*)?(?:::\s*|$)//) {
272     $r = perl_exception (level => $name,
273     class => $1,
274     type => $2,
275     subtype => $3,
276     param => perl_code $data);
277     } else {
278     valid_err qq<Exception type and name required: "$data">,
279     node => $opt{node};
280     }
281     } elsif ($name eq 'CODE') { # Built-in code
282     my ($nm, %param);
283     if ($data =~ s/^(\w+)\s*(?::\s*|$)//) {
284     $nm = $1;
285     } elsif ($data =~ s/^<([^<>]+)>\s*(?::\s*|$)//) {
286     $nm = $1;
287     } else {
288     valid_err q<Built-in code name required>;
289     }
290     while ($data =~ /\G(\S+)\s*=>\s*(\S+)\s*(?:,\s*|$)/g) {
291     $param{$1} = $2;
292     }
293     $r = perl_builtin_code ($nm, condition => $opt{condition}, %param);
294     } elsif ($name eq 'PACKAGE' and $data) {
295     if ($data eq 'Global') {
296     $r = $ManakaiDOMModulePrefix;
297     } else {
298     valid_err qq<PACKAGE "$data" not supported>;
299     }
300     } elsif ($name eq 'REQUIRE') {
301     $r = perl_statement (q<require >. perl_package_name name => $data);
302     } elsif ($name eq 'WHEN') {
303     if ($data =~ s/^\s*IS\s*\{($RegBlockContent)\}::\s*//o) {
304     my $v = $1;
305     if ($v =~ /^\s*'([^']+)'\s*$/) { ## ISSUE: Doesn't support quoted-'
306     if ($Status->{preprocess_variable}->{$1}) {
307     $r = perl_code ($data, %opt);
308     } else {
309     $r = perl_comment ($data);
310     }
311     } else {
312     valid_err qq<WHEN-IS condition "$v" is invalid>,
313     node => $opt{node};
314     }
315     } else {
316     valid_err qq<Syntax for preprocessing macro "WHEN" is invalid>,
317     node => $opt{node};
318     }
319     } elsif ($name eq 'FILE' or $name eq 'LINE' or $name eq 'PACKAGE') {
320     $r = qq<__${name}__>;
321     } else {
322     valid_err qq<Preprocessing macro "$name" not supported>;
323     }
324     $r;
325     }goex;
326     $s;
327     }
328     }
329    
330     ## Defined in genlib.pl but overridden.
331     sub perl_code_source ($%) {
332     my ($s, %opt) = @_;
333     sprintf qq<\n#line %d "File <%s> Node <%s>"\n%s\n> .
334     qq<#line 1 "File <%s> Chunk #%d"\n>,
335     $opt{line} || 1, $opt{file} || $Info->{source_filename},
336     $opt{path} || 'x:unknown ()', $s,
337     $opt{file} || $Info->{source_filename}, ++$Status->{generated_fragment};
338     }
339    
340     sub perl_builtin_code ($;%);
341     sub perl_builtin_code ($;%) {
342     my ($name, %opt) = @_;
343     $opt{condition} ||= $Status->{condition};
344     my $r;
345     if ($name eq 'DOMString') {
346     $name = $1 if $name =~ /(\w+)$/;
347     $r = q{
348     if (defined $arg) {
349     if (ref $arg) {
350     if (ref $arg eq 'SCALAR') {
351     $r = bless {value => $$arg}, $self;
352     } elsif ($arg->isa ('IF')) {
353     $r = $arg;
354     } else {
355     $r = bless {value => ''.$arg}, $self;
356     }
357     } else {
358     $r = bless {value => $arg}, $self;
359     }
360     } else {
361     $r = undef; # null
362     }
363     };
364     $r =~ s/'IF'/perl_literal (perl_package_name (if => $name))/ge;
365     $r =~ s/\$self\b/perl_literal (perl_package_name (name => $name))/ge;
366     $opt{s} or valid_err q<Built-in code parameter "s" required>;
367     $r =~ s/\$arg\b/\$$opt{s}/g;
368     $opt{r} or valid_err q<Built-in code parameter "r" required>;
369     $r =~ s/\$r\b/\$$opt{r}/g;
370     $r =~ s/\$$opt{r} = \$$opt{s};/#/g if $opt{r} eq $opt{s};
371     } elsif (type_isa ($name, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>)) {
372     $r = perl_statement perl_exception
373     (level => 'WARNING',
374     class => 'ManakaiDOMImplementationWarning',
375     type => 'MDOM_NS_EMPTY_URI',
376     param => {
377     ExpandedURI q<MDOM_EXCEPTION:param-name> => $opt{s},
378     });
379     if ($opt{condition} and $opt{condition} ne 'DOM2') {
380     $r .= perl_statement q<$out = undef>;
381     }
382     $r = perl_if (q<defined $in and $in eq ''>, $r);
383     $opt{s} or valid_err q<Built-in code parameter "s" required>;
384     $r =~ s/\$in\b/\$$opt{s}/g;
385     $opt{r} or valid_err q<Built-in code parameter "r" required>;
386     $r =~ s/\$out\b/\$$opt{r}/g;
387     } elsif ($name eq 'UniqueID') {
388     $r = q{(
389     sprintf 'mid:%d.%d.%s.dom.manakai@suika.fam.cx',
390     time, $$,
391     ['A'..'Z', 'a'..'z', '0'..'9']->[rand 62] .
392     ['A'..'Z', 'a'..'z', '0'..'9']->[rand 62] .
393     ['A'..'Z', 'a'..'z', '0'..'9']->[rand 62] .
394     ['A'..'Z', 'a'..'z', '0'..'9']->[rand 62] .
395     ['A'..'Z', 'a'..'z', '0'..'9']->[rand 62]
396     )};
397     ## TODO: Check as HTML Name if not XML.
398     } elsif ($name eq 'CheckQName') {
399     $opt{version} = '1.0' if $opt{condition} and $opt{condition} eq 'DOM2';
400     my $chk = perl_if
401     (qq<##CHKNAME##>, undef,
402     (perl_statement
403     perl_exception
404     (class => 'DOMException',
405     type => 'INVALID_CHARACTER_ERR',
406     subtype_uri =>
407     ExpandedURI q<MDOM_EXCEPTION:MDOM_BAD_NAME>,
408     param => {
409     ExpandedURI q<DOMCore:name>
410     => perl_code_literal
411     (perl_var type => '$', local_name => 'qname'),
412     }))) .
413     perl_if
414     (qq<##CHKQNAME##>, undef,
415     (perl_statement
416     perl_exception
417     (class => 'DOMException',
418     type => 'NAMESPACE_ERR',
419     subtype_uri =>
420     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_MALFORMED_QNAME>,
421     param => {
422     ExpandedURI q<DOMCore:qualifiedName>
423     => perl_code_literal
424     (perl_var type => '$', local_name => 'qname'),
425     })));
426     my $chk10 = $chk;
427     $chk10 =~ s{##CHKNAME##}
428     {q<$qname =~ /\A\p{InXML_NameStartChar10}>.
429     q<\p{InXMLNameChar10}*\z/>}ge;
430     $chk10 =~ s{##CHKQNAME##}
431     {q<$qname =~ /\A\p{InXML_NCNameStartChar10}>.
432     q<\p{InXMLNCNameChar10}*>.
433     q<(?::\p{InXML_NCNameStartChar10}>.
434     q<\p{InXMLNCNameChar10}*)?\z/>}ge;
435     my $chk11 = $chk;
436     $chk11 =~ s{##CHKNAME##}
437     {q<$qname =~ /\A\p{InXMLNameStartChar11}>.
438     q<\p{InXMLNameChar11}*\z/>}ge;
439     $chk11 =~ s{##CHKQNAME##}
440     {q<$qname =~ /\A\p{InXMLNCNameStartChar11}>.
441     q<\p{InXMLNCNameChar11}*>.
442     q<(?::\p{InXMLNCNameStartChar11}>.
443     q<\p{InXMLNCNameChar11}*)?\z/>}ge;
444     my %class;
445     if ($opt{version} and $opt{version} eq '1.0') {
446     $r = $chk10;
447     %class = (qw/InXML_NameStartChar10 InXMLNameChar10
448     InXML_NCNameStartChar10 InXMLNCNameChar10/);
449     } elsif ($opt{version} and $opt{version} eq '1.1') {
450     $r = $chk11;
451     %class = (qw/InXMLNameStartChar11 InXMLNameChar11
452     InXMLNCNameStartChar11 InXMLNCNameChar11/);
453     } elsif ($opt{version}) {
454     $r = perl_if (q<defined >.
455     perl_var (type => '$', local_name => $opt{version}) .
456     q< and >.
457     perl_var (type => '$', local_name => $opt{version}) .
458     q< eq '1.1'>, $chk11, $chk10);
459     %class = (qw/InXML_NameStartChar10 InXMLNameChar10
460     InXML_NCNameStartChar10 InXMLNCNameChar10
461     InXMLNameStartChar11 InXMLNameChar11
462     InXMLNCNameStartChar11 InXMLNCNameChar11/);
463     } else {
464     valid_err q<Built-in code parameter "version" required>;
465     }
466     $opt{qname} or valid_err q<Built-in code parameter "qname" required>;
467     $r =~ s/\$qname\b/\$$opt{qname}/g;
468     $Info->{Require_perl_package_use}->{'Char::Class::XML'} or
469     valid_err q<"Char::Class::XML" must be "Require"d in the interface >.
470     qq{"$Status->{IF}", condition "$Status->{condition}"};
471     for (%class) {
472     $Info->{Require_perl_package_use}->{'Char::Class::XML::::Import'}->{$_} or
473     valid_err qq<"$_" must be exported from "Char::Class::XML" in the >.
474     qq{interface "$Status->{IF}", condition }.
475     qq{"$Status->{condition}"};
476     }
477     } elsif ($name eq 'CheckNCName') {
478     $opt{version} = '1.0' if $opt{condition} and $opt{condition} eq 'DOM2';
479     my $chk = perl_if
480     (qq<##CHKNAME##>, undef,
481     (perl_statement
482     perl_exception
483     (class => 'DOMException',
484     type => 'INVALID_CHARACTER_ERR',
485     subtype_uri =>
486     ExpandedURI q<MDOM_EXCEPTION:MDOM_BAD_NAME>,
487     param => {
488     ExpandedURI q<DOMCore:name>
489     => perl_code_literal
490     (perl_var type => '$', local_name => 'qname'),
491     }))) .
492     perl_if
493     (qq<##CHKNCNAME##>, undef,
494     (perl_statement
495     perl_exception
496     (class => 'DOMException',
497     type => 'NAMESPACE_ERR',
498     subtype_uri =>
499     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_BAD_NCNAME>,
500     param => {
501     ExpandedURI q<infoset:name>
502     => perl_code_literal
503     (perl_var type => '$', local_name => 'qname'),
504     })));
505     my $chk10 = $chk;
506     $chk10 =~ s{##CHKNAME##}
507     {q<$qname =~ /\A\p{InXML_NameStartChar10}>.
508     q<\p{InXMLNameChar10}*\z/>}ge;
509     $chk10 =~ s{##CHKNCNAME##}
510     {q<$qname =~ /:/>}ge;
511     my $chk11 = $chk;
512     $chk11 =~ s{##CHKNAME##}
513     {q<$qname =~ /\A\p{InXMLNameStartChar11}>.
514     q<\p{InXMLNameChar11}*\z/>}ge;
515     $chk11 =~ s{##CHKNCNAME##}
516     {q<$qname =~ /:/>}ge;
517     my $t = ($opt{empty} and $opt{empty} eq 'warn3' and
518     (not $opt{condition} or $opt{condition} ne 'DOM2')) ?
519     perl_if
520     (q<defined $qname and $qname eq q<>>,
521     perl_statement (perl_exception
522     (level => 'WARNING',
523     class => 'ManakaiDOMImplementationWarning',
524     type => 'MDOM_NS_EMPTY_PREFIX',
525     param => {
526     ExpandedURI q<MDOM_EXCEPTION:param-name> => $opt{ncname},
527     })).
528     perl_statement (q<$qname = undef>)) : '';
529     my %class;
530     if ($opt{version} and $opt{version} eq '1.0') {
531     $r = $chk10;
532     %class = (qw/InXML_NameStartChar10 InXMLNameChar10/);
533     } elsif ($opt{version} and $opt{version} eq '1.1') {
534     $r = $chk11;
535     %class = (qw/InXMLNameStartChar11 InXMLNameChar11/);
536     } elsif ($opt{version}) {
537     $r = perl_if (q<defined >.
538     perl_var (type => '$', local_name => $opt{version}) .
539     q< and >.
540     perl_var (type => '$', local_name => $opt{version}) .
541     q< eq '1.1'>, $chk11, $chk10);
542     %class = (qw/InXML_NameStartChar10 InXMLNameChar10
543     InXMLNameStartChar11 InXMLNameChar11/);
544     } else {
545     valid_err q<Built-in code parameter "version" required>;
546     }
547     $r = $t . $r;
548     $opt{ncname} or valid_err q<Built-in code parameter "ncname" required>;
549     $r =~ s/\$qname\b/\$$opt{ncname}/g;
550     $Info->{Require_perl_package_use}->{'Char::Class::XML'} or
551     valid_err q<"Char::Class::XML" must be "Require"d in the interface >.
552     qq{"$Status->{IF}", condition "$Status->{condition}"};
553     for (%class) {
554     $Info->{Require_perl_package_use}->{'Char::Class::XML::::Import'}->{$_} or
555     valid_err qq<"$_" must be exported from "Char::Class::XML" in the >.
556     qq{interface "$Status->{IF}", condition }.
557     qq{"$Status->{condition}"};
558     }
559     } elsif ($name eq 'CheckName') {
560     $opt{version} = '1.0' if $opt{condition} and
561     ($opt{condition} eq 'DOM2' or
562     $opt{condition} eq 'DOM1');
563     my $chk = perl_if
564     (qq<##CHKNAME##>, undef,
565     (perl_statement
566     perl_exception
567     (class => 'DOMException',
568     type => 'INVALID_CHARACTER_ERR',
569     subtype_uri =>
570     ExpandedURI q<MDOM_EXCEPTION:MDOM_BAD_NAME>,
571     param => {
572     ExpandedURI q<DOMCore:name>
573     => perl_code_literal
574     (perl_var type => '$', local_name => 'qname'),
575     })));
576     my $chk10 = $chk;
577     $chk10 =~ s{##CHKNAME##}
578     {q<$qname =~ /\A\p{InXML_NameStartChar10}>.
579     q<\p{InXMLNameChar10}*\z/>}ge;
580     my $chk11 = $chk;
581     $chk11 =~ s{##CHKNAME##}
582     {q<$qname =~ /\A\p{InXMLNameStartChar11}>.
583     q<\p{InXMLNameChar11}*\z/>}ge;
584     my %class;
585    
586     if ($opt{version} and $opt{version} eq '1.0') {
587     $r = $chk10;
588     %class = (qw/InXML_NameStartChar10 InXMLNameChar10/);
589     } elsif ($opt{version} and $opt{version} eq '1.1') {
590     $r = $chk11;
591     %class = (qw/InXMLNameStartChar11 InXMLNameChar11/);
592     } elsif ($opt{version}) {
593     $r = perl_if (q<defined >.
594     perl_var (type => '$', local_name => $opt{version}) .
595     q< and >.
596     perl_var (type => '$', local_name => $opt{version}) .
597     q< eq '1.1'>, $chk11, $chk10);
598     %class = (qw/InXML_NameStartChar10 InXMLNameChar10
599     InXMLNameStartChar11 InXMLNameChar11/);
600     } else {
601     valid_err q<Built-in code parameter "version" required>;
602     }
603     $opt{name} or valid_err q<Built-in code parameter "name" required>;
604     $r =~ s/\$qname\b/\$$opt{name}/g;
605     $Info->{Require_perl_package_use}->{'Char::Class::XML'} or
606     valid_err q<"Char::Class::XML" must be "Require"d in the interface >.
607     qq{"$Status->{IF}", condition "$Status->{condition}"};
608     for (%class) {
609     $Info->{Require_perl_package_use}->{'Char::Class::XML::::Import'}->{$_} or
610     valid_err qq<"$_" must be exported from "Char::Class::XML" in the >.
611     qq{interface "$Status->{IF}", condition }.
612     qq{"$Status->{condition}"};
613     }
614     } elsif ($name eq 'CheckNull') {
615     $r = perl_code q{
616     __EXCEPTION{
617     ManakaiDOMImplementationException.PARAM_NULL_POINTER::
618     <Q:MDOM_EXCEPTION:param-name> => 'arg',
619     }__ unless defined $arg;
620     };
621     $opt{s} or valid_err q<Built-in code parameter "s" required>;
622     $r =~ s/\$arg\b/\$$opt{s}/g;
623     $r =~ s/'arg'/perl_literal ($opt{s})/ge;
624     } elsif ($name eq 'XMLVersion') {
625     $r = perl_code q{
626     $r = defined $node->{<Q:DOMCore:hasFeature>}->{XML} ?
627     defined $node->{<Q:infoset:version>} ?
628     $node->{<Q:infoset:version>} : '1.0' : null;
629     };
630     $opt{docNode} or valid_err q<Built-in code parameter "docNode" required>;
631     $r =~ s/\$node\b/\$$opt{docNode}/g;
632     $opt{out} or valid_err q<Built-in code parameter "out" required>;
633     $r =~ s/\$r\b/\$$opt{out}/g;
634     } elsif ($name eq 'XMLNS') {
635     for (qw/docNode namespaceURI qualifiedName out-version
636     out-prefix out-localName/) {
637     $opt{$_} or valid_err qq<Built-in code parameter "$_" required>,
638     node => $opt{node};
639     }
640    
641     ## Check the Document XML version
642     ## - The Document must support the "XML" feature
643     $r = perl_builtin_code ('XMLVersion', %opt,
644     out => $opt{'out-version'},
645     docNode => $opt{docNode});
646     $r .= perl_if
647     (q<defined >.perl_var (type => '$',
648     local_name => $opt{'out-version'}),
649     undef,
650     perl_statement
651     perl_exception
652     (type => 'NOT_SUPPORTED_ERR',
653     class => 'DOMException',
654     subtype_uri =>
655     ExpandedURI q<MDOM_EXCEPTION:MDOM_DOC_NOSUPPORT_XML>));
656    
657     ## Check the QName
658     $r .= perl_builtin_code ('CheckQName', %opt,
659     qname => $opt{qualifiedName},
660     version => $opt{'out-version'});
661    
662     ## Split QName into prefix and local name
663     my $prefix = perl_var (type => '$', local_name => $opt{'out-prefix'});
664     my $lname = perl_var (type => '$', local_name => $opt{'out-localName'});
665     my $nsURI = perl_var (type => '$', local_name => $opt{namespaceURI});
666     $r .= qq{($prefix, $lname) = split /:/, \$$opt{qualifiedName}, 2;
667     ($prefix, $lname) = (undef, $prefix) unless defined $lname;};
668    
669     ## Check namespace binding
670     $r .= perl_if
671     (qq<defined $prefix>,
672     perl_cases (
673     qq<not defined $nsURI>,
674     => perl_statement
675     (perl_exception
676     (type => 'NAMESPACE_ERR',
677     class => 'DOMException',
678     subtype_uri =>
679     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_PREFIX_WITH_NULL_URI>,
680     param => {
681     ExpandedURI q<infoset:prefix> =>
682     perl_code_literal ($prefix),
683     })),
684     qq<$prefix eq 'xml' and $nsURI ne >.
685     perl_literal (ExpandedURI q<xml:>)
686     => perl_statement
687     (perl_exception
688     (type => 'NAMESPACE_ERR',
689     class => 'DOMException',
690     subtype_uri =>
691     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_XML_WITH_OTHER_URI>,
692     param => {
693     ExpandedURI q<infoset:namespaceName> =>
694     perl_code_literal ($nsURI),
695     })),
696     qq<$prefix eq 'xmlns' and $nsURI ne >.
697     perl_literal (ExpandedURI q<xmlns:>)
698     => perl_statement
699     (perl_exception
700     (type => 'NAMESPACE_ERR',
701     class => 'DOMException',
702     subtype_uri =>
703     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_XMLNS_WITH_OTHER_URI>,
704     param => {
705     ExpandedURI q<infoset:namespaceName> =>
706     perl_code_literal ($nsURI),
707     })),
708     perl_literal (ExpandedURI q<xml:>).
709     qq< eq $nsURI and $prefix ne 'xml'>
710     => perl_statement
711     (perl_exception
712     (type => 'NAMESPACE_ERR',
713     class => 'DOMException',
714     subtype_uri =>
715     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_OTHER_WITH_XML_URI>,
716     param => {
717     ExpandedURI q<infoset:prefix> =>
718     perl_code_literal ($prefix),
719     ExpandedURI q<DOMCore:qualifiedName>
720     => perl_code_literal ('$qualifiedName'),
721     })),
722     perl_literal (ExpandedURI q<xmlns:>).
723     qq< eq $nsURI and $prefix ne 'xmlns'>
724     => perl_statement
725     (perl_exception
726     (type => 'NAMESPACE_ERR',
727     class => 'DOMException',
728     subtype_uri =>
729     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_OTHER_WITH_XMLNS_URI>,
730     param => {
731     ExpandedURI q<infoset:prefix> =>
732     perl_code_literal ($prefix),
733     ExpandedURI q<DOMCore:qualifiedName>
734     => perl_code_literal ('$qualifiedName'),
735     })),
736     perl_literal (ExpandedURI q<xmlns:>).
737     qq< eq $nsURI and $prefix eq 'xmlns' and $lname eq 'xmlns'>
738     => perl_statement
739     (perl_exception
740     (type => 'NAMESPACE_ERR',
741     class => 'DOMException',
742     subtype_uri =>
743     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_XMLNS_XMLNS>,
744     param => {
745     })),
746     ),
747     perl_cases ( # No prefix
748     perl_literal (ExpandedURI q<xml:>).qq< eq $nsURI>
749     => perl_statement
750     (perl_exception
751     (type => 'NAMESPACE_ERR',
752     class => 'DOMException',
753     subtype_uri =>
754     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_OTHER_WITH_XML_URI>,
755     param => {
756     ExpandedURI q<DOMCore:qualifiedName>
757     => perl_code_literal ($lname),
758     })),
759     perl_literal (ExpandedURI q<xmlns:>).
760     qq< eq $nsURI and $lname ne 'xmlns'>
761     => perl_statement
762     (perl_exception
763     (type => 'NAMESPACE_ERR',
764     class => 'DOMException',
765     subtype_uri =>
766     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_OTHER_WITH_XMLNS_URI>,
767     param => {
768     ExpandedURI q<DOMCore:qualifiedName>
769     => perl_code_literal ($lname),
770     })),
771     qq<$lname eq 'xmlns' and $nsURI ne >.
772     perl_literal (ExpandedURI q<xmlns:>)
773     => perl_statement
774     (perl_exception
775     (type => 'NAMESPACE_ERR',
776     class => 'DOMException',
777     subtype_uri =>
778     ExpandedURI q<MDOM_EXCEPTION:MDOM_NS_XMLNSQ_WITH_OTHER_URI>,
779     param => {
780     ExpandedURI q<infoset:namespaceName>
781     => perl_code_literal ($nsURI),
782     })),
783     ));
784     } elsif ($name eq 'isRelativeDOMURI') {
785     $r = q<$in !~ /^[0-9A-Za-z+_.%-]:/>;
786     ## TODO: I18n consideration
787     for (qw/in/) {
788     $opt{$_} or valid_err qq<Built-in code parameter "$_" required>,
789     node => $opt{node};
790     $r =~ s/\$$_/\$$opt{$_}/g;
791     }
792     } elsif ($name eq 'ParseFeatures') {
793     $r = q{
794     {
795     if (ref $in eq 'HASH') {
796     for (keys %$in) {
797     if ($_ =~ /^\+(.+)/) {
798     $out{lc $1} = {version => $in{$_}, plus => 1};
799     } else {
800     $out{lc $_} = {version => $in{$_}, plus => 0};
801     }
802     }
803     } else {
804     my @f = grep {length} split /\s+/, $in;
805     for (my $i = 0; $i < @f; $i++) {
806     my ($name, $plus) = (lc $f[$i]);
807     $plus = 1 if $name =~ s/^\+//;
808     if ($i + 1 < @f and $f[$i + 1] =~ /^\d/) {
809     $out{$name} = {version => $f[$i + 1], plus => $plus}; $i++;
810     } else {
811     $out{$name} = {version => undef, plus => $plus};
812     }
813     }
814     }
815     }
816     }; ## NOTE: Feature name is case-insensitive.
817     ## NOTE: This code does not work if a feature appears more than
818     ## one versions. DOM specification does not specify how
819     ## implementations should cope with such case.
820     for (qw/in out/) {
821     $opt{$_} or valid_err qq<Built-in code parameter "$_" required>,
822     node => $opt{node};
823     $r =~ s/\$$_/\$$opt{$_}/g;
824     $r =~ s/%$_/%$opt{$_}/g;
825     }
826     } else {
827     valid_err qq<Built-in code "$name" not defined>;
828     }
829     $r;
830     }
831    
832 wakaba 1.3 =head2 C<Operator> element
833    
834     An C<Operatpr> element associates an operator or special-purpose
835     function name to the method or attribute. For the Perl binding,
836     it can be used to declare the method or attribute to be
837     called at the operation (by overloading of an operator;
838     see also L<overload>).
839    
840     Element value: A C<Type> dependent operator name.
841     For the Perl binding, it is either the operator name
842     used with the C<overload> module (except C<=>),
843     C<DESTROY> or C<new>.
844    
845     Child elements:
846    
847     =over 4
848    
849     =item C<Type> = type (Required)
850    
851     The type of the element value. It also specifies the
852     target binding of the C<Operatpr> element.
853    
854     =back
855    
856     =cut
857    
858 wakaba 1.1 sub ops2perl () {
859     my $result = '';
860     for (keys %{$Status->{Operator}}) {
861     if ($_ eq 'DESTROY') {
862     $result .= perl_statement q<sub DESTROY ($)>;
863     $result .= perl_statement
864     perl_assign
865     perl_var (type => '*', local_name => 'DESTROY')
866     => $Status->{Operator}->{DESTROY};
867     delete $Status->{Operator}->{DESTROY};
868     } elsif ($_ eq 'new') {
869     $result .= perl_statement q<sub new ($)>;
870     $result .= perl_statement
871     perl_assign
872     perl_var (type => '*', local_name => 'new')
873     => $Status->{Operator}->{$_};
874     delete $Status->{Operator}->{$_};
875     } elsif ($_ eq 'object-error-handler') {
876     $result .= perl_statement q<sub ___report_error ($$)>;
877     $result .= perl_statement
878     perl_assign
879     perl_var (type => '*', local_name => '___report_error')
880     => $Status->{Operator}->{$_};
881     delete $Status->{Operator}->{$_};
882     } elsif ({qw[
883     + 1 - 1 * 1 / 1 % 1 ** 1 << 1 >> 1 x 1 . 1
884     += 1 -= 1 *= 1 /= 1 %= 1 **= 1 <<= 1 >>= 1 x= 1 .= 1
885     < 1 <= 1 > 1 >= 1 == 1 != 1 <=> 1
886     lt 1 le 1 gt 1 ge 1 eq 1 ne 1 cmp 1
887     & 1 | 1 ^ 1
888     neg 1 ! 1 ~ 1
889     ++ 1 -- 1
890     atan2 1 cos 1 sin 1 exp 1 abs 1 log 1 sqrt 1
891     bool 1 "" 1 0+ 1
892     <> 1
893     ${} 1 @{} 1 %{} 1 &{} 1 *{} 1
894     ]}->{$_}) {
895     #
896     } else {
897     valid_err qq[$Status->{if}: Operator "$_" not supported];
898     }
899     }
900     if (keys %{$Status->{Operator}}) {
901     $result .= perl_statement 'use overload ' .
902     perl_list map ({($_,
903     perl_code_literal $Status->{Operator}->{$_})}
904     keys %{$Status->{Operator}}),
905     fallback => 1;
906     }
907     $result;
908     }
909    
910    
911    
912     sub qname_label ($;%) {
913     my ($node, %opt) = @_;
914     my $q = defined $opt{qname} ? $opt{qname}
915     : $node->get_attribute_value ('QName');
916     my $prefix = DEFAULT_PFX;
917     if ($q =~ s/^([^:]*)://) {
918     $prefix = $1;
919     }
920    
921     if ($prefix ne DEFAULT_PFX or not $opt{no_default_ns}) {
922     if (defined $Info->{Namespace}->{$prefix}) {
923     my $uri = $Info->{Namespace}->{$prefix};
924     if (defined $Status->{ns_in_doc}->{$prefix}) {
925     if ($Status->{ns_in_doc}->{$prefix} ne $uri) {
926     my $i = 1;
927     {
928     if (defined $Status->{ns_in_doc}->{$prefix.$i}) {
929     if ($Status->{ns_in_doc}->{$prefix.$i} eq $uri) {
930     $prefix .= $i; last;
931     } else {
932     $i++; redo;
933     }
934     } else {
935     $Status->{ns_in_doc}->{$prefix.$i} = $uri;
936     $prefix .= $i; last;
937     }
938     }
939     }
940     } else {
941     $Status->{ns_in_doc}->{$prefix} = $uri;
942     }
943     } else {
944 wakaba 1.4 valid_err qq<Namespace prefix "$prefix" not defined>,
945     node => defined $opt{qname} ? undef : $node->get_attribute ('QName');
946 wakaba 1.1 }
947     }
948    
949     $opt{out_type} ||= ExpandedURI q<DOMMain:any>;
950     if ($opt{out_type} eq ExpandedURI q<lang:pod>) {
951     pod_code ($prefix eq DEFAULT_PFX ? $q : qq<$prefix:$q>);
952     } else {
953     $prefix eq DEFAULT_PFX ? qq<"$q"> : qq<"$prefix:$q">;
954     }
955     }
956    
957 wakaba 1.3 =head1 TYPES
958    
959     In the DIS format, types (such as datatypes of something defined
960     by the DIS document or media types of the element values) are
961     identified by pair of a namespace URI and a local name. In general,
962     the pair is specified by a QName in the DIS document. The pair is
963     sometiems interpreted as a URI reference for the purpose of
964     comparise.
965    
966     NOTE: In DIS documents, the QName is less strictly defined than
967     the XML standards; its namespace prefix can be empty; and
968     its namespace prefix and local name can contain any character
969     other than C<COLON>. In addition, the interpretation of the
970     null-prefixed QName might differ by the context in which the
971     QName is used. In general, its namespace is the default
972     namespace, as is QName in the XML document representing an element
973     type name. But some local names, such as C<long> and C<DOMString>
974     might be interpreted as belonging to the C<DOMMain> namespace.
975    
976     =cut
977    
978 wakaba 1.1 {
979     my $nest = 0;
980     sub type_normalize ($);
981     sub type_normalize ($) {
982     my ($uri) = @_;
983     $nest++ == 100 and valid_err q<Possible loop for DataTypeAlias of <$uri>>;
984     if ($Info->{DataTypeAlias}->{$uri}->{canon_uri}) {
985     $uri = type_normalize ($Info->{DataTypeAlias}->{$uri}->{canon_uri});
986     }
987     $nest--;
988     $uri;
989     }
990     }
991    
992     {
993     my $nest = 0;
994     sub type_isa ($$);
995     sub type_isa ($$) {
996     my ($uri, $uri2) = @_;
997     $nest++ == 100 and valid_err qq<Possible loop for <DataType/ISA> of <$uri>>;
998     my $r = 0;
999     if ($uri eq $uri2) {
1000     $r = 1;
1001     } else {
1002     for (@{$Info->{DataTypeAlias}->{$uri}->{isa_uri}||[]}) {
1003     if (type_isa $_, $uri2) {
1004     $r = 1;
1005     last;
1006     }
1007     }
1008     }
1009     $nest--;
1010     $r;
1011     }
1012     }
1013    
1014     sub type_label ($;%) {
1015     my $uri = type_normalize shift;
1016     my %opt = @_;
1017     my $pod_code = sub { $opt{is_pod} ? pod_code $_[0] : $_[0] };
1018     my $r = {
1019 wakaba 1.3 ExpandedURI q<DOMMain:boolean> => q<Boolean Value>,
1020     ExpandedURI q<DOMMain:long> => q<Signed Long Integer>,
1021 wakaba 1.1 ExpandedURI q<DOMMain:unsigned-long> => q<Unsigned Long Integer>,
1022 wakaba 1.3 ExpandedURI q<DOMMain:unsigned-short> => q<Unsigned Short Floating Number>,
1023 wakaba 1.1 ExpandedURI q<ManakaiDOM:ManakaiDOMURI>
1024     => $pod_code->(q<DOMString>).q< (DOM URI)>,
1025     ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>
1026 wakaba 1.3 => $pod_code->(q<DOMString>).q< (DOM Namespace URI)>,
1027 wakaba 1.1 ExpandedURI q<ManakaiDOM:ManakaiDOMFeatureName>
1028     => $pod_code->(q<DOMString>).q< (DOM Feature name)>,
1029     ExpandedURI q<ManakaiDOM:ManakaiDOMFeatureVersion>
1030     => $pod_code->(q<DOMString>).q< (DOM Feature version)>,
1031     ExpandedURI q<ManakaiDOM:ManakaiDOMFeatures>
1032     => $pod_code->(q<DOMString>).q< (DOM features)>,
1033 wakaba 1.3 ExpandedURI q<ManakaiDOM:ManakaiDOMKeyIdentifier>
1034     => $pod_code->(q<DOMString>).q< (DOM Key Identifier)>,
1035     ExpandedURI q<ManakaiDOM:ManakaiDOMKeyIdentifiers>
1036     => $pod_code->(q<DOMString>).q< (DOM Key Identifiers)>,
1037 wakaba 1.1 }->{$uri};
1038     unless ($r) {
1039     if ($uri =~ /([\w_-]+)$/) {
1040     my $label = $1;
1041     $label =~ s/--+/ /g;
1042     $label =~ s/__+/ /g;
1043     $r = $pod_code->($label);
1044     } else {
1045     $r = $pod_code->("<$uri>");
1046     }
1047     }
1048     $r;
1049     }
1050    
1051     sub type_package_name ($) {
1052     my $qname = shift;
1053     if ($qname =~ /^([^:]*):([^:]*)$/) {
1054     perl_package_name name => perl_name $2, ucfirst => 1;
1055     } else {
1056     perl_package_name name => perl_name $qname, ucfirst => 1;
1057     }
1058     }
1059    
1060     sub ns_uri_to_perl_package_name ($) {
1061     my $uri = shift;
1062     if ($Info->{uri_to_perl_package}->{$uri}) {
1063     return $Info->{uri_to_perl_package}->{$uri};
1064     } else {
1065     return qq<Perl package name for namespace <$uri> not defined>;
1066     }
1067     }
1068    
1069     sub ns_prefix_to_uri ($) {
1070     my $pfx = shift;
1071     if (exists $Info->{Namespace}->{$pfx}) {
1072     if (not defined $Info->{Namespace}->{$pfx}) {
1073     valid_err qq<Namespace name for "$pfx" not defined>;
1074     } else {
1075     return $Info->{Namespace}->{$pfx};
1076     }
1077     } else {
1078     valid_err qq<Namespace prefix "$pfx" not declared>;
1079     }
1080     }
1081    
1082     sub type_expanded_uri ($) {
1083     my $qname = shift || '';
1084     if ($qname =~ /^[a-z-]+$/ or $qname eq 'Object') {
1085     expanded_uri ("DOMMain:$qname");
1086     } else {
1087     expanded_uri ($qname);
1088     }
1089     }
1090    
1091     sub expanded_uri ($) {
1092     my $lname = shift || '';
1093     my $pfx = DEFAULT_PFX;
1094     if ($lname =~ s/^([^:]*)://) {
1095     $pfx = $1;
1096     }
1097     ns_prefix_to_uri ($pfx) . $lname;
1098     }
1099    
1100     sub array_contains ($$) {
1101     my ($array, $val) = @_;
1102     if (ref $array eq 'ARRAY') {
1103     for (@$array) {
1104     return 1 if $_ eq $val;
1105     }
1106     } else {
1107     return $array eq $val;
1108     }
1109     return 0;
1110     }
1111    
1112    
1113     sub get_warning_perl_code ($) {
1114     my $pnode = shift;
1115     my $r = '';
1116     for my $node (@{$pnode->child_nodes}) {
1117     next unless $node->node_type eq '#element' and
1118     $node->local_name eq 'Warning';
1119     my %param;
1120     for (@{$node->child_nodes}) {
1121     next unless $_->node_type eq '#element' and
1122     $_->local_name eq 'Param';
1123     $param{expanded_uri $_->get_attribute_value ('QName')}
1124     = perl_code_literal get_value_literal ($_, name => 'Value',
1125     type_name => 'Type');
1126     }
1127     $r .= perl_statement
1128     perl_exception
1129     class => type_package_name $node->get_attribute_value
1130     ('Type',
1131     default => 'DOMMain:any'),
1132     type => $node->get_attribute_value ('Name'),
1133     param => \%param;
1134     }
1135     $r;
1136     } # get_warning_perl_code
1137    
1138     sub get_perl_definition_node ($%) {
1139     my ($node, %opt) = @_;
1140     my $ln = $opt{name} || 'Def';
1141     my $def = $node->get_element_by (sub {
1142     my ($me, $you) = @_;
1143     $you->local_name eq $ln and
1144     type_expanded_uri $you->get_attribute_value ('Type', default => '')
1145     eq ExpandedURI q<lang:Perl> and
1146     condition_match ($you, %opt);
1147     }) || ($opt{use_dis} and $node->get_element_by (sub {
1148     my ($me, $you) = @_;
1149     $you->local_name eq $ln and
1150     $you->get_attribute_value ('Type', default => '')
1151     eq ExpandedURI q<lang:dis> and
1152     condition_match ($you, %opt);
1153     })) || $node->get_element_by (sub {
1154     my ($me, $you) = @_;
1155     $you->local_name eq $ln and
1156     not $you->get_attribute_value ('Type', default => '') and
1157     condition_match ($you, %opt);
1158     }) || $node->get_element_by (sub {
1159     my ($me, $you) = @_;
1160     $you->local_name eq $ln and
1161     type_expanded_uri $you->get_attribute_value ('Type', default => '')
1162     eq ExpandedURI q<lang:Perl> and
1163     condition_match ($you); # no condition specified
1164     }) || ($opt{use_dis} and $node->get_element_by (sub {
1165     my ($me, $you) = @_;
1166     $you->local_name eq $ln and
1167     type_expanded_uri $you->get_attribute_value ('Type', default => '')
1168     eq ExpandedURI q<lang:dis> and
1169     condition_match ($you); # no condition specified
1170     })) || $node->get_element_by (sub {
1171     my ($me, $you) = @_;
1172     $you->local_name eq $ln and
1173     not $you->get_attribute_value ('Type', default => '') and
1174     condition_match ($you); # no condition specified
1175     });
1176     $def;
1177     }
1178    
1179     sub get_perl_definition ($%) {
1180     my ($node, %opt) = @_;
1181     my $def = get_perl_definition_node $node, %opt;
1182     $def ? $def->value : $opt{default};
1183     }
1184    
1185 wakaba 1.3 =head1 DISDOC DOCUMENTATION FORMAT
1186    
1187     The DISDOC format is a documentation format for DIS documents.
1188    
1189     =cut
1190    
1191 wakaba 1.1 sub dis2perl ($) {
1192     my $node = shift;
1193     my $r = '';
1194     for (@{$node->child_nodes}) {
1195     next unless $_->node_type eq '#element';
1196     if ($_->local_name eq 'GetProp') {
1197     $r .= perl_statement perl_assign
1198     perl_var (type => '$', local_name => 'r')
1199     => '$self->{node}->{' .
1200     perl_literal (expanded_uri ($_->value)) . '}';
1201     } elsif ($_->local_name eq 'GetPropNode') {
1202     $r .= perl_statement perl_assign
1203     perl_var (type => '$', local_name => 'r')
1204     => '$self->{node}->{' .
1205     perl_literal (expanded_uri ($_->value)) . '}';
1206     ## Conditional
1207     $r .= perl_statement
1208     perl_code q{$r = __CLASS{Node}__->__INT{getNodeReference}__ ($r)
1209     if defined $r};
1210     } elsif ($_->local_name eq 'SetProp') {
1211     my $t = perl_statement perl_assign
1212     '$self->{node}->{' .
1213     perl_literal (expanded_uri ($_->value)) . '}'
1214     => perl_var (type => '$', local_name => 'given');
1215     if ($_->get_attribute_value ('CheckReadOnly', default => 1)) {
1216     $r .= perl_if
1217     q[$self->{'node'}->{].
1218     perl_literal (ExpandedURI (q<DOMCore:read-only>)).q[}],
1219     perl_statement
1220     (perl_exception
1221     class => 'DOMException',
1222     type => 'NO_MODIFICATION_ALLOWED_ERR',
1223     param => {}),
1224     $t;
1225     } else {
1226     $r .= $t;
1227     }
1228     } elsif ($_->local_name eq 'Overridden') {
1229     $r = perl_statement perl_exception
1230     class => 'ManakaiDOMImplementationException',
1231     type => 'MDOM_DEBUG_BUG',
1232     param => {
1233     ExpandedURI q<MDOM_EXCEPTION:values> => {
1234     msg => q<This class defines only the interface; >.
1235     q<some other class must inherit this class >.
1236     q<and implement this subroutine.>,
1237     },
1238     };
1239     } elsif ($_->local_name eq 'Type') {
1240     #
1241     } else {
1242     valid_err qq{Element type "@{[$_->local_name]}" not supported},
1243     node => $_;
1244     }
1245     }
1246     if (defined $node->value and length $node->value) {
1247     valid_err q{DIS has value}, node => $node;
1248     }
1249     $r;
1250     } # dis2perl
1251    
1252     {
1253     use re 'eval';
1254     our $Element;
1255     $Element = qr/[A-Za-z0-9]+(?>:(?>[^<>]*)(?>(?>[^<>]+|<(??{$Element})>)*))?/;
1256     my $MElement = qr/([A-Za-z0-9]+)(?>:((?>[^<>]*)(?>(?>[^<>]+|<(??{$Element})>)*)))?/;
1257    
1258     sub disdoc2text ($;%);
1259     sub disdoc2text ($;%) {
1260     my ($s, %opt) = @_;
1261     $s =~ s/\x0D\x0A/\x0A/g;
1262     $s =~ tr/\x0D/\x0A/;
1263     my @s = split /\x0A\x0A+/, $s;
1264     my @r;
1265     for my $s (@s) {
1266     if ($s =~ s/^\{([0-9A-Za-z-]+)::\s*//) { ## Start tag'ed element
1267     my $et = $1;
1268     if ($et eq 'P') { ## Paragraph
1269     push @r, (disdoc_inline2text ($s, %opt));
1270     } elsif ($et eq 'LI' or $et eq 'OLI') { ## List
1271     my $marker = '* ';
1272     if ($et eq 'OLI') {
1273     $marker = '# ';
1274     }
1275     if ($s =~ s/^(.+?)::\s*//) {
1276     $marker = disdoc_inline2text ($1, %opt) . ': ';
1277     }
1278     push @r, $marker . (disdoc_inline2text ($s, %opt));
1279 wakaba 1.3 } elsif ($et eq 'NOTE') {
1280     push @r, "NOTE: ". disdoc_inline2text ($s, %opt);
1281     } elsif ($et eq 'eg') {
1282     push @r, "Example. ";
1283     $s =~ s/^\s+//;
1284     valid_err qq<Invalid content for DISDOC "eg" element: "$s">,
1285     node => $opt{node} if length $s;
1286 wakaba 1.1 } else {
1287     valid_err qq<Unknown DISDOC element type "$et">, node => $opt{node};
1288     }
1289     } elsif ($s =~ /^\}\s*$/) { ## End tag
1290     #
1291     } elsif ($s =~ s/^([-=])\s*//) { ## List
1292     my $marker = $1;
1293     if ($marker eq '=') {
1294     $marker = '# ';
1295     } elsif ($marker eq '-') {
1296     $marker = '* ';
1297     }
1298     if ($s =~ s/^(.+?)::\s*//) {
1299     $marker = disdoc_inline2text ($1, %opt) . ': ';
1300     }
1301     push @r, $marker . (disdoc_inline2pod ($s, %opt));
1302     } elsif ($s =~ /^[^\w\s<]/) { ## Reserved for future extension
1303     valid_err qq<Broken DISDOC: "$s">, node => $opt{node};
1304     } else {
1305     $s =~ s/^\s+//;
1306     push @r, disdoc_inline2text ($s, %opt);
1307     }
1308     }
1309     join "\n\n", @r;
1310     } # disdoc2text
1311    
1312     sub disdoc_inline2text ($;%);
1313     sub disdoc_inline2text ($;%) {
1314     my ($s, %opt) = @_;
1315     $s =~ s{\G(?:([^<>]+)|<$MElement>|(.))}{
1316     my ($cdata, $type, $data, $err) = ($1, $2, defined $3 ? $3 : '', $4);
1317     my $r = '';
1318     if (defined $err) {
1319     valid_err qq<Invalid character "$err" in DISDOC>,
1320     node => $opt{node};
1321     } elsif (defined $cdata) {
1322     $r = $cdata;
1323 wakaba 1.3 } elsif ({DFN => 1, CITE => 1, KEY => 1}->{$type}) {
1324 wakaba 1.1 $r = disdoc_inline2text $data;
1325     } elsif ({SRC => 1}->{$type}) {
1326     $r = q<[>. disdoc_inline2text ($data) . q<]>;
1327 wakaba 1.3 } elsif ({EM => 1}->{$type}) {
1328     $r = q<*>. disdoc_inline2text ($data) . q<*>;
1329 wakaba 1.1 } elsif ({URI => 1}->{$type}) {
1330     $r = q{<} . $data . q{>};
1331     } elsif ({CODE => 1, Perl => 1}->{$type}) {
1332     $r = q<"> . disdoc_inline2text ($data) . q<">;
1333     } elsif ({IF => 1, TYPE => 1, P => 1, XML => 1, SGML => 1, DOM => 1,
1334     FeatureVer => 1, CHAR => 1, HTML => 1, Prefix => 1,
1335     Module => 1, QUOTE => 1, PerlModule => 1,
1336     FILE => 1}->{$type}) {
1337     $r = q<"> . $data . q<">;
1338     } elsif ({Feature => 1, CP => 1, ERR => 1,
1339     HA => 1, HE => 1, XA => 1, SA => 1, SE => 1}->{$type}) {
1340     $r = qname_label (undef, qname => $data,
1341     no_default_ns => 1);
1342     } elsif ({Q => 1, EV => 1,
1343     XE => 1}->{$type}) {
1344     $r = qname_label (undef, qname => $data);
1345     } elsif ({M => 1, A => 1, X => 1, WARN => 1}->{$type}) {
1346     if ($data =~ /^([^.]+)\.([^.]+)$/) {
1347     $r = q<"> . $1 . '->' . $2 . q<">;
1348     } else {
1349     $r = q<"> . $data . q<">;
1350     }
1351     } elsif ({InfosetP => 1}->{$type}) {
1352     $r = q<[> . $data . q<]>;
1353     } elsif ($type eq 'lt') {
1354     $r = '<';
1355     } elsif ($type eq 'gt') {
1356     $r = '>';
1357     } else {
1358     valid_err qq<DISDOC element type "$type" not supported>,
1359     node => $opt{node};
1360     }
1361     $r;
1362     }ges;
1363     $s;
1364     } # disdoc_inline2text
1365    
1366     sub disdoc2pod ($;%);
1367     sub disdoc2pod ($;%) {
1368     my ($s, %opt) = @_;
1369     $s =~ s/\x0D\x0A/\x0A/g;
1370     $s =~ tr/\x0D/\x0A/;
1371     my @s = split /\x0A\x0A+/, $s;
1372     my @el = ({type => '#document'});
1373     my @r;
1374     for my $s (@s) {
1375     if ($s =~ s/^\{([0-9A-Za-z-]+)::\s*//) { ## Start tag'ed element
1376     my $et = $1;
1377     if ($el[-1]->{type} eq '#list' and
1378     not {qw/LI 1 OLI 1/}->{$et}) {
1379     push @r, '=back';
1380     pop @el;
1381     }
1382     push @el, {type => $et};
1383     if ($et eq 'P') { ## Paragraph
1384     push @r, pod_para (disdoc_inline2pod ($s, %opt));
1385 wakaba 1.3 } elsif ($et eq 'NOTE') {
1386     push @r, pod_para (pod_em ('NOTE').": ".disdoc_inline2pod ($s, %opt));
1387     } elsif ($et eq 'eg') {
1388     push @r, pod_para (pod_em ('Example').". ");
1389     $s =~ s/^\s+//;
1390     valid_err qq<Invalid content for DISDOC "eg" element: "$s">,
1391     node => $opt{node} if length $s;
1392 wakaba 1.1 } elsif ($et eq 'LI' or $et eq 'OLI') { ## List
1393     my $marker = '*';
1394     unless ($el[-1]->{type} eq '#list') {
1395     push @el, {type => '#list', n => 0};
1396     push @r, '=over 4';
1397     }
1398     if ($et eq 'OLI') {
1399     $marker = ++($el[-1]->{n}) . '. ';
1400     }
1401     if ($s =~ s/^(.+?)::\s*//) {
1402     $marker = disdoc_inline2pod ($1, %opt);
1403     }
1404     push @r, pod_item ($marker), pod_para (disdoc_inline2pod ($s, %opt));
1405     } else {
1406     valid_err qq<Unknown DISDOC element type "$et">, node => $opt{node};
1407     }
1408     } elsif ($s =~ /^\}\s*$/) { ## End tag
1409     while (@el > 1 and $el[-1]->{type} =~ /^\#/) {
1410     if ($el[-1]->{type} eq '#list') {
1411     push @r, '=back';
1412     }
1413     pop @el;
1414     }
1415     if ($el[-1]->{type} eq '#document') {
1416     valid_err qq<Unmatched DISDOC end tag>, node => $opt{node};
1417     } else {
1418     pop @el;
1419     }
1420     } elsif ($s =~ s/^([-=])\s*//) { ## List
1421     my $marker = $1;
1422     unless ($el[-1]->{type} eq '#list') {
1423     push @el, {type => '#list', n => 0};
1424     push @r, '=over 4';
1425     }
1426     if ($marker eq '=') {
1427     $marker = ++($el[-1]->{n}) . '. ';
1428     } elsif ($marker eq '-') {
1429     $marker = '*';
1430     }
1431     if ($s =~ s/^(.+?)::\s*//) {
1432     $marker = disdoc_inline2pod ($1, %opt);
1433     }
1434     push @r, pod_item ($marker), pod_para (disdoc_inline2pod ($s, %opt));
1435     } elsif ($s =~ /^[^\w\s<]/) { ## Reserved for future extension
1436     valid_err qq<Broken DISDOC: "$s">, node => $opt{node};
1437     } else {
1438     if ($el[-1]->{type} eq '#list') {
1439     push @r, '=back';
1440     pop @el;
1441     }
1442     $s =~ s/^\s+//;
1443     push @r, pod_para disdoc_inline2pod ($s, %opt);
1444     }
1445     }
1446     while (@el and $el[-1]->{type} =~ /^\#/) {
1447     if ($el[-1]->{type} eq '#list') {
1448     push @r, '=back';
1449     }
1450     pop @el;
1451     }
1452     if (@el) {
1453     valid_err qq[DISDOC end tag required for "$el[-1]->{type}"],
1454     node => $opt{node};
1455     }
1456     wantarray ? @r : join "\n\n", @r;
1457     } # disdoc2pod
1458    
1459     sub disdoc_inline2pod ($;%);
1460     sub disdoc_inline2pod ($;%) {
1461     my ($s, %opt) = @_;
1462     $s =~ s{\G(?:([^<>]+)|<$MElement>|(.))}{
1463     my ($cdata, $type, $data, $err) = ($1, $2, defined $3 ? $3 : '', $4);
1464     my $r = '';
1465     if (defined $err) {
1466     valid_err qq<Invalid character "$err" in DISDOC>,
1467     node => $opt{node};
1468     } elsif (defined $cdata) {
1469     $r = pod_cdata $cdata;
1470 wakaba 1.3 } elsif ({CODE => 1, KEY => 1}->{$type}) {
1471 wakaba 1.1 $r = pod_code disdoc_inline2pod $data;
1472 wakaba 1.3 } elsif ({EM => 1}->{$type}) {
1473     $r = pod_em disdoc_inline2pod $data;
1474 wakaba 1.1 } elsif ({DFN => 1}->{$type}) {
1475     $r = pod_dfn disdoc_inline2pod $data;
1476     } elsif ({CITE => 1}->{$type}) {
1477     $r = q[I<] . disdoc_inline2pod ($data) . q[>];
1478     } elsif ({SRC => 1}->{$type}) {
1479     $r = q<[>. disdoc_inline2pod ($data) . q<]>;
1480     } elsif ({URI => 1}->{$type}) {
1481     $r = pod_uri $data;
1482     } elsif ({
1483     IF => 1, TYPE => 1, P => 1, DOM => 1, XML => 1, HTML => 1,
1484     SGML => 1, FeatureVer => 1, CHAR => 1, Prefix => 1,
1485     Perl => 1, FILE => 1,
1486     }->{$type}) {
1487     $r = pod_code $data;
1488     } elsif ({Feature => 1, CP => 1, ERR => 1,
1489     HA => 1, HE => 1, XA => 1, SA => 1, SE => 1}->{$type}) {
1490     $r = qname_label (undef, qname => $data,
1491     out_type => ExpandedURI q<lang:pod>,
1492     no_default_ns => 1);
1493     } elsif ({Q => 1, EV => 1,
1494     XE => 1}->{$type}) {
1495     $r = qname_label (undef, qname => $data,
1496     out_type => ExpandedURI q<lang:pod>);
1497     } elsif ({
1498     M => 1, A => 1,
1499     }->{$type}) {
1500     if ($data =~ /^([^.]+)\.([^.]+)$/) {
1501     $r = pod_code ($1 . '->' . $2);
1502     } else {
1503     $r = pod_code $data;
1504     }
1505     } elsif ({X => 1, WARN => 1}->{$type}) {
1506     if ($data =~ /^([^.]+)\.([^.]+)$/) {
1507     $r = pod_code ($1) . '.' . pod_code ($2);
1508     } else {
1509     $r = pod_code $data;
1510     }
1511     } elsif ({InfosetP => 1}->{$type}) {
1512     $r = q<[> . $data . q<]>;
1513     } elsif ({QUOTE => 1}->{$type}) {
1514     $r = q<"> . $data . q<">;
1515     } elsif ({PerlModule => 1}->{$type}) {
1516     $r = pod_link label => pod_code ($data), module => $data;
1517     } elsif ({Module => 1}->{$type}) {
1518     $r = pod_link label => pod_code ($data),
1519     module => perl_package_name (name => $data);
1520     } elsif ($type eq 'lt' or $type eq 'gt') {
1521     $r = qq<E<$type>>;
1522     } else {
1523     valid_err qq<DISDOC element type "$type" not supported>,
1524     node => $opt{node};
1525     }
1526     $r;
1527     }ges;
1528     $s;
1529     }
1530     }
1531    
1532     sub get_description ($;%) {
1533     my ($node, %opt) = @_;
1534     my $ln = $opt{name} || 'Description';
1535     my $lang = $opt{lang} || q<en> || q<i-default>;
1536     my $textplain = ExpandedURI q<DOMMain:any>;
1537     my $default = q<lang:disdoc>;
1538     $opt{type} ||= ExpandedURI q<lang:pod>;
1539     my $script = $opt{script} || q<>;
1540     my $def;
1541     for my $type (($opt{type} ne $textplain ? $opt{type} : ()),
1542     ExpandedURI q<lang:disdoc>,
1543     $textplain) {
1544     $def = $node->get_element_by (sub {
1545     my ($me, $you) = @_;
1546     $you->local_name eq $ln and
1547     $you->get_attribute_value ('lang', default => 'i-default') eq $lang and
1548     type_expanded_uri ($you->get_attribute_value ('Type', default => $default))
1549     eq $type;
1550     }) || $node->get_element_by (sub {
1551     my ($me, $you) = @_;
1552     $you->local_name eq $ln and
1553     $you->get_attribute_value ('lang', default => 'i-default')
1554     eq 'i-default' and
1555     type_expanded_uri ($you->get_attribute_value ('Type', default => $default))
1556     eq $type;
1557     });
1558     last if $def;
1559     }
1560     unless ($def) {
1561     $opt{default};
1562     } else {
1563     my $srctype = type_expanded_uri
1564     $def->get_attribute_value ('Type', default => $default);
1565     my $value = $def->value;
1566     valid_err q<Description undefined>, node => $def
1567     unless defined $value;
1568     if ($srctype eq ExpandedURI q<lang:disdoc>) {
1569     if ($opt{type} eq ExpandedURI q<lang:pod>) {
1570     $value = $opt{is_inline} ?
1571     disdoc_inline2pod ($value, node => $def):
1572     disdoc2pod ($value, node => $def);
1573     } else {
1574     $value = $opt{is_inline} ?
1575     disdoc_inline2text ($value, node => $def):
1576     disdoc2text ($value, node => $def);
1577     if ($opt{type} eq ExpandedURI q<lang:muf>) {
1578     $value =~ s/\s+/ /g;
1579     }
1580     }
1581     } elsif ($srctype eq ExpandedURI q<lang:muf>) {
1582     if ($opt{type} eq ExpandedURI q<lang:muf>) {
1583     $value = muf_template $value;
1584     $value =~ s/\s+/ /g;
1585     } else {
1586     impl_err q<Can't convert MUF tempalte to >.$opt{type};
1587     }
1588     } elsif ($srctype eq $opt{type}) {
1589     #
1590     } else {
1591     if ($opt{type} eq ExpandedURI q<lang:pod>) {
1592     $value = pod_paras $def->value;
1593     } elsif ($opt{type} eq ExpandedURI q<lang:muf>) {
1594     $value =~ s/%/%percent;/g;
1595     $value =~ s/\s+/ /g;
1596     }
1597     }
1598     $value;
1599     }
1600     }
1601    
1602     sub get_level_description ($%) {
1603     my ($node, %opt) = @_;
1604     my @l = @{$node->get_attribute_value ('SpecLevel', default => [],
1605     as_array => 1)};
1606     unless (@l) {
1607     my $min = $opt{level}->[0] || 1;
1608     for ($min..$MAX_DOM_LEVEL) {
1609     if ($Info->{Condition}->{'DOM' . $_}) {
1610     unshift @l, $_;
1611     last;
1612     }
1613     }
1614     }
1615     return q<> unless @l;
1616     @l = sort {$a <=> $b} @l;
1617     @{$opt{level}} = @l;
1618     my $r = q<introduced in DOM Level > . (0 + shift @l);
1619     if (@l > 1) {
1620     my $s = 0 + pop @l;
1621     $r .= q< and modified in DOM Levels > . join ', ', @l;
1622     $r .= qq< and $s>;
1623     } elsif (@l == 1) {
1624     $r .= q< and modified in DOM Level > . (0 + $l[0]);
1625     }
1626     $r;
1627     } # get_level_description
1628    
1629     sub get_alternate_description ($;%) {
1630     my ($node, %opt) = @_;
1631     my @desc;
1632     $opt{if} ||= 'interface';
1633     $opt{method} ||= $node->local_name =~ /Attr/ ? 'attribute' : 'method';
1634    
1635     ## XML Namespace unaware alternate
1636     ## (This method is namespace aware.)
1637     my $ns = $node->get_attribute_value ('NoNSVersion', as_array => 1,
1638     default => undef);
1639     if (defined $ns) {
1640     my $a = '';
1641     if (@$ns) {
1642     $a = english_list
1643     [map {
1644     if (/^(?:[AM]:)?([^.]+)\.([^.]+)$/) {
1645     pod_code ($2) . ' on the interface '.
1646     type_label (type_expanded_uri ($1), is_pod => 1)
1647     } else {
1648     pod_code ($_)
1649     }
1650     } @$ns], connector => 'and/or';
1651     $a = qq<DOM applications dealing with documents that do >.
1652     qq<not use XML Namespaces should use $a instead.>;
1653     }
1654     push @desc, pod_para
1655     qq<This $opt{method} is namespace-aware. Mixing >.
1656     qq<namespace-aware and -unaware methods can lead >.
1657     qq<to unpredictable result. $a>;
1658     }
1659    
1660     ## XML Namespace aware alternate
1661     ## (This method is namespace unaware.)
1662     $ns = $node->get_attribute_value ('NSVersion', as_array => 1,
1663     default => undef);
1664     if (defined $ns) {
1665     my $a = '';
1666     if (@$ns) {
1667     $a = english_list
1668     [map {
1669     if (/^(?:[AM]:)?([^.]+)\.([^.]+)$/) {
1670     pod_code ($2) . ' on the interface '.
1671     type_label (type_expanded_uri ($1), is_pod => 1)
1672     } else {
1673     pod_code ($_)
1674     }
1675     } @$ns];
1676     $a = qq<DOM applications dealing with documents that do >.
1677     qq<use XML Namespaces should use $a instead.>;
1678     }
1679     push @desc, pod_para
1680     qq<This $opt{method} is namespace ignorant. Mixing >.
1681     qq<namespace-aware and -unaware methods can lead >.
1682     qq<to unpredictable result. $a>;
1683     }
1684    
1685     @desc;
1686     } # get_alternate_description
1687    
1688     sub get_redef_description ($;%) {
1689     my ($node, %opt) = @_;
1690     my @desc;
1691     $opt{if} ||= 'interface';
1692     $opt{method} ||= 'method';
1693     if ($node->local_name eq 'ReMethod' or
1694     $node->local_name eq 'ReAttr') {
1695     my $redef = $node->get_attribute_value ('Redefine');
1696     push @desc, pod_para qq<This $opt{method} is defined by the >.
1697     ($redef ? qq<$opt{if} > . type_label
1698     (type_expanded_uri ($redef),
1699     is_pod => 1)
1700     : qq<super-$opt{if} of this $opt{if}>).
1701     q< but that definition has been overridden here.>;
1702     }
1703     if ($node->get_attribute_value ('IsAbstract', default => 0)) {
1704     push @desc, pod_para (qq<This $opt{method} is defined abstractly; >.
1705 wakaba 1.3 qq<it must be overridden by the concrete >.
1706     qq<implementation. >);
1707 wakaba 1.1 }
1708     my @redefBy;
1709     for (@{$node->child_nodes}) {
1710     next unless $_->node_type eq '#element' and
1711     $_->local_name eq 'RedefinedBy';
1712     push @redefBy, type_label (type_expanded_uri ($_->value), is_pod => 1);
1713     }
1714     if (@redefBy) {
1715     push @desc, pod_para qq<This $opt{method} is redefined by the >.
1716     qq<implementation of the sub-$opt{if}>.
1717     (@redefBy > 1 ? 's ' : ' ').
1718     english_list (\@redefBy, connector => 'and').'.';
1719     }
1720     @desc;
1721     } # get_redef_description;
1722    
1723     sub get_isa_description ($;%) {
1724     my ($node, %opt) = @_;
1725     $opt{if} ||= $node->get_attribute_value ('IsAbstract', default => 0)
1726     ? 'interface' : 'class';
1727     my @desc;
1728     my @isa;
1729     my @impl;
1730     for (@{$node->child_nodes}) {
1731     next unless $_->node_type eq '#element';
1732     if ($_->local_name eq 'ISA') {
1733     my $v = $_->value;
1734     if (type_expanded_uri $_->get_attribute_value ('Type',
1735     default => 'DOMMain:any') eq
1736     ExpandedURI q<lang:Perl>) {
1737     push @isa, pod_link (module => $v);
1738     } else {
1739     $v =~ s/::[^:]*$//g;
1740     push @isa, type_label (type_expanded_uri ($v), is_pod => 1);
1741     }
1742     } elsif ($_->local_name eq 'Implement') {
1743     my $v = $_->value;
1744     $v =~ s/::[^:]*$//g;
1745     push @impl, type_label (type_expanded_uri ($v), is_pod => 1);
1746     }
1747     }
1748     if (@isa and @impl) {
1749     push @desc, pod_para (qq<This $opt{if} inherits >.
1750     english_list (\@isa, connector => 'and').
1751     qq< and implements >.
1752     (@impl>1?q<interfaces >:q<the interface >).
1753     english_list (\@impl, connector => 'and').q<.>);
1754     } elsif (@isa) {
1755     push @desc, pod_para (qq<This $opt{if} inherits >.
1756     english_list (\@isa, connector => 'and').q<.>);
1757     } elsif (@impl) {
1758     push @desc, pod_para (qq<This $opt{if} implements >.
1759     (@impl>1?q<interfaces >:q<the interface >).
1760     english_list (\@impl, connector => 'and').q<.>);
1761     }
1762     @desc;
1763     } # get_isa_description
1764    
1765     sub get_incase_label ($;%) {
1766     my ($node, %opt) = @_;
1767     my $label = $node->get_attribute_value ('Label', default => '');
1768     unless (length $label) {
1769     $label = $node->get_attribute ('Value');
1770     my $type = type_normalize
1771     type_expanded_uri
1772     ($node->get_attribute_value ('Type') ||
1773     $node->parent_node->get_attribute_value
1774     ('Type',
1775     default => q<DOMMain:any>));
1776     if ($label) {
1777     if ($label->get_attribute_value ('is-null', default => 0)) {
1778     $label = 'null';
1779     } else {
1780     if (not defined $label->value) {
1781     valid_err q<Value is null>, node => $node;
1782     }
1783     if (type_isa $type, ExpandedURI q<DOMMain:DOMString>) {
1784     $label = perl_literal $label->value;
1785     } else {
1786     $label = $label->value;
1787     }
1788     }
1789     $label = $opt{is_pod} ? pod_code $label : $label;
1790     } else {
1791     $label = type_label $type, is_pod => $opt{is_pod};
1792     }
1793     } else {
1794     $label = get_description $node, name => 'Label', is_inline => 1;
1795     }
1796     $label;
1797     }
1798    
1799     sub get_value_literal ($%) {
1800     my ($node, %opt) = @_;
1801     my $value = get_perl_definition_node $node, %opt;
1802     my $type = type_normalize type_expanded_uri
1803     $node->get_attribute_value ($opt{type_name} || 'Type',
1804     default => q<DOMMain:any>);
1805     my $r;
1806     if ($type eq ExpandedURI q<DOMMain:boolean>) {
1807     if ($value) {
1808     $r = ($value->value and $value->value eq 'true') ? 1 : 0;
1809     } else {
1810     $r = $opt{default} ? 1 : 0;
1811     }
1812     } elsif ($type eq ExpandedURI q<DOMMain:unsigned-long> or
1813     $type eq ExpandedURI q<DOMMain:unsigned-long-long> or
1814     $type eq ExpandedURI q<DOMMain:long> or
1815     $type eq ExpandedURI q<DOMMain:float> or
1816     $type eq ExpandedURI q<DOMMain:unsigned-short>) {
1817     if ($value) {
1818     $r = $value->value;
1819     } else {
1820     $r = defined $opt{default} ? $opt{default} : 0;
1821     }
1822     } elsif (type_isa $type, ExpandedURI q<DOMMain:DOMString>) {
1823     if ($value) {
1824     if ($value->get_attribute_value ('is-null', default => 0)) {
1825     $r = 'undef';
1826     } else {
1827     $r = perl_literal $value->value;
1828     }
1829     } else {
1830     if (exists $opt{default}) {
1831     $r = defined $opt{default} ? perl_literal $opt{default} : 'undef';
1832     } else {
1833     $r = perl_literal '';
1834     }
1835     }
1836     } elsif ($type eq ExpandedURI q<Perl:ARRAY>) {
1837     if ($value) {
1838     $r = perl_literal $value->value (as_array => 1);
1839     } else {
1840     $r = perl_literal (defined $opt{default} ? $opt{default} : []);
1841     }
1842     } elsif ($type eq ExpandedURI q<Perl:HASH>) {
1843     if ($value) {
1844     $r = perl_literal $value->value;
1845     } else {
1846     $r = perl_literal (defined $opt{default} ? $opt{default} : {});
1847     }
1848     } else {
1849     if ($value) {
1850     if ($value->get_attribute_value ('is-null', default => 0)) {
1851     $r = 'undef';
1852     } else {
1853     $r = perl_literal $value->value;
1854     }
1855     } else {
1856     if (exists $opt{default}) {
1857     $r = defined $opt{default} ? perl_literal $opt{default} : 'undef';
1858     } else {
1859     $r = 'undef';
1860     }
1861     }
1862     }
1863     $r;
1864     }
1865    
1866     sub get_internal_code ($$;%) {
1867     my ($node, $name, %opt) = @_;
1868     $node = $node->parent_node;
1869     my $m;
1870     my $def;
1871     if ($m = $node->get_element_by (sub {
1872     my ($me, $you) = @_;
1873     $you->node_type eq '#element' and
1874     ($you->local_name eq 'Method' or
1875     $you->local_name eq 'ReMethod') and
1876     $you->get_attribute_value ('Name') eq $name
1877     })) {
1878     $def = $m->get_attribute ('Return');
1879     $def = (get_perl_definition_node $def, name => 'IntDef', use_dis => 1 or
1880     get_perl_definition_node $def, name => 'Def', use_dis => 1) if $def;
1881     } elsif ($m = $node->get_element_by (sub {
1882     my ($me, $you) = @_;
1883     $you->node_type eq '#element' and
1884     ($you->local_name eq 'Attr' or
1885     $you->local_name eq 'ReAttr') and
1886     $you->get_attribute_value ('Name') eq $name
1887     })) {
1888     $def = $m->get_attribute ('Get');
1889     $def = (get_perl_definition_node $def, name => 'IntDef', use_dis => 1 or
1890     get_perl_definition_node $def, name => 'Def', use_dis => 1) if $def;
1891     } elsif ($m = $node->get_element_by (sub {
1892     my ($me, $you) = @_;
1893     $you->node_type eq '#element' and
1894     $you->local_name eq 'IntMethod' and
1895     $you->get_attribute_value ('Name') eq $name
1896     })) {
1897     $def = $m->get_attribute ('Return');
1898     $def = get_perl_definition_node $def, name => 'Def', use_dis => 1 if $def;
1899     } elsif ($m = $node->get_element_by (sub {
1900     my ($me, $you) = @_;
1901     $you->node_type eq '#element' and
1902     $you->local_name eq 'IntAttr' and
1903     $you->get_attribute_value ('Name') eq $name
1904     })) {
1905     $def = $m->get_attribute ('Get');
1906     $def = get_perl_definition_node $def, name => 'Def', use_dis => 1 if $def;
1907     }
1908     if ($def) {
1909     if (type_expanded_uri ($def->get_attribute_value ('Type', default => ''))
1910     eq ExpandedURI q<lang:dis>) {
1911     return dis2perl $def;
1912     } else {
1913     return perl_code $def->value;
1914     }
1915     } else {
1916     valid_warn qq<Internal method "$name" not defined>;
1917     is_implemented (if => $Status->{IF}, method => $name, set => 0);
1918     $Status->{is_implemented} = 0;
1919     return perl_statement perl_exception
1920     level => 'EXCEPTION',
1921     class => 'DOMException',
1922 wakaba 1.2 type => 'NOT_SUPPORTED_ERR',
1923     subtype_uri
1924     => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_METHOD_NOT_IMPLEMENTED>,
1925 wakaba 1.1 param => {
1926     ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
1927     ExpandedURI q<MDOM_EXCEPTION:method> => $name,
1928     };
1929     }
1930     } # get_internal_code
1931    
1932     sub register_namespace_declaration ($) {
1933     my $node = shift;
1934     for (@{$node->child_nodes}) {
1935     if ($_->node_type eq '#element' and
1936     $_->local_name eq 'Namespace') {
1937     for (@{$_->child_nodes}) {
1938     $Info->{Namespace}->{$_->local_name} = $_->value;
1939     }
1940     }
1941     }
1942     }
1943    
1944     {
1945     my $nest = 0;
1946     sub is_implemented (%);
1947     sub is_implemented (%) {
1948     my (%opt) = @_;
1949     my $r = 0;
1950     $nest++ == 100 and valid_err q<Condition loop detected>;
1951     my $member = ($Info->{is_implemented}->{$opt{if}}->{$opt{method} ||
1952     $opt{attr} . '.' . $opt{on}}
1953     ||= {});
1954     if (exists $opt{set}) {
1955     $r = ($member->{$opt{condition} || ''} = $opt{set});
1956     } else {
1957     if (defined $member->{$opt{condition} || ''}) {
1958     $r = $member->{$opt{condition} || ''};
1959     } else {
1960     for (@{$Info->{Condition}->{$opt{condition} || ''}->{ISA} || []}) {
1961     if (is_implemented (%opt, condition => $_)) {
1962     $r = 1;
1963     last;
1964     }
1965     }
1966     }
1967     }
1968     $nest--;
1969     $r;
1970     }
1971     sub is_all_implemented (%);
1972     sub is_all_implemented (%) {
1973     my (%opt) = @_;
1974     $nest++ == 100 and valid_err q<Condition loop detected>;
1975     $opt{not_implemented} ||= [];
1976     IF: for my $if (keys %{$Info->{is_implemented}}) {
1977     for my $mem (keys %{$Info->{is_implemented}->{$if}}) {
1978     ## Note: In fact, this checks whether the method is NOT implemented
1979     ## rather than the method IS implemented.
1980     if (exists $Info->{is_implemented}->{$if}->{$mem}->{$opt{condition}} and
1981     not $Info->{is_implemented}->{$if}->{$mem}->{$opt{condition}}) {
1982     @{$opt{not_implemented}} = ($if, $mem, $opt{condition} || '');
1983     last IF;
1984     }
1985     }
1986     }
1987     if (not @{$opt{not_implemented}}) {
1988     for (@{$Info->{Condition}->{$opt{condition} || ''}->{ISA} || []}) {
1989     if (not is_all_implemented (%opt, condition => $_)) {
1990     last;
1991     }
1992     }
1993     }
1994     @{$opt{not_implemented}} ? 0 : 1;
1995     }}
1996    
1997     sub condition_match ($%) {
1998     my ($node, %opt) = @_;
1999     my $conds = $node->get_attribute_value ('Condition', default => [],
2000     as_array => 1);
2001     my $level = $node->get_attribute_value
2002     ('Level',
2003     default_list => @$conds ? []
2004     : ($opt{level_default} || []),
2005     as_array => 1);
2006     for (@$conds) {
2007     unless ($Info->{Condition}->{$_}) {
2008     valid_err qq<Condition "$_" not defined>;
2009     }
2010     }
2011     for (@$level) {
2012     unless ($Info->{Condition}->{"DOM".$_}) {
2013     valid_err qq<Condition "DOM$_" not defined>;
2014     }
2015     }
2016     if (not $opt{condition}) {
2017     if (@$conds == 0 and @$level == 0) {
2018     return 1;
2019     } elsif (array_contains $conds, '$normal') {
2020     return 1;
2021     } elsif ($opt{ge} and not @$conds) {
2022     return 1;
2023     } elsif ($opt{any_unless_condition}) {
2024     return 1;
2025     } else {
2026     return 0;
2027     }
2028     } else {
2029     if (array_contains $conds, $opt{condition}) {
2030     return 1;
2031     } elsif ($opt{condition} =~ /^DOM(\d+)$/) {
2032     if ($opt{ge}) {
2033     for (my $i = $1; $i; $i--) {
2034     if (array_contains $level, $i) {
2035     return 1;
2036     }
2037     }
2038     } else {
2039     if ($1 and array_contains $level, $1) {
2040     return 1;
2041     }
2042     }
2043     }
2044     ## 'default_any': Match to 'any' condition (no condition specified)
2045     if ($opt{default_any} and @$conds == 0 and @$level == 0) {
2046     return 1;
2047     }
2048     return 0;
2049     }
2050     }
2051    
2052     =head1 SOURCE FORMAT
2053    
2054     "Dis" (DOM implementation source) file is written in
2055     SuikaWikiConfig/2.0 text format.
2056    
2057     =head2 IF element
2058    
2059     C<IF> element defines a DOM interface with its descriptions
2060     and implementations.
2061    
2062     Children elements:
2063    
2064     =over 4
2065    
2066     =item IF/Name = name (1 - 1)
2067    
2068     Interface name. It should be taken from DOM specification.
2069    
2070     =item IF/Description = text (0 - infinite)
2071    
2072     Description for the interface.
2073    
2074     =item IF/ISA[list] = list of names (0 - 1)
2075    
2076     Names of interfaces that this interface inherits.
2077    
2078     =item IF/Method, IF/IntMethod, IF/ReMethod
2079    
2080     Method definition.
2081    
2082     =item IF/Attr, IF/IntAttr, IF/ReAttr
2083    
2084     Attribute definition.
2085    
2086     =item IF/ConstGroup
2087    
2088     Constant value group definition.
2089    
2090     =item IF/Const
2091    
2092     Constant value definition.
2093    
2094     =back
2095    
2096     =cut
2097    
2098     sub if2perl ($) {
2099     my $node = shift;
2100     local $Status->{depth} = $Status->{depth} + 1;
2101     my $pack_name = perl_package_name
2102     name => my $if_name
2103     = perl_name $node->get_attribute_value ('Name'),
2104     ucfirst => 1;
2105     my $if_pack_name = perl_package_name if => $if_name;
2106     my $iif_pack_name = perl_package_name iif => $if_name;
2107     local $Status->{IF} = $if_name;
2108     local $Status->{if} = {}; ## Temporary data
2109     local $Info->{Namespace} = {%{$Info->{Namespace}}};
2110     local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
2111     local $Info->{Require_perl_package_use} = {};
2112     local $Status->{is_implemented} = 1;
2113     my $is_abs = $node->get_attribute ('IsAbstract', default => 0);
2114     my $is_fin = $node->get_attribute ('IsFinal', default => 0);
2115     $is_fin = -1 if $is_abs; # 1=no subclass, 0=free, -1=must be subclass
2116     my $impl_by_app = $node->get_attribute ('ImplByApp', default => 0);
2117    
2118     my @level;
2119     my $mod = get_level_description $node, level => \@level;
2120    
2121     push my @desc,
2122     pod_head ($Status->{depth}, 'Interface ' . pod_code ($if_name).
2123     ($is_abs?'':', Class '.pod_code ($pack_name)));
2124    
2125     push @desc, pod_paras (get_description ($node));
2126     push @desc, pod_para ('This interface is ' . $mod . q<.>) if $mod;
2127    
2128     if ($impl_by_app) {
2129     push @desc, pod_para ('This interface is intended to be implemented '.
2130     'by DOM applications. To implement this '.
2131     'interface, put the statement '),
2132 wakaba 1.3 pod_pre ('push our @ISA, q<'.($is_abs?$if_pack_name:$pack_name).
2133     '>;'),
2134 wakaba 1.1 pod_para ('on your package and define methods and '.
2135     'attributes.');
2136     }
2137    
2138     push @desc, get_isa_description ($node);
2139    
2140     my $result = pod_block @desc;
2141    
2142     my $has_role = $node->get_attribute ('Role');
2143    
2144     for my $condition ((sort keys %{$Info->{Condition}}), '') {
2145     if ($condition =~ /^DOM(\d+)$/) {
2146     next if @level and $level[0] > $1;
2147     }
2148     local $Status->{Operator} = {};
2149     local $Status->{condition} = $condition;
2150     my $cond_if_pack_name = perl_package_name if => $if_name,
2151     condition => $condition;
2152     my $cond_iif_pack_name = perl_package_name iif => $if_name,
2153     condition => $condition;
2154     my $cond_pack_name = perl_package_name name => $if_name,
2155     condition => $condition;
2156     my $cond_int_pack_name = perl_package_name name => $if_name,
2157     condition => $condition,
2158     is_internal => 1;
2159     my $cond_iint_pack_name = perl_package_name name => $if_name,
2160     condition => $condition,
2161     is_internal => 1,
2162     is_for_inheriting => 1;
2163     $result .= perl_package full_name => $cond_int_pack_name;
2164     my @isa;
2165     for (@{$node->child_nodes}) {
2166     next unless $_->node_type eq '#element' and
2167     condition_match $_, condition => $condition,
2168     default_any => 1, ge => 1;
2169     if ($_->local_name eq 'ISA') {
2170     if (type_expanded_uri ($_->get_attribute_value ('Type',
2171     default => ExpandedURI q<DOMMain:any>))
2172     eq ExpandedURI q<lang:Perl>) {
2173     my $v = $_->value;
2174     if ($v =~ /[^\w:]|(?<!:):(?!:)/) {
2175     valid_err q<Invalid package name "$v">, node => $_;
2176     }
2177     push @isa, $v;
2178     } else {
2179     push @isa, perl_package_name qname_with_condition => $_->value,
2180     condition => $condition,
2181     is_internal => 1,
2182     is_for_inheriting => 1;
2183     }
2184     } elsif ($_->local_name eq 'Implement') {
2185     push @isa, perl_package_name if_qname_with_condition => $_->value,
2186     condition => $condition;
2187     }
2188     }
2189     push my @isag, perl_package_name (name => 'ManakaiDOMObject')
2190     unless $if_name eq 'ManakaiDOMObject';
2191     my @isaa;
2192     if ($condition) {
2193     for (@{$Info->{Condition}->{$condition}->{ISA}}) {
2194     push @isaa, perl_package_name name => $if_name,
2195     condition => $_,
2196     is_internal => 1;
2197     }
2198     $result .= perl_inherit [$cond_int_pack_name, @isaa, @isa, @isag]
2199     => $cond_pack_name;
2200     $result .= perl_inherit [@isaa, $cond_iif_pack_name]
2201     => $cond_int_pack_name;
2202     $result .= perl_inherit [$cond_int_pack_name, @isa]
2203     => $cond_iint_pack_name;
2204     $result .= perl_inherit [$cond_if_pack_name, $iif_pack_name]
2205     => $cond_iif_pack_name;
2206     $result .= perl_inherit [$if_pack_name] => $cond_if_pack_name;
2207     } else { ## No condition specified
2208     $result .= perl_inherit [$cond_int_pack_name, @isa, @isag]
2209     => $cond_pack_name;
2210     if ($Info->{NormalCondition}) {
2211     push @isaa, perl_package_name name => $if_name,
2212     condition => $Info->{NormalCondition},
2213     is_internal => 1;
2214     $result .= perl_inherit [@isaa]
2215     => $cond_int_pack_name;
2216     } else { ## Condition not used
2217     $result .= perl_inherit [$iif_pack_name] => $cond_int_pack_name;
2218     }
2219     $result .= perl_inherit [$cond_int_pack_name, @isa]
2220     => $cond_iint_pack_name;
2221     $result .= perl_inherit [$if_pack_name] => $iif_pack_name;
2222     }
2223     for my $pack ($cond_pack_name, $cond_int_pack_name,
2224     $cond_iif_pack_name, $cond_if_pack_name,
2225     $cond_iint_pack_name) {
2226 wakaba 1.4 $Status->{def_pack}->{$pack} = 1;
2227 wakaba 1.1 }
2228    
2229     my @feature;
2230     for (@{$node->child_nodes}) {
2231     my $gt = 0;
2232     unless (condition_match $_, level_default => \@level,
2233     condition => $condition) {
2234     if (condition_match $_, level_default => \@level,
2235     condition => $condition, ge => 1) {
2236     $gt = 1;
2237     } else {
2238     next;
2239     }
2240     }
2241    
2242     if ($_->local_name eq 'Method' or
2243     $_->local_name eq 'IntMethod' or
2244     $_->local_name eq 'ReMethod') {
2245     $result .= method2perl ($_, level => \@level, condition => $condition)
2246     unless $gt;
2247     } elsif ($_->local_name eq 'Attr' or
2248     $_->local_name eq 'IntAttr' or
2249     $_->local_name eq 'ReAttr') {
2250     $result .= attr2perl ($_, level => \@level, condition => $condition)
2251     unless $gt;
2252     } elsif ($_->local_name eq 'ConstGroup') {
2253     $result .= constgroup2perl ($_, level => \@level,
2254     condition => $condition,
2255     without_document => $gt,
2256     package => $cond_int_pack_name);
2257     } elsif ($_->local_name eq 'Const') {
2258     $result .= const2perl ($_, level => \@level, condition => $condition,
2259     package => $cond_int_pack_name)
2260     unless $gt;
2261     } elsif ($_->local_name eq 'Require') {
2262     $result .= req2perl ($_, level => \@level, condition => $condition);
2263     } elsif ($_->local_name eq 'Feature') {
2264     push @feature, $_;
2265     } elsif ({qw/Name 1 Spec 1 ISA 1 Description 1 Implement 1
2266     Level 1 SpecLevel 1 ImplNote 1 Role 1
2267     IsAbstract 1 IsFinal 1 ImplByApp 1/}->{$_->local_name}) {
2268     #
2269     } else {
2270     valid_warn qq{Element @{[$_->local_name]} not supported};
2271     }
2272     }
2273    
2274     if ($has_role) {
2275     my $role = type_expanded_uri $has_role->value;
2276     if ($role eq ExpandedURI q<DOMCore:DOMImplementationSource>) {
2277     $result .= perl_statement
2278     q<push @org::w3c::dom::DOMImplementationSourceList, >.
2279     perl_literal $cond_pack_name;
2280     } else {
2281     my $var = q<@{>.perl_var (type => '$',
2282     local_name => $ManakaiDOMModulePrefix.'::Role').
2283     q<{>.perl_literal ($role).q<}}>;
2284     my %prop;
2285     if ($has_role->get_attribute ('compat')) {
2286     $prop{compat} = type_expanded_uri
2287     $has_role->get_attribute_value ('compat');
2288     } else {
2289     $prop{compat} = '';
2290     }
2291     $result .= perl_statement
2292     'push '.$var.q<, >.
2293     perl_list {
2294     class => $cond_pack_name,
2295     constructor => 'new',
2296     %prop,
2297     };
2298     }
2299     }
2300    
2301     if (@feature or $has_role) {
2302     $result .= '{' . perl_statement 'our $Feature';
2303     for (@feature) {
2304     my $name = $_->get_attribute ('QName');
2305     if ($name) {
2306     $name = type_expanded_uri ($name->value);
2307     } else {
2308     $name = $_->get_attribute_value ('Name');
2309     }
2310     $result .= perl_statement '$Feature->{'.perl_literal ($name).'}->{'.
2311     perl_literal ($_->get_attribute_value ('Version')).
2312     '} = 1';
2313     }
2314    
2315     $result .= perl_sub
2316     name => '___classHasFeature',
2317     prototype => '$%',
2318     code =>
2319     perl_statement ('my ($self, %f) = @_').
2320     q[
2321     for (keys %f) {
2322     if ($Feature->{$_}) {
2323     if (defined $f{$_}->{version}) {
2324     delete $f{$_}
2325     if $Feature->{$_}->{$f{$_}->{version}};
2326     } else {
2327     delete $f{$_} if keys %{$Feature->{$_}};
2328     }
2329     return 1 if keys (%f) == 0;
2330     }
2331     }
2332     ].
2333     (@isa + @isaa ?
2334     q[for (].perl_list (@isa, @isaa).q[) {
2335     if (my $c = $_->can ('___classHasFeature')) {
2336     if ($c->($self, %f)) {
2337     return 1;
2338     }
2339     }
2340     }] : '').
2341     (($has_role and $has_role->get_attribute ('compat'))?
2342     q[
2343     my %g;
2344     for (keys %f) {
2345     unless ($f{$_}->{plus}) {
2346     return 0;
2347     } else {
2348     $g{$_} = {version => $f{$_}->{version}};
2349     }
2350     }
2351     for (reverse @{$].$ManakaiDOMModulePrefix.'::Role{'.
2352     perl_literal (type_expanded_uri
2353     $has_role->value).'}'.q[||[]}) {
2354     if ($_->{compat} eq ].
2355     perl_literal ($has_role->get_attribute_value
2356     ('compat')).q[) {
2357     if ($_->{class}->___classHasFeature (%g)) {
2358     return 1;
2359     }
2360     }
2361     }
2362     ]:'').
2363     perl_statement (q<return 0>);
2364     $result .= '}';
2365     }
2366    
2367     $result .= ops2perl;
2368     }
2369    
2370     $result;
2371     } # if2perl
2372    
2373     =head2 Method, IntMethod and ReMethod elements
2374    
2375     C<Method>, C<IntMethod> and C<ReMethod> element defines a method.
2376     Methods defined by C<Method> are ones as defined in the DOM
2377     specification. Methods defined by C<IntMethod> are only for
2378     internal use and usually not defined by the specifications.
2379     Methods defined by C<ReMethod> do actually not belong
2380     to this interface but to ancestor interface in the specification
2381     but overriddenly re-defined for this type of descendant interfaces
2382     (for example, some methods defined in Node interface of the DOM
2383     Core Module are re-defined in Element, Attr or other node-type
2384     interfaces, since those methods work differently by type of
2385     the node).
2386    
2387     Children elements:
2388    
2389     =over 4
2390    
2391     =item Name = name (1 - 1)
2392    
2393     Method name. It should be taken from DOM specification
2394     if element type is C<Method> or C<ReMethod>. Method name
2395     for C<ReMethod> must be used as the name of the C<Method>
2396     defined in ancestor interface. Method name for C<IntMethod>
2397     must be different with any other C<Method>, C<IntMethod>
2398     or C<ReMethod> (including those defined by ancestor interfaces).
2399    
2400     =item Description = text (0 - infinite)
2401    
2402     Description for the method.
2403    
2404     =back
2405    
2406     =cut
2407    
2408     sub method2perl ($;%) {
2409     my ($node, %opt) = @_;
2410     local $Status->{depth} = $Status->{depth} + 1;
2411     my $m_name = perl_name $node->get_attribute_value ('Name');
2412     my $level;
2413     my @level = @{$opt{level} || []};
2414     local $Status->{Method} = $m_name;
2415     local $Status->{is_implemented} = 1;
2416     my $result = '';
2417     if ($node->local_name eq 'IntMethod') {
2418     $m_name = perl_internal_name $m_name;
2419     $level = '';
2420     } else {
2421     $level = get_level_description $node, level => \@level;
2422     }
2423    
2424     my @param_list;
2425     my $param_prototype = '$';
2426     my @param_desc;
2427     my @param_domstring;
2428     if ($node->get_attribute ('Param')) {
2429     for (@{$node->child_nodes}) {
2430     if ($_->local_name eq 'Param') {
2431     my $name = perl_name $_->get_attribute_value ('Name');
2432     my $type = type_expanded_uri $_->get_attribute_value
2433     ('Type',
2434     default => 'DOMMain:any');
2435     push @param_list, '$' . $name;
2436     push @param_desc, pod_item (pod_code '$' . $name);
2437     if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2438     push @param_domstring, [$name, $type];
2439     }
2440     push my @param_desc_val,
2441     pod_item (type_label $type, is_pod => 1),
2442 wakaba 1.3 pod_paras get_description $_;
2443 wakaba 1.1 $param_prototype .= '$';
2444     for (@{$_->child_nodes}) {
2445     next unless $_->local_name eq 'InCase';
2446     push @param_desc_val, pod_item (get_incase_label $_, is_pod => 1),
2447 wakaba 1.3 pod_paras (get_description $_);
2448 wakaba 1.1 }
2449     push @param_desc, pod_list 4, @param_desc_val;
2450     }
2451     }
2452     }
2453    
2454     my $return = $node->get_attribute ('Return');
2455     unless ($return) {
2456     ## NOTE: A method without return value does not have 'Return'
2457     ## before its code is implemented.
2458     valid_warn q<Required "Return" element not found>, node => $node;
2459     $return = $node->get_attribute ('Return', make_new_node => 1);
2460     }
2461     my $has_return = $return->get_attribute_value ('Type', default => 0) ? 1 : 0;
2462     push my @desc,
2463     pod_head ($Status->{depth}, 'Method ' .
2464     pod_code (($has_return ? '$return = ' : '') .
2465     '$obj->' . $m_name .
2466     ' (' . join (', ', @param_list) . ')')),
2467     pod_paras (get_description ($node)),
2468     $level ? pod_para ('The method ' . pod_code ($m_name) .
2469     q< has been > . $level . '.') : ();
2470    
2471     if (@param_list) {
2472 wakaba 1.3 push @desc, pod_para ('This method has ' .
2473 wakaba 1.1 english_number (@param_list + 0,
2474     singular => q<parameter>,
2475     plural => q<parameters>) . ':'),
2476     pod_list (4, @param_desc);
2477     } else {
2478     push @desc, pod_para (q<This method has no parameter.>);
2479     }
2480    
2481     my $is_abs = $node->get_attribute_value ('IsAbstract', default => 0);
2482     if ($is_abs) {
2483     unless (get_perl_definition_node $return,
2484     condition => $opt{condition},
2485     level_default => $opt{level_default},
2486     use_dis => 1) {
2487     for ($return->append_new_node (type => '#element',
2488     local_name => 'Def')) {
2489     $_->set_attribute ('Type' => ExpandedURI q<lang:dis>);
2490     $_->set_attribute ('Overridden' => 1);
2491     }
2492     }
2493     }
2494    
2495     my @return;
2496     my @exception;
2497     my $has_exception = 0;
2498     my $code_node = get_perl_definition_node $return,
2499     condition => $opt{condition},
2500     level_default => $opt{level_default},
2501     use_dis => 1;
2502     my $int_code_node = get_perl_definition_node $return, name => 'IntDef',
2503     condition => $opt{condition},
2504     level_default => $opt{level_default},
2505     use_dis => 1;
2506     my $code;
2507     my $int_code;
2508     for ({code => \$code, code_node => $code_node,
2509     internal => sub {
2510     return get_internal_code $node, $_[0] if $_[0];
2511     if ($int_code_node) {
2512     perl_code $int_code_node->value,
2513     internal => sub {
2514     $_[0] ? get_internal_code $node, $_[0] :
2515     valid_err q<Preprocessing macro INT cannot be used here>;
2516     };
2517     } else {
2518     valid_err "<IF[Name = $Status->{IF}]/Method[Name = $m_name]/" .
2519     "Return/IntDef> required";
2520     }
2521     }},
2522     {code => \$int_code, code_node => $int_code_node,
2523     internal => sub {$_[0]?get_internal_code $node,$_[0]:
2524     valid_err q<Preprocessing macro INT cannot be> .
2525     q<used here>}}) {
2526     if ($_->{code_node}) {
2527     my $mcode;
2528     if (type_expanded_uri ($_->{code_node}->get_attribute_value
2529     ('Type', default => q<DOMMain:any>))
2530     eq ExpandedURI q<lang:dis>) {
2531     $mcode = dis2perl $_->{code_node};
2532     } else {
2533     $mcode = perl_code $_->{code_node}->value,
2534     internal => $_->{internal};
2535     }
2536     if ($mcode =~ /^\s*$/) {
2537     ${$_->{code}} = '';
2538     } else {
2539     ${$_->{code}} = perl_code_source ($mcode,
2540     path => $_->{code_node}->node_path
2541     (key => 'Name'));
2542     }
2543     }
2544     }
2545     if ($code_node) {
2546     if ($has_return) {
2547     $code = perl_statement (perl_assign 'my $r' => get_value_literal $return,
2548     name => 'DefaultValue',
2549     type_name => 'Type') .
2550     $code;
2551     if ($code_node->get_attribute_value ('cast-output', default => 1)) {
2552     my $type = type_normalize
2553     type_expanded_uri $return->get_attribute_value
2554     ('Type',
2555     default => q<DOMMain:any>);
2556     if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2557     $code .= perl_builtin_code $type,
2558     s => 'r', r => 'r',
2559     condition => $opt{condition};
2560     }
2561     }
2562     $code .= perl_statement ('$r');
2563     } else {
2564     $code .= perl_statement ('undef');
2565     }
2566     if ($code_node->get_attribute_value ('auto-argument', default => 1)) {
2567     if ($code_node->get_attribute_value ('cast-input', default => 1)) {
2568     for (@param_domstring) {
2569     $code = perl_builtin_code ($_->[1],
2570     s => $_->[0], r => $_->[0],
2571     condition => $opt{condition}) . $code;
2572     }
2573     }
2574     $code = perl_statement (perl_assign 'my (' .
2575     join (', ', '$self', @param_list) .
2576     ')' => '@_') .
2577     $code;
2578     }
2579     if ($int_code_node) {
2580     if ($has_return) {
2581     $int_code = perl_statement (perl_assign 'my $r' => perl_literal '') .
2582     $int_code .
2583     perl_statement ('$r');
2584     } else {
2585     $int_code .= perl_statement ('undef');
2586     }
2587     $int_code = perl_statement (perl_assign 'my (' .
2588     join (', ', '$self', @param_list) .
2589     ')' => '@_') .
2590     $int_code
2591     if $int_code_node->get_attribute_value ('auto-argument', default => 1);
2592     }
2593    
2594     if ($has_return) {
2595     push @return, pod_item (type_label (type_expanded_uri
2596     ($return->get_attribute_value
2597     ('Type',
2598     default => 'DOMMain:any')),
2599     is_pod => 1)),
2600 wakaba 1.3 pod_paras (get_description $return);
2601 wakaba 1.1 }
2602     for (@{$return->child_nodes}) {
2603     if ($_->local_name eq 'InCase') {
2604     push @return, pod_item ( get_incase_label $_, is_pod => 1),
2605 wakaba 1.3 pod_paras (get_description $_);
2606 wakaba 1.1 $has_return++;
2607     } elsif ($_->local_name eq 'Exception') {
2608     push @exception, pod_item ('Exception: ' .
2609     (type_label ($_->get_attribute_value
2610     ('Type',
2611     default => 'DOMMain:any'),
2612     is_pod => 1)).
2613     '.' . pod_code $_->get_attribute_value
2614     ('Name',
2615     default => '<unknown>')),
2616 wakaba 1.3 pod_paras (get_description $_);
2617 wakaba 1.1 my @st;
2618     for (@{$_->child_nodes}) {
2619     next unless $_->node_type eq '#element';
2620     if ($_->local_name eq 'SubType') {
2621     push @st, subtype2poditem ($_);
2622     } elsif ({qw/Name 1 Type 1
2623     Description 1 ImplNote 1
2624     Condition 1 Level 1 SpecLevel 1/}->{$_->local_name}) {
2625     #
2626     } else {
2627     valid_err qq{Element type "@{[$_->local_name]}" not supported},
2628     node => $_;
2629     }
2630     }
2631     push @exception, pod_list 4, @st if @st;
2632     $has_exception++;
2633     }
2634     }
2635     } else {
2636     $Status->{is_implemented} = 0;
2637     $int_code = $code
2638     = perl_statement ('my $self = shift').
2639     perl_statement perl_exception
2640     level => 'EXCEPTION',
2641     class => 'DOMException',
2642     type => 'NOT_SUPPORTED_ERR',
2643 wakaba 1.2 subtype_uri
2644     => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_METHOD_NOT_IMPLEMENTED>,
2645 wakaba 1.1 param => {
2646     ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
2647     ExpandedURI q<MDOM_EXCEPTION:method> => $Status->{Method},
2648     };
2649     @return = ();
2650     push @exception, pod_item ('Exception: ' . pod_code ('DOMException') . '.' .
2651     pod_code ('NOT_SUPPORTED_ERR')),
2652     pod_para ('Call of this method allways result in
2653     this exception raisen, since this
2654     method is not implemented yet.');
2655     $has_return = 0;
2656     $has_exception = 1;
2657     }
2658     is_implemented if => $Status->{IF}, method => $Status->{Method},
2659     condition => $opt{condition}, set => $Status->{is_implemented};
2660     if ($has_return or $has_exception) {
2661     if ($has_return) {
2662     push @desc, pod_para (q<This method results in > .
2663     ($has_return == 1 ? q<the value:>
2664     : q<either:>)),
2665     pod_list 4, pod_item (pod_code q<$return>),
2666     pod_list (4, @return),
2667     @exception;
2668     } elsif ($has_exception) {
2669     push @desc, pod_para (q<This method does not return any value,
2670     but it might raise > .
2671     ($has_exception == 1 ? q<an exception:>
2672     : q<one of exceptions from:>)),
2673     pod_list 4, @exception;
2674     }
2675     } else {
2676     push @desc, pod_para q<This method does not return any value
2677     nor does raise any exceptions.>;
2678     }
2679    
2680     push @desc, get_alternate_description $node;
2681     push @desc, get_redef_description $node;
2682    
2683     if ($node->local_name eq 'IntMethod' or
2684     $Status->{if}->{method_documented}->{$m_name}++) {
2685     $result .= pod_block pod_comment @desc;
2686     } else {
2687     $result .= pod_block @desc;
2688     }
2689    
2690     $result .= perl_sub name => $m_name,
2691     prototype => $param_prototype,
2692     code => $code;
2693     $result .= perl_sub name => perl_internal_name $m_name,
2694     prototype => $param_prototype,
2695     code => $int_code
2696     if $int_code_node;
2697    
2698     if (my $op = get_perl_definition_node $node, name => 'Operator') {
2699     my $value = $op->value;
2700     valid_err qq{Overloaded operator name not specified},
2701     node => $op
2702     unless defined $value;
2703     $Status->{Operator}->{$value} = '\\' . perl_var type => '&',
2704     local_name => $m_name;
2705     }
2706    
2707     $result;
2708     } # method2perl
2709    
2710     sub attr2perl ($;%) {
2711     my ($node, %opt) = @_;
2712     local $Status->{depth} = $Status->{depth} + 1;
2713     my $m_name = perl_name $node->get_attribute_value ('Name');
2714     my $level;
2715     my @level = @{$opt{level} || []};
2716     local $Status->{Method} = $m_name;
2717     local $Status->{is_implemented} = 1;
2718     my $result = '';
2719     if ($node->local_name eq 'IntAttr') {
2720     $m_name = perl_internal_name $m_name;
2721     $level = '';
2722     } else {
2723     $level = get_level_description $node, level => \@level;
2724     }
2725    
2726     my $return = $node->get_attribute ('Get');
2727     unless ($return) {
2728     valid_err q<Required "Get" element not found>, node => $node;
2729     }
2730     my $set = $node->get_attribute ('Set');
2731     my $has_set = defined $set ? 1 : 0;
2732     push my @desc,
2733     pod_head ($Status->{depth}, 'Attribute ' .
2734     pod_code ('$obj->' . $m_name)),
2735     pod_paras (get_description ($node)),
2736     $level ? pod_para ('The method ' . pod_code ($m_name) .
2737     q< has been > . $level . '.') : ();
2738    
2739     my $is_abs = $node->get_attribute_value ('IsAbstract', default => 0);
2740     if ($is_abs) {
2741     unless (get_perl_definition_node $return,
2742     condition => $opt{condition},
2743     level_default => $opt{level_default},
2744     use_dis => 1) {
2745     for ($return->append_new_node (type => '#element',
2746     local_name => 'Def')) {
2747     $_->set_attribute ('Type' => ExpandedURI q<lang:dis>);
2748     $_->set_attribute ('Overridden' => 1);
2749     }
2750     }
2751     }
2752    
2753     my $code_node = get_perl_definition_node $return,
2754     condition => $opt{condition},
2755     level_default => $opt{level_default},
2756     use_dis => 1;
2757     my $int_code_node = get_perl_definition_node $return, name => 'IntDef',
2758     condition => $opt{condition},
2759     level_default => $opt{level_default},
2760     use_dis => 1;
2761     my ($set_code_node, $int_set_code_node);
2762     if ($has_set) {
2763     if ($is_abs) {
2764     unless (get_perl_definition_node $set,
2765     condition => $opt{condition},
2766     level_default => $opt{level_default},
2767     use_dis => 1) {
2768     for ($return->append_new_node (type => '#element',
2769     local_name => 'Def')) {
2770     $_->set_attribute ('Type' => ExpandedURI q<lang:dis>);
2771     $_->set_attribute ('Overridden' => 1);
2772     }
2773     }
2774     }
2775     $set_code_node = get_perl_definition_node $set,
2776     condition => $opt{condition},
2777     level_default => $opt{level_default},
2778     use_dis => 1;
2779     $int_set_code_node = get_perl_definition_node $set, name => 'IntDef',
2780     condition => $opt{condition},
2781     level_default => $opt{level_default},
2782     use_dis => 1;
2783     }
2784     my $code = '';
2785     my $int_code = '';
2786     my $set_code = '';
2787     my $int_set_code = '';
2788     for ({code => \$code, code_node => $code_node,
2789     internal => sub {
2790     return get_internal_code $node, $_[0] if $_[0];
2791     if ($int_code_node) {
2792     perl_code $int_code_node->value,
2793     internal => sub {
2794     $_[0] ? get_internal_code $node, $_[0] :
2795     valid_err q<Preprocessing macro INT cannot be used here>;
2796     };
2797     } else {
2798     valid_err "<IF[Name = $Status->{IF}]/Attr[Name = $m_name]/" .
2799     "Get/IntDef> required";
2800     }
2801     }},
2802     {code => \$int_code, code_node => $int_code_node,
2803     internal => sub {$_[0]?get_internal_code $node,$_[0]:
2804     valid_err q<Preprocessing macro INT cannot be> .
2805     q<used here>}},
2806     {code => \$set_code, code_node => $set_code_node,
2807     internal => sub {
2808     return get_internal_code $node, $_[0] if $_[0];
2809     if ($int_set_code_node) {
2810     perl_code $int_set_code_node->value,
2811     internal => sub {
2812     $_[0] ? get_internal_code $node, $_[0] :
2813     valid_err q<Preprocessing macro INT cannot be used here>;
2814     };
2815     } else {
2816     valid_err "<IF[Name = $Status->{IF}]/Attr[Name = $m_name]/" .
2817     "Set/IntDef> required";
2818     }
2819     }},
2820     {code => \$int_set_code, code_node => $int_set_code_node,
2821     internal => sub {$_[0]?get_internal_code $node,$_[0]:
2822     valid_err q<Preprocessing macro INT cannot be> .
2823     q<used here>}}) {
2824     if ($_->{code_node}) {
2825     my $mcode;
2826     if (type_expanded_uri ($_->{code_node}->get_attribute_value
2827     ('Type', default => q<DOMMain:any>))
2828     eq ExpandedURI q<lang:dis>) {
2829     $mcode = dis2perl $_->{code_node};
2830     } else {
2831     $mcode = perl_code $_->{code_node}->value,
2832     internal => $_->{internal},
2833     node => $_->{code_node};
2834     }
2835     if ($mcode =~ /^\s*$/) {
2836     ${$_->{code}} = '';
2837     } else {
2838     ${$_->{code}} = perl_code_source ($mcode,
2839     path => $_->{code_node}->node_path
2840     (key => 'Name'));
2841     }
2842     }
2843     }
2844    
2845     my @return;
2846     my @return_xcept;
2847     if ($code_node) {
2848     is_implemented if => $Status->{IF}, attr => $Status->{Method},
2849     condition => $opt{condition}, set => 1, on => 'get';
2850     my $co = $code_node->get_attribute_value ('cast-output',
2851     default => $code eq '' ? 0 : 1);
2852     if ($code eq '' and not $co) {
2853     $code = perl_statement get_value_literal $return,
2854     name => 'DefaultValue',
2855     type_name => 'Type';
2856     } else {
2857     $code = perl_statement (perl_assign 'my $r' => get_value_literal $return,
2858     name => 'DefaultValue',
2859     type_name => 'Type') .
2860     $code;
2861     if ($co) {
2862     my $type = type_normalize
2863     type_expanded_uri $return->get_attribute_value
2864     ('Type',
2865     default => q<DOMMain:any>);
2866     if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2867     $code .= perl_builtin_code $type,
2868     s => 'r', r => 'r',
2869     condition => $opt{condition};
2870     }
2871     }
2872     $code .= perl_statement ('$r');
2873     }
2874     $code = get_warning_perl_code ($return) . $code;
2875     if ($int_code_node) {
2876     $int_code = perl_statement (perl_assign 'my $r' => perl_literal '') .
2877     $int_code .
2878     perl_statement ('$r');
2879     $int_code = perl_statement (perl_assign 'my ($self)' => '@_') . $int_code
2880     if $int_code_node->get_attribute_value ('auto-argument', default => 1);
2881     }
2882    
2883     push @return, pod_item (type_label (type_expanded_uri
2884     $return->get_attribute_value
2885     ('Type',
2886     default => 'DOMMain:any'),
2887     is_pod => 1)),
2888 wakaba 1.3 pod_paras (get_description $return);
2889 wakaba 1.1 for (@{$return->child_nodes}) {
2890     if ($_->local_name eq 'InCase') {
2891     push @return, pod_item (get_incase_label $_, is_pod => 1),
2892 wakaba 1.3 pod_paras (get_description $_);
2893 wakaba 1.1 } elsif ($_->local_name eq 'Exception') {
2894     push @return_xcept, pod_item ('Exception: ' .
2895     (type_label ($_->get_attribute_value
2896     ('Type',
2897     default => 'DOMMain:any'),
2898     is_pod => 1)) .
2899     '.' . pod_code $_->get_attribute_value
2900     ('Name',
2901     default => '<unknown>')),
2902 wakaba 1.3 pod_paras (get_description $_);
2903 wakaba 1.1 my @st;
2904     for (@{$_->child_nodes}) {
2905     next unless $_->node_type eq '#element';
2906     if ($_->local_name eq 'SubType') {
2907     push @st, subtype2poditem ($_);
2908     } elsif ({qw/Name 1 Type 1
2909     Description 1 ImplNote 1
2910     Condition 1 Level 1 SpecLevel 1/}->{$_->local_name}) {
2911     #
2912     } else {
2913     valid_err qq{Element type "@{[$_->local_name]}" not supported},
2914     node => $_;
2915     }
2916     }
2917     push @return_xcept, pod_list 4, @st if @st;
2918     }
2919     }
2920     } else {
2921     is_implemented if => $Status->{IF}, attr => $Status->{Method},
2922     condition => $opt{condition}, set => 0, on => 'get';
2923     $Status->{is_implemented} = 0;
2924     $int_code = $code
2925     = perl_statement perl_exception
2926     level => 'EXCEPTION',
2927     class => 'DOMException',
2928     type => 'NOT_SUPPORTED_ERR',
2929 wakaba 1.2 subtype_uri
2930     => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_ATTR_NOT_IMPLEMENTED>,
2931 wakaba 1.1 param => {
2932     ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
2933     ExpandedURI q<MDOM_EXCEPTION:attr> => $Status->{Method},
2934     ExpandedURI q<MDOM_EXCEPTION:on> => 'get',
2935     };
2936     @return = ();
2937     push @return_xcept,
2938     pod_item ('Exception: ' . pod_code ('DOMException') . '.' .
2939     pod_code ('NOT_SUPPORTED_ERR')),
2940     pod_para ('Getting of this attribute allways result in
2941     this exception raisen, since this
2942     attribute is not implemented yet.');
2943     }
2944     push @desc, pod_para ('DOM applications can get the value by:'),
2945     pod_pre (qq{\$return = \$obj->$m_name}),
2946     pod_list (4,
2947     @return ? (pod_item pod_code q<$return>,
2948     pod_list 4, @return): (),
2949     @return_xcept);
2950    
2951     my @set_desc;
2952     my @set_xcept;
2953     if ($set_code_node) {
2954     is_implemented if => $Status->{IF}, attr => $Status->{Method},
2955     condition => $opt{condition}, set => 1, on => 'set';
2956     if ($set_code_node->get_attribute_value ('cast-input',
2957     default => $set_code eq '' ? 0 : 1)) {
2958     my $type = type_normalize
2959     type_expanded_uri $set->get_attribute_value
2960     ('Type',
2961     default => q<DOMMain:any>);
2962     if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2963     $set_code = perl_builtin_code ($type,
2964     s => 'given', r => 'given',
2965     condition => $opt{condition})
2966     . $set_code;
2967     }
2968     }
2969     $set_code = get_warning_perl_code ($set) . $set_code;
2970    
2971     push @set_desc, pod_item (type_label (type_expanded_uri
2972     ($set->get_attribute_value
2973     ('Type',
2974     default => 'DOMMain:any')),
2975     is_pod => 1)),
2976 wakaba 1.3 pod_paras (get_description $set);
2977 wakaba 1.1 for (@{$set->child_nodes}) {
2978     if ($_->local_name eq 'InCase') {
2979     push @set_desc, pod_item (get_incase_label $_, is_pod => 1),
2980 wakaba 1.3 pod_paras (get_description $_);
2981 wakaba 1.1 } elsif ($_->local_name eq 'Exception') {
2982     push @set_xcept, pod_item ('Exception: ' .
2983     (type_label ($_->get_attribute_value
2984     ('Type',
2985     default => 'DOMMain:any'),
2986     is_pod => 1)) .
2987     '.' . pod_code $_->get_attribute_value
2988     ('Name',
2989     default => '<unknown>')),
2990 wakaba 1.3 pod_paras (get_description $_);
2991 wakaba 1.1 my @st;
2992     for (@{$_->child_nodes}) {
2993     next unless $_->node_type eq '#element';
2994     if ($_->local_name eq 'SubType') {
2995     push @st, subtype2poditem ($_);
2996     } elsif ({qw/Name 1 Type 1
2997     Description 1 ImplNote 1
2998     Condition 1 Level 1 SpecLevel 1/}->{$_->local_name}) {
2999     #
3000     } else {
3001     valid_err qq{Element type "@{[$_->local_name]}" not supported},
3002     node => $_;
3003     }
3004     }
3005     push @set_xcept, pod_list 4, @st if @st;
3006     }
3007     }
3008     } elsif ($has_set) {
3009     is_implemented if => $Status->{IF}, attr => $Status->{Method},
3010     condition => $opt{condition}, set => 0, on => 'set';
3011     $Status->{is_implemented} = 0;
3012     $int_set_code = $set_code
3013     = perl_statement perl_exception
3014     level => 'EXCEPTION',
3015     class => 'DOMException',
3016     type => 'NOT_SUPPORTED_ERR',
3017 wakaba 1.2 subtype_uri
3018     => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_ATTR_NOT_IMPLEMENTED>,
3019 wakaba 1.1 param => {
3020     ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
3021     ExpandedURI q<MDOM_EXCEPTION:attr> => $Status->{Method},
3022     ExpandedURI q<MDOM_EXCEPTION:on> => 'set',
3023     };
3024     @set_desc = pod_item '(Not implemented yet)';
3025     @set_xcept = ();
3026     push @set_xcept, pod_item ('Exception: ' . pod_code ('DOMException') . '.' .
3027     pod_code ('NOT_SUPPORTED_ERR')),
3028     pod_para ('Setting of this attribute allways result in
3029     this exception raisen, since this
3030     attribute is not implemented yet.');
3031     }
3032    
3033     if ($has_set) {
3034     push @desc, pod_para ('DOM applications can set the value by:'),
3035     pod_pre (qq{\$obj->$m_name (\$newValue)}),
3036     pod_list 4,
3037     pod_item (pod_code q<$newValue>),
3038     pod_list 4, @set_desc;
3039     push @desc, (@set_xcept ?
3040     (pod_para (q<Setting this attribute may raise exception:>),
3041     pod_list (4, @set_xcept)) :
3042     (pod_para (q<Setting this attribute does not raise >.
3043     q<exception in general.>)));
3044     } else {
3045     push @desc, pod_para ('This attribute is read-only.');
3046     }
3047     is_implemented if => $Status->{IF}, method => $Status->{Method},
3048     condition => $opt{condition}, set => $Status->{is_implemented};
3049    
3050     push @desc, get_alternate_description $node;
3051     push @desc, get_redef_description $node, method => 'attribute';
3052    
3053     if ($node->local_name eq 'IntAttr' or
3054     $Status->{if}->{method_documented}->{$m_name}++) {
3055     $result .= pod_block pod_comment @desc;
3056     } else {
3057     $result .= pod_block @desc;
3058     }
3059    
3060     my $warn = get_warning_perl_code ($node);
3061     my $proto;
3062     if ($has_set) {
3063     $code = perl_statement (perl_assign
3064     perl_var (scope => 'my', type => '$', local_name => 'self')
3065     => 'shift').
3066     $warn.
3067     perl_if
3068     q<exists $_[0]>,
3069     ($set_code =~/\bgiven\b/ ?
3070     perl_statement (q<my $given = shift>) : '') . $set_code .
3071     perl_statement ('undef'),
3072     $code;
3073     $int_code = perl_statement (perl_assign
3074     perl_var (scope => 'my', type => '$', local_name => 'self')
3075     => 'shift').
3076     perl_if
3077     q<exists $_[0]>,
3078     perl_statement (q<my $given = shift>) . $int_set_code,
3079     $int_code;
3080     $proto = '$;$';
3081     } else {
3082     $code = q<my $self = shift; > . $warn . $code;
3083     $int_code = q<my $self = shift; > . $int_code;
3084     $proto = '$';
3085     }
3086     $result .= perl_sub name => $m_name,
3087     prototype => $proto,
3088     code => $code;
3089     $result .= perl_sub name => perl_internal_name $m_name,
3090     prototype => $proto,
3091     code => $int_code
3092     if $int_code_node;
3093    
3094     if (my $op = get_perl_definition_node $node, name => 'Operator') {
3095     $Status->{Operator}->{$op->value} = '\\' . perl_var type => '&',
3096     local_name => $m_name;
3097     }
3098    
3099     $result;
3100     } # attr2perl
3101    
3102     =head2 DataType element
3103    
3104     The C<DataType> element defines a datatype.
3105    
3106     =cut
3107    
3108     sub datatype2perl ($;%) {
3109     my ($node, %opt) = @_;
3110     local $Status->{depth} = $Status->{depth} + 1;
3111     my $pack_name = perl_package_name
3112     name => my $if_name
3113     = perl_name $node->get_attribute_value ('Name'),
3114     ucfirst => 1;
3115     local $Status->{IF} = $if_name;
3116     local $Status->{if} = {}; ## Temporary data
3117     local $Info->{Namespace} = {%{$Info->{Namespace}}};
3118     local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
3119     local $Info->{Require_perl_package_use} = {};
3120     local $Status->{Operator} = {};
3121     my $result = perl_package full_name => $pack_name;
3122     my @isa;
3123     for (@{$node->child_nodes}) {
3124     next unless $_->node_type eq '#element' and
3125     $_->local_name eq 'ISA' and
3126     condition_match $_, condition => $opt{condition},
3127     default_any => 1, ge => 1;
3128     push @isa, perl_package_name qname_with_condition => $_->value,
3129     condition => $opt{condition};
3130     }
3131     $result .= perl_inherit [@isa, perl_package_name (name => 'ManakaiDOMObject'),
3132     perl_package_name (if => $if_name)];
3133 wakaba 1.4 $Status->{def_pack}->{$pack_name} = 1;
3134     $Status->{def_pack}->{perl_package_name if => $if_name} = 1;
3135 wakaba 1.1
3136     my @level = @{$opt{level} || []};
3137     my $mod = get_level_description $node, level => \@level;
3138     $result .= pod_block
3139     pod_head ($Status->{depth}, 'Type ' . pod_code $if_name),
3140     pod_paras (get_description ($node)),
3141     ($mod ? pod_para ('This type is ' . $mod) : ());
3142    
3143     for (@{$node->child_nodes}) {
3144     if ($_->local_name eq 'Method' or
3145     $_->local_name eq 'IntMethod') {
3146     $result .= method2perl ($_, level => \@level,
3147     condition => $opt{condition});
3148     } elsif ($_->local_name eq 'Attr' or
3149     $_->local_name eq 'IntAttr') {
3150     $result .= attr2perl ($_, level => \@level, condition => $opt{condition});
3151     } elsif ($_->local_name eq 'ConstGroup') {
3152     $result .= constgroup2perl ($_, level => \@level,
3153     condition => $opt{condition},
3154     package => $pack_name);
3155     } elsif ($_->local_name eq 'Const') {
3156     $result .= const2perl ($_, level => \@level,
3157     condition => $opt{condition},
3158     package => $pack_name);
3159     } elsif ($_->local_name eq 'ISA') {
3160     push @{$Info->{DataTypeAlias}->{type_expanded_uri $if_name}
3161     ->{isa_uri}||=[]},
3162     type_expanded_uri $_->value;
3163     } elsif ({qw/Name 1 FullName 1 Spec 1 Description 1
3164     Level 1 SpecLevel 1 Def 1 ImplNote 1/}->{$_->local_name}) {
3165     #
3166     } else {
3167     valid_warn qq{Element @{[$_->local_name]} not supported};
3168     }
3169     }
3170    
3171     $result .= ops2perl;
3172    
3173     $result;
3174     } # datatype2perl
3175    
3176     sub datatypealias2perl ($;%) {
3177     my ($node, %opt) = @_;
3178     local $Status->{depth} = $Status->{depth} + 1;
3179     my $if_name = $node->get_attribute_value ('Name');
3180     my $long_name = expanded_uri $if_name;
3181     my $real_long_name = type_expanded_uri
3182     (my $real_name = $node->get_attribute_value
3183     ('Type', default => 'DOMMain:any'));
3184     if (type_label ($real_long_name) eq type_label ($long_name)) {
3185     $Info->{DataTypeAlias}->{$long_name}->{canon_uri} = $real_long_name;
3186     return perl_comment sprintf '%s <%s> := %s <%s>',
3187     type_label ($long_name), $long_name,
3188     type_label ($real_long_name), $real_long_name;
3189     }
3190     $Info->{DataTypeAlias}->{$long_name}->{canon_uri} = $real_long_name;
3191    
3192     $if_name = perl_name $if_name, ucfirst => 1;
3193     $real_name = type_package_name $real_name;
3194     my $pack_name = perl_package_name name => $if_name;
3195     local $Status->{IF} = $if_name;
3196     local $Status->{if} = {}; ## Temporary data
3197     local $Info->{Namespace} = {%{$Info->{Namespace}}};
3198     local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
3199     local $Info->{Require_perl_package_use} = {};
3200     my $result = perl_package full_name => $pack_name;
3201     $result .= perl_inherit [perl_package_name (full_name => $real_name),
3202     perl_package_name (if => $if_name)];
3203 wakaba 1.4 $Status->{def_pack}->{perl_package_name if => $if_name} = 1;
3204 wakaba 1.1
3205     my @level = @{$opt{level} || []};
3206     my $mod = get_level_description $node, level => \@level;
3207     $result .= pod_block
3208     pod_head ($Status->{depth}, 'Type ' . pod_code $if_name),
3209     pod_paras (get_description ($node)),
3210     pod_para ('This type is an alias of the type ' .
3211     (type_label $real_long_name, is_pod => 1) . '.'),
3212     ($mod ? pod_para ('This type is ' . $mod) : ());
3213    
3214     for (@{$node->child_nodes}) {
3215     if ({qw/Name 1 FullName 1 Spec 1 Type 1 Description 1
3216     Level 1 SpecLevel 1 Condition 1 ImplNote 1
3217     Def 1/}->{$_->local_name}) {
3218     #
3219     } else {
3220     valid_warn qq{Element @{[$_->local_name]} not supported};
3221     }
3222     }
3223    
3224     $result;
3225     } # datatypealias2perl
3226    
3227     =item Exception top-level element
3228    
3229     =item Warning top-level element
3230    
3231     =cut
3232    
3233     sub exception2perl ($;%) {
3234     my ($node, %opt) = @_;
3235     local $Status->{depth} = $Status->{depth} + 1;
3236     local $Status->{const} = {};
3237     local $Status->{if} = {}; ## Temporary data
3238     local $Status->{in_exception} = 1;
3239     local $Info->{Namespace} = {%{$Info->{Namespace}}};
3240     local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
3241     local $Info->{Require_perl_package_use} = {};
3242     my $pack_name = perl_package_name
3243     name => my $if_name
3244     = perl_name $node->get_attribute_value ('Name'),
3245     ucfirst => 1;
3246     my $type = $node->local_name eq 'Exception' ? 'Exception' : 'Warning';
3247     local $Status->{IF} = $if_name;
3248     my $result = perl_package full_name => $pack_name;
3249 wakaba 1.4 $Status->{def_pack}->{$pack_name} = 1;
3250 wakaba 1.1 my @isa = perl_package_name (if => $if_name);
3251     if ($if_name eq 'ManakaiDOM'.$type) {
3252     push @isa, perl_package_name name => 'ManakaiDOMExceptionOrWarning';
3253     } elsif ($if_name eq 'ManakaiDOMExceptionOrWarning') {
3254     push @isa, 'Message::Util::Error';
3255     } else {
3256     push @isa, perl_package_name name => 'ManakaiDOM'.$type
3257     }
3258     $result .= perl_inherit [@isa];
3259 wakaba 1.4 $Status->{def_pack}->{perl_package_name if => $if_name} = 1;
3260 wakaba 1.1 my @level = @{$opt{level} || []};
3261     my $mod = get_level_description $node, level => \@level;
3262     $result .= pod_block
3263     pod_head ($Status->{depth}, $type . ' ' . pod_code $if_name),
3264     pod_paras (get_description ($node)),
3265     ($mod ? pod_para ('This ' . lc ($type) . ' is introduced in ' .
3266     $mod . '.') : ()),
3267     ($type eq 'Exception' ?
3268     (pod_para ('To catch this class of exceptions:'),
3269     pod_pre (join "\n",
3270     q|try { |,
3271     q| ... |,
3272     q|} catch | . $pack_name . q| with { |,
3273     q| my $err = shift; |,
3274     q| if ($err->{type} eq 'ERROR_NAME') { |,
3275     q| ... # Recover from some error, |,
3276     q| } else { |,
3277     q| $err->throw; # rethrow if other |,
3278     q| } |,
3279     q|}; # Don't forget semicolon! |))
3280     : ());
3281    
3282     for (@{$node->child_nodes}) {
3283     if ($_->local_name eq 'Method' or
3284     $_->local_name eq 'IntMethod' or
3285     $_->local_name eq 'ReMethod') {
3286     $result .= method2perl ($_, level => \@level,
3287     condition => $opt{condition},
3288     any_unless_condition => 1);
3289     } elsif ($_->local_name eq 'Attr' or
3290     $_->local_name eq 'IntAttr' or
3291     $_->local_name eq 'ReAttr') {
3292     my $get;
3293     if ($_->local_name eq 'Attr' and
3294     $_->get_attribute_value ('Name') eq 'code' and
3295     $get = $_->get_attribute ('Get') and
3296     not get_perl_definition_node $get, name => 'Def') {
3297     for ($get->append_new_node (type => '#element',
3298     local_name => 'Def',
3299     value => q{
3300     $r = $self->{<Q:ManakaiDOM:code>};
3301     })) {
3302     $_->set_attribute (type => 'lang:Perl'); ## ISSUE: NS prefix assoc.
3303     }
3304     }
3305     $result .= attr2perl ($_, level => \@level, condition => $opt{condition},
3306     any_unless_condition => 1);
3307     } elsif ($_->local_name eq 'ConstGroup') {
3308     $result .= constgroup2perl ($_, level => \@level,
3309     condition => $opt{condition},
3310     package => $pack_name,
3311     any_unless_condition => 1);
3312     } elsif ($_->local_name eq 'Const') {
3313     $result .= const2perl ($_, level => \@level,
3314     condition => $opt{condition},
3315     package => $pack_name,
3316     any_unless_condition => 1);
3317     } elsif ({qw/Name 1 Spec 1 Description 1
3318     Level 1 SpecLevel 1 Condition 1
3319     ImplNote 1/}->{$_->local_name}) {
3320     #
3321     } else {
3322     valid_warn qq{Element @{[$_->local_name]} not supported};
3323     }
3324     }
3325    
3326     $result .= perl_sub
3327     name => '___error_def', prototype => '',
3328     code => perl_list {
3329     map {
3330     $_ => {
3331     ExpandedURI q<DOMCore:code> => perl_code_literal
3332     ($Status->{const}->{$_}->{code_literal}),
3333     description
3334     => $Status->{const}->{$_}->{description},
3335     ExpandedURI q<MDOM_EXCEPTION:subtype>
3336     => $Status->{const}->{$_}->{subtype},
3337     }
3338     } sort keys %{$Status->{const}}
3339     };
3340    
3341     $result;
3342     } # exception2perl
3343    
3344     sub constgroup2perl ($;%);
3345     sub constgroup2perl ($;%) {
3346     my ($node, %opt) = @_;
3347     local $Status->{depth} = $Status->{depth} + 1;
3348     my $name = $node->get_attribute ('Name');
3349     if (defined $name) {
3350     $name = perl_name $name->value, ucfirst => 1;
3351     }
3352     local $Status->{IF} = $name || q<[anonymous constant group]>;
3353     my @level = @{$opt{level} || []};
3354     my $mod = get_level_description $node, level => \@level;
3355     my $result = '';
3356     my $consts = {};
3357     $Info->{DataTypeAlias}->{expanded_uri $node->get_attribute_value ('Name')}
3358     ->{isa_uri} = [type_expanded_uri $node->get_attribute_value
3359     ('Type', default => q<DOMMain:any>)]
3360     if defined $name;
3361    
3362     my $i = 0;
3363     {
3364     local $Status->{EXPORT_OK} = $consts;
3365     for (@{$node->child_nodes}) {
3366     my $only_document = $opt{only_document} || 0;
3367     unless ($_->node_type eq '#element' and
3368     condition_match $_, level_default => \@level,
3369     condition => $opt{condition},
3370     any_unless_condition
3371     => $opt{any_unless_condition}) {
3372     $only_document = 1;
3373     }
3374    
3375     if ($_->local_name eq 'ConstGroup') {
3376     $result .= constgroup2perl ($_, level => \@level,
3377     condition => $opt{condition},
3378     without_document => $opt{without_document},
3379     only_document => $only_document,
3380     package => $opt{package},
3381     any_unless_condition
3382     => $opt{any_unless_condition});
3383     $i++;
3384     } elsif ($_->local_name eq 'Const') {
3385     $result .= const2perl ($_, level => \@level,
3386     condition => $opt{condition},
3387     without_document => $opt{without_document},
3388     only_document => $only_document,
3389     package => $opt{package},
3390     any_unless_condition
3391     => $opt{any_unless_condition});
3392     $i++;
3393     } elsif ({qw/Name 1 Spec 1 ISA 1 Description 1 Type 1 IsBitMask 1
3394     Level 1 SpecLevel 1 Def 1 ImplNote 1
3395     FullName 1/}->{$_->local_name}) {
3396     #
3397     } else {
3398     valid_warn qq{Element @{[$_->local_name]} not supported};
3399     }
3400     }
3401     }
3402    
3403     for (keys %$consts) {
3404     $Status->{EXPORT_OK}->{$_} = 1;
3405     $Status->{EXPORT_TAGS}->{$name}->{$_} = 1 if defined $name;
3406     }
3407    
3408     return $result if $opt{without_document};
3409    
3410     my @desc;
3411     if (defined $name) {
3412     push @desc, pod_head $Status->{depth}, 'Constant Group ' . pod_code $name;
3413     } else {
3414     push @desc, pod_head $Status->{depth}, 'Constant Group: ' .
3415     get_description ($node,
3416     name => 'FullName');
3417     }
3418    
3419     push @desc, pod_paras (get_description ($node)),
3420     ($mod ? pod_para ('This constant group has been ' . $mod . '.')
3421     : ()),
3422     pod_para ('This constant group has ' .
3423     english_number $i, singular => q<value.>,
3424     plural => q<values.>);
3425    
3426     push @desc, pod_para ('To export all constant values in this group:'),
3427     pod_pre (perl_statement "use $Info->{Package} qw/:$name/")
3428     if defined $name;
3429    
3430     $result = pod_block (@desc) . $result;
3431    
3432     $result;
3433     } # constgroup2perl
3434    
3435     sub const2perl ($;%) {
3436     my ($node, %opt) = @_;
3437     local $Status->{depth} = $Status->{depth} + 1;
3438     my $name = perl_name $node->get_attribute_value ('Name');
3439     my $longname = perl_var local_name => $name,
3440     package => {full_name => $opt{package} ||
3441     $Info->{Package}};
3442     local $Status->{IF} = $name;
3443     local $Status->{const_subtype} = {};
3444     my @level = @{$opt{level} || []};
3445     my $mod = get_level_description $node, level => \@level;
3446     my @desc;
3447     unless ($opt{without_document}) {
3448     @desc = (pod_head ($Status->{depth}, 'Constant Value ' . pod_code $name),
3449     pod_paras (get_description ($node)),
3450     ($mod ? pod_para ('This constant value has been ' . $mod . '.')
3451     : ()));
3452    
3453     if ($Status->{in_exception}) { ## Is Exception/Warning code
3454     #
3455     } else { ## Is NOT Exception/Warning code
3456     push @desc, pod_para ('To export this constant value:'),
3457     pod_pre (perl_statement "use $Info->{Package} qw/$name/");
3458     }
3459    
3460     my @param;
3461     for (@{$node->child_nodes}) {
3462     next unless $_->node_type eq '#element';
3463     if ($_->local_name eq 'Param') {
3464     if ($Status->{in_exception}) {
3465     push @param, param2poditem ($_);
3466     } else {
3467     valid_err qq{Element "Param" may not be used with non-Exception}.
3468     qq{/Warning constants},
3469     node => $node;
3470     }
3471     } elsif ($_->local_name eq 'SubType') {
3472     if ($Status->{in_exception}) {
3473     push @param, subtype2poditem ($_);
3474     } else {
3475     valid_err qq{Element "SubType" may not be used with non-Exception}.
3476     qq{/Warning constants},
3477     node => $node;
3478     }
3479     } elsif ({qw/Name 1 Spec 1 Description 1
3480     Condition 1 Level 1 SpecLevel 1
3481     Type 1 Value 1 ImplNote 1/}->{$_->local_name}) {
3482     #
3483     } else {
3484     valid_err qq{Element type "@{[$_->local_name]}" not supported},
3485     node => $node;
3486     }
3487     }
3488     push @desc, pod_list 4, @param if @param;
3489     }
3490    
3491     my $result = '';
3492     unless ($opt{only_document}) {
3493     $result = perl_sub name => $longname, prototype => '',
3494     code => my $code = get_value_literal
3495     $node, name => 'Value';
3496     $result .= perl_sub name => perl_var (package => {full_name
3497     => $Info->{Package}},
3498     local_name => $name), prototype => '',
3499     code => $code
3500     if $opt{package} and $Info->{Package} ne $opt{package};
3501     my $desc_template = get_description $node,
3502     type => ExpandedURI q<lang:muf>,
3503     default => $name;
3504     $Status->{const}->{$name} = {
3505     description => $desc_template,
3506     code_literal => $code,
3507     subtype => $Status->{const_subtype} || {},
3508     };
3509     }
3510    
3511     $Status->{EXPORT_OK}->{$name} = 1;
3512    
3513     unless ($opt{without_document}) {
3514     $result = pod_block (@desc) . $result;
3515     }
3516    
3517     $result;
3518     } # const2perl
3519    
3520     sub param2poditem ($;%) {
3521     my ($node, %opt) = @_;
3522     my @desc;
3523     $opt{name_prefix} = 'Parameter: ' unless defined $opt{name_prefix};
3524     if ($node->get_attribute ('Name')) {
3525     push @desc, $opt{name_prefix} . pod_code $node->get_attribute_value ('Name');
3526     } elsif ($node->get_attribute ('QName')) {
3527     push @desc, pod_item $opt{name_prefix} .
3528     qname_label ($node,
3529     out_type => ExpandedURI q<lang:pod>);
3530     } else {
3531     valid_err q<Attribute "Name" or "QName" required>,
3532     node => $node;
3533     }
3534    
3535     my @val;
3536     push @val, pod_item (type_label (type_expanded_uri
3537     ($node->get_attribute_value
3538     ('Type',
3539     default => 'DOMMain:any')),
3540     is_pod => 1)),
3541 wakaba 1.3 pod_paras (get_description $node);
3542 wakaba 1.1 for (@{$node->child_nodes}) {
3543     last unless $_->node_type eq '#element';
3544     if ($_->local_name eq 'InCase') {
3545     push @val, pod_item (get_incase_label $_, is_pod => 1),
3546 wakaba 1.3 pod_paras (get_description $_);
3547 wakaba 1.1 } elsif ({qw/Name 1 QName 1 Type 1
3548     Description 1 ImplNote 1/}->{$_->local_name}) {
3549     #
3550     } else {
3551     valid_err qq{Element type "@{[$_->local_name]}" not supported},
3552     node => $_;
3553     }
3554     }
3555    
3556     if (@val) {
3557     push @desc, pod_list 4, @val;
3558     }
3559    
3560     @desc;
3561     } # param2poditem
3562    
3563     sub subtype2poditem ($;%) {
3564     my ($node, %opt) = @_;
3565     my @desc;
3566     $opt{name_prefix} = 'SubType: ' unless defined $opt{name_prefix};
3567     my $qname = $node->get_attribute_value ('QName');
3568     if (defined $qname) {
3569     push @desc, pod_item $opt{name_prefix} .
3570     qname_label ($node, qname => $qname,
3571     out_type => ExpandedURI q<lang:pod>);
3572     } else {
3573     valid_err q<Attribute "QName" required>,
3574     node => $node;
3575     }
3576    
3577 wakaba 1.3 push @desc, pod_paras (get_description $node);
3578 wakaba 1.1 my @param;
3579     for (@{$node->child_nodes}) {
3580     last unless $_->node_type eq '#element';
3581     if ($_->local_name eq 'Param') {
3582     push @param, param2poditem ($_);
3583     } elsif ({qw/QName 1 Type 1 SpecLevel 1
3584     Description 1 ImplNote 1/}->{$_->local_name}) {
3585     #
3586     } else {
3587     valid_err qq{Element type "@{[$_->local_name]}" not supported},
3588     node => $_;
3589     }
3590     }
3591    
3592     if (@param) {
3593     push @desc, pod_list 4, @param;
3594     }
3595    
3596     my $desc_template = get_description $node,
3597     type => ExpandedURI q<lang:muf>,
3598     default => $qname;
3599     $Status->{const_subtype}->{type_expanded_uri $qname} = {
3600     description => $desc_template,
3601     };
3602    
3603    
3604     @desc;
3605     } # subtype2poditem
3606    
3607     =head2 Require element
3608    
3609     The C<Require> element indicates that some external modules
3610     are required. Both DOM-implementing modules and language-specific
3611     library modules are allowed.
3612    
3613     Children:
3614    
3615     =over 4
3616    
3617     =item Require/Module (0 - infinite)
3618    
3619     A required module.
3620    
3621     Children:
3622    
3623     =over 4
3624    
3625     =item Require/Module/Name = name (0 - 1)
3626    
3627     The DOM module name. Iif it is a DOM-implementing module,
3628     this attribute MUST be specified.
3629    
3630     =item Require/Module/Namespace = namespace-uri (0 - 1)
3631    
3632     The namespace URI for the module, if any. Namespace prefix
3633     C<Name> is to be binded with C<Namespace> if both
3634     C<Name> and C<Namespace> are available.
3635    
3636     =item Require/Module/Def = Type-dependent (0 - infinite)
3637    
3638     Language-depending definition of loading of the required module.
3639     If no appropriate C<Type> of C<Def> element is available,
3640     loading code is generated from C<Name> attribute.
3641    
3642     =back
3643    
3644     =back
3645    
3646     =cut
3647    
3648     sub req2perl ($) {
3649     my $node = shift;
3650     my $reqnode = $node->local_name eq 'Require' ? $node :
3651     $node->get_attribute ('Require', make_new_node => 1);
3652     my $result = '';
3653     for (@{$reqnode->child_nodes}) {
3654     if ($_->local_name eq 'Module') {
3655     my $m_name = $_->get_attribute_value ('Name', default => '<anon>');
3656     my $ns_uri = $_->get_attribute_value ('Namespace');
3657     $Info->{Namespace}->{$m_name} = $ns_uri if defined $ns_uri;
3658     $m_name = perl_name $m_name, ucfirst => 1;
3659     my $desc = get_description $_;
3660     $result .= perl_comment (($m_name ne '<anon>' ? $m_name : '') .
3661     ($desc ? ' - ' . $desc : ''))
3662     if $desc or $m_name ne '<anon>';
3663     my $def = get_perl_definition_node $_, name => 'Def';
3664     if ($def) {
3665     my $s;
3666     my $req;
3667     my $pack_name;
3668     if ($req = $def->get_attribute ('require')) {
3669     $s = 'require ' . ($pack_name = perl_code $req->value);
3670     $Info->{uri_to_perl_package}->{$ns_uri} = $pack_name if $ns_uri;
3671     $Info->{Require_perl_package}->{$pack_name} = 1;
3672     } elsif ($req = $def->get_attribute ('use')) {
3673     $s = 'use ' . ($pack_name = perl_code $req->value);
3674     $Info->{uri_to_perl_package}->{$ns_uri} = $pack_name if $ns_uri;
3675     $Info->{Require_perl_package}->{$pack_name} = 1;
3676     $Info->{Require_perl_package_use}->{$pack_name} = 1;
3677     } elsif (defined ($s = $def->value)) {
3678     #
3679     } else {
3680     valid_warn qq<Required module definition for $m_name is empty>;
3681     }
3682     if ($req and my $list = $req->get_attribute_value ('Import',
3683     as_array => 1)) {
3684     if (@$list) {
3685     $s .= ' ' . perl_list @$list;
3686     $Info->{Require_perl_package_use}
3687     ->{$pack_name . '::::Import'}->{$_} = 1 for @$list;
3688     }
3689     }
3690     $result .= perl_statement $s;
3691     } else {
3692     $result .= perl_statement 'require ' .
3693     perl_code "__CLASS{$m_name}__";
3694     }
3695     } elsif ($_->local_name eq 'Condition') {
3696     } else {
3697     valid_warn qq[Requiredness type @{[$_->local_name]} not supported];
3698     }
3699     }
3700     $result;
3701     }
3702    
3703     =head2 Module element
3704    
3705     A "dis" file requires one (and only one) C<Module> top-level element.
3706     Other elements, such as C<Require>, may include C<Module> elements
3707     as their children.
3708    
3709     Children:
3710    
3711     =over 4
3712    
3713     =item Module/Name = name (0 - 1)
3714    
3715     The module name. Usually DOM IDL module name is used.
3716    
3717     This attribute is required when C<Module> element is used as
3718     a top-level element. It is optional if C<Module> is a child
3719     of other element.
3720    
3721     =item Module/Package = Type-dependent (0 - infinite)
3722    
3723     The module package name. For example,
3724    
3725     Module:
3726     @Name: module1
3727     @Package:
3728     @@@: Module1
3729     @@Type:
3730     lang:Perl
3731    
3732     means that general module name is C<module1> and Perl-specific
3733     module name is C<Module1>.
3734    
3735     =item Module/Namespace = namespace (1 - 1)
3736    
3737     The namespace URI (an absolute URI with optional fragment identifier)
3738     that is assigned to this module. Datatypes defined by this module
3739     (such as C<DataType> or C<Interface>) are considered to belong to
3740     this namespace.
3741    
3742     In addition, the default namespace is binding to this namespace name
3743     (in other word, special namespace prefix C<#default> is associated
3744     with the URI reference).
3745    
3746     =item Module/FullName = text (0 - infinite)
3747    
3748     A human-readable module name.
3749    
3750     =item Module/Description = text (0 - infinite)
3751    
3752     A human-readable module description.
3753    
3754     =item Module/License = qname (1 - 1)
3755    
3756     A qname that identify the license term.
3757    
3758     =item Module/Date.RCS = <rcs date> (1 - 1)
3759    
3760     The last-modified date-time of this module,
3761     represented in RCS format (text C<Date:> with date and time,
3762     enclosed by C<$>s).
3763    
3764     =item Module/Require (0 - infinite)
3765    
3766     A list of modules (DOM modules or other liburary modules)
3767     that is required by entire module.
3768    
3769     =back
3770    
3771     =cut
3772    
3773     ## Get general information
3774     $Info->{source_filename} = $ARGV;
3775    
3776     ## Initial Namespace bindings
3777     for ([ManakaiDOM => ExpandedURI q<ManakaiDOM:>],
3778     [http => q<http:>]) {
3779     $Info->{Namespace}->{$_->[0]} = $_->[1];
3780     }
3781    
3782     ## Initial DataType aliasing and inheritance
3783     for (ExpandedURI q<ManakaiDOM:ManakaiDOMURI>,
3784     ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>,
3785     ExpandedURI q<ManakaiDOM:ManakaiDOMFeatureName>,
3786     ExpandedURI q<ManakaiDOM:ManakaiDOMFeatureVersion>,
3787 wakaba 1.3 ExpandedURI q<ManakaiDOM:ManakaiDOMFeatures>,
3788     ExpandedURI q<ManakaiDOM:ManakaiDOMKeyIdentifier>,
3789     ExpandedURI q<ManakaiDOM:ManakaiDOMKeyIdentifiers>) {
3790 wakaba 1.1 $Info->{DataTypeAlias}->{$_}
3791     ->{isa_uri} = [ExpandedURI q<DOMMain:DOMString>];
3792     }
3793    
3794     register_namespace_declaration ($source);
3795    
3796     my $Module = $source->get_attribute ('Module', make_new_node => 1);
3797     $Info->{Name} = perl_name $Module->get_attribute_value ('Name'), ucfirst => 1
3798     or valid_err q<Module name (/Module/Name) MUST be specified>;
3799     $Info->{Namespace}->{(DEFAULT_PFX)}
3800     = $Module->get_attribute_value ('Namespace')
3801     or valid_err q<Module namespace URI (/Module/Namespace) MUST be specified>;
3802     $Info->{Namespace}->{$Module->get_attribute_value ('Name')}
3803     = $Info->{Namespace}->{(DEFAULT_PFX)};
3804     my $pack_node = get_perl_definition_node $Module, name => 'BindingName';
3805     if ($pack_node) {
3806     $Info->{Package} = perl_code $pack_node->value;
3807     } else {
3808     $Info->{Package} = perl_package_name name => $Info->{Name};
3809     }
3810     $Info->{uri_to_perl_package}->{$Info->{Namespace}->{(DEFAULT_PFX)}}
3811     = $Info->{Package};
3812     $Info->{Require_perl_package} = {};
3813     $Info->{Require_perl_package_use} = {};
3814    
3815     ## Make source code
3816     $result .= perl_comment q<This file is automatically generated from> . "\n" .
3817     q<"> . $Info->{source_filename} . q<" at > .
3818     rfc3339_date (time) . qq<.\n> .
3819     q<Don't edit by hand!>;
3820    
3821     $result .= perl_statement q<use strict>;
3822    
3823     local $Status->{depth} = $Status->{depth} + 1;
3824     $result .= perl_package full_name => $Info->{Package};
3825 wakaba 1.4 $Status->{def_pack}->{$Info->{Package}} = 1;
3826 wakaba 1.1
3827     $result .= pod_block
3828     pod_head (1, 'NAME'),
3829     pod_para ($Info->{Package} .
3830     ' - ' . get_description ($Module, name => 'FullName')),
3831     section (
3832     opt => pod_head (1, 'DESCRIPTION'),
3833 wakaba 1.3 req => pod_paras (get_description ($Module)),
3834 wakaba 1.1 ),
3835     pod_head (1, 'DOM INTERFACES');
3836    
3837     ## Conditions
3838     my $defcond = 0;
3839     for my $cond (@{$Module->child_nodes}) {
3840     next unless $cond->node_type eq '#element' and
3841     $cond->local_name eq 'ConditionDef';
3842     my $name = $cond->get_attribute_value ('Name', default => '');
3843     my $isa = $cond->get_attribute_value ('ISA', default => []);
3844     my $fullname = get_description $cond, name => 'FullName';
3845     $isa = [$isa] unless ref $isa;
3846     if ($name =~ /^DOM(\d+)$/) {
3847     $defcond = $1 if $1 > $defcond;
3848     $fullname ||= "DOM Level " . (0 + $1);
3849     }
3850     $Info->{Condition}->{$name}->{ISA} = $isa;
3851     $Info->{Condition}->{$name}->{FullName} = $fullname || $name;
3852     }
3853     if (keys %{$Info->{Condition}}) {
3854     $Info->{NormalCondition} = $Module->get_attribute_value
3855     ('NormalCondition') ||
3856     $defcond ? 'DOM' . $defcond :
3857     valid_err q<Module/NormalCondition required>;
3858     }
3859    
3860     ## 'require'ing external modules
3861     {
3862     my $req = $Module->get_attribute ('Require', make_new_node => 1);
3863     my $reqModule = sub {
3864     my ($name, $me, $you) = @_;
3865     if ($you->get_attribute_value ('Name', default => '') eq $name) {
3866     return 1;
3867     } else {
3868     return 0;
3869     }
3870     };
3871     if (not $req->get_element_by (sub {$reqModule->('ManakaiDOMMain', @_)})) {
3872     for ($req->append_new_node (type => '#element',
3873     local_name => 'Module')) {
3874     $_->set_attribute (Name => 'ManakaiDOMMain');
3875     $_->set_attribute (Namespace => ExpandedURI q<ManakaiDOM:>);
3876     }
3877     }
3878     if (not $req->get_element_by (sub {$reqModule->('DOMMain', @_)})) {
3879     for ($req->append_new_node (type => '#element',
3880     local_name => 'Module')) {
3881     $_->set_attribute (Name => 'DOMMain');
3882     $_->set_attribute (Namespace => ExpandedURI q<DOMMain:>);
3883     }
3884     }
3885     $result .= req2perl $Module;
3886     }
3887    
3888     for my $node (@{$source->child_nodes}) {
3889     if ($node->node_type ne '#element') {
3890     ##
3891     } elsif ($node->local_name eq 'IF') {
3892     $result .= if2perl $node;
3893     } elsif ($node->local_name eq 'Exception' or
3894     $node->local_name eq 'Warning') {
3895     $result .= exception2perl $node;
3896     } elsif ($node->local_name eq 'DataType') {
3897     $result .= datatype2perl $node;
3898     } elsif ($node->local_name eq 'DataTypeAlias') {
3899     $result .= datatypealias2perl $node;
3900     } elsif ($node->local_name eq 'ConstGroup') {
3901     $result .= constgroup2perl $node;
3902     } elsif ($node->local_name eq 'Const') {
3903     $result .= const2perl $node;
3904     } elsif ({qw/Module 1 Namespace 1 ImplNote 1/}->{$node->local_name}) {
3905     #
3906     } else {
3907     valid_warn qq{Top-level element type "@{[$node->local_name]}" not supported};
3908     }
3909     }
3910    
3911     ## Export
3912     if (keys %{$Status->{EXPORT_OK}||{}}) {
3913     $result .= perl_package full_name => $Info->{Package};
3914     $result .= perl_statement 'require Exporter';
3915     $result .= perl_inherit ['Exporter'];
3916     $result .= perl_statement
3917     perl_assign
3918     perl_var (type => '@', scope => 'our',
3919     local_name => 'EXPORT_OK')
3920     => '(' . perl_list (keys %{$Status->{EXPORT_OK}}) . ')';
3921     if (keys %{$Status->{EXPORT_TAGS}||{}}) {
3922     $result .= perl_statement
3923     perl_assign
3924     perl_var (type => '%', scope => 'our',
3925     local_name => 'EXPORT_TAGS')
3926     => '(' . perl_list (map {
3927     $_ => [keys %{$Status->{EXPORT_TAGS}->{$_}}]
3928     } keys %{$Status->{EXPORT_TAGS}}) . ')';
3929     }
3930     }
3931    
3932 wakaba 1.4 ## Packages
3933     {
3934     my $list = join ', ', map {'$'.$_.'::VERSION'}
3935     sort keys %{$Status->{def_pack}};
3936     my $date = perl_literal version_date time;
3937     $result .= qq{
3938     for ($list) {
3939     \$_ = $date;
3940     }
3941     };
3942     }
3943    
3944 wakaba 1.1 ## Feature
3945     my @feature_desc;
3946     my $features = 0;
3947     for my $condition (sort keys %{$Info->{Condition}}, '') {
3948     for my $Feature (@{$Module->child_nodes}) {
3949     next unless $Feature->node_type eq '#element' and
3950     $Feature->local_name eq 'Feature' and
3951     condition_match $Feature, condition => $condition;
3952     is_all_implemented condition => $condition,
3953     not_implemented => (my $not_implemented = []);
3954    
3955     my $f_name = $Feature->get_attribute_value ('Name', default => '');
3956     unless (length $f_name) {
3957     $f_name = expanded_uri $Feature->get_attribute_value ('QName');
3958     }
3959     my $f_ver = $Feature->get_attribute_value ('Version');
3960    
3961     push @feature_desc, pod_item ('Feature ' . pod_code ($f_name) .
3962     ' version ' . pod_code ($f_ver) .
3963     ($Info->{Condition}->{$condition}->{FullName} ?
3964     ' [' . $Info->{Condition}->{$condition}
3965     ->{FullName} . ']' : '')),
3966     pod_paras (get_description $Feature);
3967    
3968     if (@$not_implemented) {
3969     push @feature_desc, pod_para ('This module provides interfaces '.
3970     'of this feature but not yet fully ' .
3971     'implemented.');
3972     $result .= perl_comment "$f_name, $f_ver: $not_implemented->[0]." .
3973     "$not_implemented->[1]<$not_implemented->[2]>" .
3974     " not implemented.";
3975     } else {
3976     push @feature_desc, pod_para ('This module implements this feature, ' .
3977     'so that the method calls such as ' .
3978     pod_code ('$DOMImplementation' .
3979     '->hasFeature (' .
3980     perl_literal ($f_name) .
3981     ', ' . perl_literal ($f_ver) .
3982     ')') . ' or ' .
3983     pod_code ('$DOMImplementation' .
3984     '->hasFeature (' .
3985     perl_literal ($f_name) .
3986     ', null)') .
3987     ' will return ' . pod_code ('true') . '.');
3988     }
3989    
3990     for (@{$Feature->child_nodes}) {
3991     next unless $_->node_type eq '#element';
3992     if ($_->local_name eq 'Contrib') {
3993     my $n = $_->value;
3994     my $ccondition;
3995     if ($n =~ s/::([^:]*)$//) {
3996     $ccondition = $1;
3997     }
3998     if ($n =~ s/^[^:]*://) {
3999     # currently prefix is not used
4000     }
4001     $result .= perl_statement
4002     perl_assign
4003     perl_var (type => '$',
4004     package => {
4005     name => $n,
4006     condition => $ccondition,
4007     is_internal => 1,
4008     },
4009     local_name => 'Feature').
4010     ## Feature name is case-insensitive
4011     '->{'.perl_literal (lc $f_name).'}->{'.
4012     perl_literal (@$not_implemented ? '+dummy+' : $f_ver) . '}'
4013     => 1;
4014     } elsif ({
4015     qw/Name 1 QName 1 FullName 1 Version 1
4016     Description 1 ImplNote 1 Spec 1
4017     Condition 1 /
4018     }->{$_->local_name}) {
4019     } else {
4020     valid_err q<Unknown element type>, node => $_;
4021     }
4022     }
4023    
4024     $features++;
4025     }
4026     }
4027     if (@feature_desc) {
4028     $result .= pod_block
4029     pod_head (1, 'DOM FEATURE'.($features>1?'S':'')),
4030     pod_list 4, @feature_desc;
4031     }
4032    
4033     ## TODO list
4034     my @todo;
4035     ## From not-implemented list
4036     for my $if (sort keys %{$Info->{is_implemented}}) {
4037     for my $mem (sort keys %{$Info->{is_implemented}->{$if}}) {
4038     for my $cond (sort keys %{$Info->{is_implemented}->{$if}->{$mem}}) {
4039     if (not $Info->{is_implemented}->{$if}->{$mem}->{$cond}) {
4040     push @todo, pod_item ('Implement '.pod_code ($if).'.'.
4041     pod_code ($mem).'.'),
4042     pod_para ('Condition = '.
4043     ($Info->{Condition}->{$cond}->{FullName} ||
4044     '(empty)'));
4045     }
4046     }
4047     }
4048     }
4049     ## From Description, ImplNote, Def
4050     my $a;
4051     $a = sub {
4052     my $n = shift;
4053     for (@{$n->child_nodes}) {
4054     if ($_->node_type eq '#element') {
4055     $a->($_);
4056     }
4057     }
4058     if (($n->node_type eq '#element' and
4059     {qw/Description 1 ImplNote 1
4060     Def 1 IntDef 1/}->{$n->local_name}) or
4061     $n->node_type eq '#comment') {
4062     my $v = $n->value;
4063     if (defined $v) {
4064     if (ref $v eq 'ARRAY') {
4065     $v = join "\n", @$v;
4066     }
4067     if ($v =~ /\b(TODO|ISSUE|BUG):/) {
4068     push @todo, pod_item ($1.': '.pod_code $n->node_path(key => 'Name'));
4069     my $t = $n->node_type eq '#comment' ? ExpandedURI q<DOMMain:any> :
4070     $n->get_attribute_value
4071     ('Type',
4072     default => {
4073     Description => ExpandedURI q<lang:disdoc>,
4074     ImplNote => ExpandedURI q<lang:disdoc>,
4075     Def => ExpandedURI q<DOMMain:any>,
4076     IntDef => ExpandedURI q<DOMMain:any>,
4077     }->{$n->local_name});
4078     if ($t eq ExpandedURI q<lang:disdoc>) {
4079     push @todo, disdoc2pod $v;
4080     } else {
4081     push @todo, pod_pre ($v);
4082     }
4083     }
4084     }
4085     }
4086     };
4087     $a->($source);
4088     if (@todo) {
4089     $result .= pod_block
4090     pod_head (1, 'TO DO'),
4091     pod_list 4, @todo;
4092     }
4093    
4094    
4095     ## Namespace bindings for documentation
4096     if (my $n = keys %{$Status->{ns_in_doc}}) {
4097     my @desc = (pod_head (1, 'NAMESPACE BINDING'.($n > 1 ? 'S' : '')),
4098     pod_para ('In this documentation, namespace prefix'.
4099     ($n > 1 ? 'es ' : ' ').
4100     ($n > 1 ? 'are' : 'is').' bound to:'));
4101     push @desc,
4102     pod_list 4, map {
4103     pod_item (pod_code $_),
4104     pod_para (pod_code ($Status->{ns_in_doc}->{$_})),
4105     } keys %{$Status->{ns_in_doc}};
4106     $result .= pod_block @desc;
4107     }
4108    
4109     ## See also
4110     ## TODO: implement this.
4111    
4112     ## Author
4113     my @desc;
4114     my @author;
4115     my $author;
4116     my $authors = 0;
4117     for (@{$Module->child_nodes}) {
4118     if ($_->node_type eq '#element' and $_->local_name eq 'Author') {
4119     my $n = get_description ($_, name => 'FullName');
4120     push @author, pod_item $n;
4121     my @d;
4122     $author = defined $author ? $authors ? $author
4123     : ($authors++, $author . ', et al.')
4124     : $n;
4125     for (@{$_->child_nodes}) {
4126     next unless $_->node_type eq '#element';
4127     if ($_->local_name eq 'Mail') {
4128     push @d, pod_item ('Mail'), pod_para (pod_mail $_->value);
4129     } elsif ({qw/FullName 1/}->{$_->local_name}) {
4130     #
4131     } else {
4132     valid_err q<Unknown element type>, node => $_;
4133     }
4134     }
4135     push @author, pod_list 6, @d if @d;
4136     }
4137     }
4138     $author = 'AUTHORS' unless defined $author;
4139     if (@author) {
4140     push @desc, pod_head (1, 'AUTHOR'.($authors?'S':'')),
4141     pod_list (4, @author);
4142     }
4143    
4144     ## License
4145     push @desc, pod_head (1, 'LICENSE');
4146     my $year = (gmtime)[5]+1900;
4147     my $license = expanded_uri
4148     $Module->get_attribute_value ('License', default => '');
4149     if ($license eq ExpandedURI q<license:Perl>) {
4150     push @desc,
4151     pod_para (qq<Copyright $year $author. All rights reserved.>),
4152     pod_para q<This program is free software; you can redistribute it and/or
4153     modify it under the same terms as Perl itself.>;
4154     } elsif ($license eq ExpandedURI q<license:Perl+MPL>) {
4155     push @desc,
4156     pod_para (qq<Copyright $year $author. All rights reserved.>),
4157     pod_para (q<This program is free software; you can redistribute it and/or >.
4158     q<modify it under the same terms as Perl itself.>),
4159    
4160     pod_para (q<Alternatively, the contents of this file may be used >.
4161     q<under the following terms (the >.pod_dfn (q<MPL/GPL/LGPL>).
4162     q<, in which case the provisions of the MPL/GPL/LGPL are applicable instead >.
4163     q<of those above. If you wish to allow use of your version of this file only >.
4164     q<under the terms of the MPL/GPL/LGPL, and not to allow others to >.
4165     q<use your version of this file under the terms of the Perl, indicate your >.
4166     q<decision by deleting the provisions above and replace them with the notice >.
4167     q<and other provisions required by the MPL/GPL/LGPL. If you do not delete >.
4168     q<the provisions above, a recipient may use your version of this file under >.
4169     q<the terms of any one of the Perl or the MPL/GPL/LGPL. >),
4170    
4171     pod_head (2, 'MPL/GPL/LGPL'),
4172    
4173     # q<***** BEGIN LICENSE BLOCK *****>
4174     pod_para (q<Version: MPL 1.1/GPL 2.0/LGPL 2.1>),
4175    
4176     pod_para
4177     (q<The contents of this file are subject to the Mozilla Public License Version >.
4178     q<1.1 (the >.pod_dfn (q<License>).q<); you may not use this file except in >.
4179     q<compliance with >.
4180     q<the License. You may obtain a copy of the License at >.
4181     pod_uri (q<http://www.mozilla.org/MPL/>).q<.>),
4182    
4183     pod_para
4184     (q<Software distributed under the License is distributed on an ">.
4185     pod_em (q<AS IS>).q<" basis, >.
4186     pod_em (q<WITHOUT WARRANTY OF ANY KIND>).
4187     q<, either express or implied. See the License >.
4188     q<for the specific language governing rights and limitations under the >.
4189     q<License. >);
4190    
4191     my $orig = $Module->get_attribute ('License')->get_attribute ('Original');
4192     if ($orig) {
4193     push @desc, pod_para ('The Original Code is the '.
4194     get_description ($orig, name => 'FullName').'.');
4195     push @desc, pod_para ('The Initial Developer of the Original Code is '.
4196     get_description ($orig->get_attribute ('Author'),
4197     name => 'FullName').'. '.
4198     q<Portions created by the Initial Developer are >.
4199     q<Copyright >.pod_char (name => 'copy').' '.
4200     $orig->get_attribute_value ('Year',
4201     default => $year).
4202     q< the Initial Developer. All Rights Reserved.>);
4203     } else {
4204     my $a = $author;
4205     $a =~ /, et al\.$/ if $authors;
4206    
4207     push @desc, pod_para
4208     (q<The Original Code is the manakai DOM module.>),
4209    
4210     pod_para (qq<The Initial Developer of the Original Code is $a. >.
4211     q<Portions created by the Initial Developer are Copyright >.
4212     pod_char (name => 'copy').qq< $year >.
4213     ## ISSUE: Should first created year provided from some source?
4214     q<the Initial Developer. All Rights Reserved.>);
4215     }
4216    
4217     push @desc, pod_list 4,
4218     pod_item (q<Contributor(s):>),
4219     pod_para (q<See >.
4220     pod_link (section => 'AUTHOR'.($authors?'S':'')).
4221     q<.>);
4222    
4223     push @desc, pod_para
4224     q<Alternatively, the contents of this file may be used under the terms of >.
4225     q<either the GNU General Public License Version 2 or later (the ">.
4226     pod_dfn (q<GPL>).q<"), or >.
4227     q<the GNU Lesser General Public License Version 2.1 or later (the ">.
4228     pod_dfn (q<LGPL>).q<"), >.
4229     q<in which case the provisions of the GPL or the LGPL are applicable instead >.
4230     q<of those above. If you wish to allow use of your version of this file only >.
4231     q<under the terms of either the GPL or the LGPL, and not to allow others to >.
4232     q<use your version of this file under the terms of the MPL, indicate your >.
4233     q<decision by deleting the provisions above and replace them with the notice >.
4234     q<and other provisions required by the GPL or the LGPL. If you do not delete >.
4235     q<the provisions above, a recipient may use your version of this file under >.
4236     q<the terms of any one of the MPL, the GPL or the LGPL. >;
4237    
4238     # ***** END LICENSE BLOCK *****
4239     } elsif ($license) {
4240     valid_warn q<Unknown license: <$license>>;
4241     push @desc,
4242     pod_para (qq<Copyright $year $author. All rights reserved.>),
4243     pod_para (qq<License: >.pod_uri ($license).q<.>);
4244     } else {
4245     valid_err q<Required attribute "/Module/License" not specified>;
4246     }
4247     $result .= pod_block @desc;
4248    
4249    
4250     $result .= perl_statement 1;
4251    
4252 wakaba 1.4 if ($Opt{output_pod} eq 'file') {
4253     open my $pod, '>', $Opt{output_pod_file}
4254     or die "$0: $Opt{output_pod_file}: $!";
4255     print $pod $result_pod;
4256     } elsif ($Opt{output_pod} eq 'only') {
4257     $result = $result_pod;
4258     }
4259    
4260 wakaba 1.1 output_result $result;
4261    
4262    
4263     __END__
4264    
4265     =head1 SEE ALSO
4266    
4267     W3C DOM Specifications <http://www.w3.org/DOM/DOMTR>
4268    
4269     SuikaWiki:DOM <http://suika.fam.cx/~wakaba/-temp/wiki/wiki?DOM>
4270    
4271     C<idl2dis.pl>: This script generates "dis" files,
4272     that can be used as a template for the DOM implementation,
4273     from DOM IDL files.
4274    
4275     =head1 LICENSE
4276    
4277     Copyright 2004 Wakaba <w@suika.fam.cx>. All rights reserved.
4278    
4279     This program is free software; you can redistribute it and/or
4280     modify it under the same terms as Perl itself.
4281    
4282     Note that copyright holder(s) of this script does not claim
4283     any rights for materials outputed by this script, although it will
4284     contain some fragments from this script. License terms for them should be
4285     defined by the copyright holder of the source document.
4286    
4287     =cut
4288    
4289 wakaba 1.4 # $Date: 2004/10/16 13:34:55 $
4290 wakaba 1.1
4291    

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24