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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations) (download)
Sat Oct 16 13:34:55 2004 UTC (20 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.2: +105 -24 lines
File MIME type: text/plain
New DISDOC elements introduced

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24