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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations) (download)
Sun Oct 10 00:01:08 2004 UTC (20 years, 1 month ago) by wakaba
Branch: MAIN
File MIME type: text/plain
Some files moved; DOM Level 3 LS configuration parameters and errors definition added

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24