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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations) (download)
Sun Oct 10 06:09:47 2004 UTC (20 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.1: +10 -2 lines
File MIME type: text/plain
domtest2perl.pl: New

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 subtype_uri
1811 => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_METHOD_NOT_IMPLEMENTED>,
1812 param => {
1813 ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
1814 ExpandedURI q<MDOM_EXCEPTION:method> => $name,
1815 };
1816 }
1817 } # get_internal_code
1818
1819 sub register_namespace_declaration ($) {
1820 my $node = shift;
1821 for (@{$node->child_nodes}) {
1822 if ($_->node_type eq '#element' and
1823 $_->local_name eq 'Namespace') {
1824 for (@{$_->child_nodes}) {
1825 $Info->{Namespace}->{$_->local_name} = $_->value;
1826 }
1827 }
1828 }
1829 }
1830
1831 {
1832 my $nest = 0;
1833 sub is_implemented (%);
1834 sub is_implemented (%) {
1835 my (%opt) = @_;
1836 my $r = 0;
1837 $nest++ == 100 and valid_err q<Condition loop detected>;
1838 my $member = ($Info->{is_implemented}->{$opt{if}}->{$opt{method} ||
1839 $opt{attr} . '.' . $opt{on}}
1840 ||= {});
1841 if (exists $opt{set}) {
1842 $r = ($member->{$opt{condition} || ''} = $opt{set});
1843 } else {
1844 if (defined $member->{$opt{condition} || ''}) {
1845 $r = $member->{$opt{condition} || ''};
1846 } else {
1847 for (@{$Info->{Condition}->{$opt{condition} || ''}->{ISA} || []}) {
1848 if (is_implemented (%opt, condition => $_)) {
1849 $r = 1;
1850 last;
1851 }
1852 }
1853 }
1854 }
1855 $nest--;
1856 $r;
1857 }
1858 sub is_all_implemented (%);
1859 sub is_all_implemented (%) {
1860 my (%opt) = @_;
1861 $nest++ == 100 and valid_err q<Condition loop detected>;
1862 $opt{not_implemented} ||= [];
1863 IF: for my $if (keys %{$Info->{is_implemented}}) {
1864 for my $mem (keys %{$Info->{is_implemented}->{$if}}) {
1865 ## Note: In fact, this checks whether the method is NOT implemented
1866 ## rather than the method IS implemented.
1867 if (exists $Info->{is_implemented}->{$if}->{$mem}->{$opt{condition}} and
1868 not $Info->{is_implemented}->{$if}->{$mem}->{$opt{condition}}) {
1869 @{$opt{not_implemented}} = ($if, $mem, $opt{condition} || '');
1870 last IF;
1871 }
1872 }
1873 }
1874 if (not @{$opt{not_implemented}}) {
1875 for (@{$Info->{Condition}->{$opt{condition} || ''}->{ISA} || []}) {
1876 if (not is_all_implemented (%opt, condition => $_)) {
1877 last;
1878 }
1879 }
1880 }
1881 @{$opt{not_implemented}} ? 0 : 1;
1882 }}
1883
1884 sub condition_match ($%) {
1885 my ($node, %opt) = @_;
1886 my $conds = $node->get_attribute_value ('Condition', default => [],
1887 as_array => 1);
1888 my $level = $node->get_attribute_value
1889 ('Level',
1890 default_list => @$conds ? []
1891 : ($opt{level_default} || []),
1892 as_array => 1);
1893 for (@$conds) {
1894 unless ($Info->{Condition}->{$_}) {
1895 valid_err qq<Condition "$_" not defined>;
1896 }
1897 }
1898 for (@$level) {
1899 unless ($Info->{Condition}->{"DOM".$_}) {
1900 valid_err qq<Condition "DOM$_" not defined>;
1901 }
1902 }
1903 if (not $opt{condition}) {
1904 if (@$conds == 0 and @$level == 0) {
1905 return 1;
1906 } elsif (array_contains $conds, '$normal') {
1907 return 1;
1908 } elsif ($opt{ge} and not @$conds) {
1909 return 1;
1910 } elsif ($opt{any_unless_condition}) {
1911 return 1;
1912 } else {
1913 return 0;
1914 }
1915 } else {
1916 if (array_contains $conds, $opt{condition}) {
1917 return 1;
1918 } elsif ($opt{condition} =~ /^DOM(\d+)$/) {
1919 if ($opt{ge}) {
1920 for (my $i = $1; $i; $i--) {
1921 if (array_contains $level, $i) {
1922 return 1;
1923 }
1924 }
1925 } else {
1926 if ($1 and array_contains $level, $1) {
1927 return 1;
1928 }
1929 }
1930 }
1931 ## 'default_any': Match to 'any' condition (no condition specified)
1932 if ($opt{default_any} and @$conds == 0 and @$level == 0) {
1933 return 1;
1934 }
1935 return 0;
1936 }
1937 }
1938
1939 =head1 SOURCE FORMAT
1940
1941 "Dis" (DOM implementation source) file is written in
1942 SuikaWikiConfig/2.0 text format.
1943
1944 =head2 IF element
1945
1946 C<IF> element defines a DOM interface with its descriptions
1947 and implementations.
1948
1949 Children elements:
1950
1951 =over 4
1952
1953 =item IF/Name = name (1 - 1)
1954
1955 Interface name. It should be taken from DOM specification.
1956
1957 =item IF/Description = text (0 - infinite)
1958
1959 Description for the interface.
1960
1961 =item IF/ISA[list] = list of names (0 - 1)
1962
1963 Names of interfaces that this interface inherits.
1964
1965 =item IF/Method, IF/IntMethod, IF/ReMethod
1966
1967 Method definition.
1968
1969 =item IF/Attr, IF/IntAttr, IF/ReAttr
1970
1971 Attribute definition.
1972
1973 =item IF/ConstGroup
1974
1975 Constant value group definition.
1976
1977 =item IF/Const
1978
1979 Constant value definition.
1980
1981 =back
1982
1983 =cut
1984
1985 sub if2perl ($) {
1986 my $node = shift;
1987 local $Status->{depth} = $Status->{depth} + 1;
1988 my $pack_name = perl_package_name
1989 name => my $if_name
1990 = perl_name $node->get_attribute_value ('Name'),
1991 ucfirst => 1;
1992 my $if_pack_name = perl_package_name if => $if_name;
1993 my $iif_pack_name = perl_package_name iif => $if_name;
1994 local $Status->{IF} = $if_name;
1995 local $Status->{if} = {}; ## Temporary data
1996 local $Info->{Namespace} = {%{$Info->{Namespace}}};
1997 local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
1998 local $Info->{Require_perl_package_use} = {};
1999 local $Status->{is_implemented} = 1;
2000 my $is_abs = $node->get_attribute ('IsAbstract', default => 0);
2001 my $is_fin = $node->get_attribute ('IsFinal', default => 0);
2002 $is_fin = -1 if $is_abs; # 1=no subclass, 0=free, -1=must be subclass
2003 my $impl_by_app = $node->get_attribute ('ImplByApp', default => 0);
2004
2005 my @level;
2006 my $mod = get_level_description $node, level => \@level;
2007
2008 push my @desc,
2009 pod_head ($Status->{depth}, 'Interface ' . pod_code ($if_name).
2010 ($is_abs?'':', Class '.pod_code ($pack_name)));
2011
2012 push @desc, pod_paras (get_description ($node));
2013 push @desc, pod_para ('This interface is ' . $mod . q<.>) if $mod;
2014
2015 if ($impl_by_app) {
2016 push @desc, pod_para ('This interface is intended to be implemented '.
2017 'by DOM applications. To implement this '.
2018 'interface, put the statement '),
2019 pod_pre ('push our @ISA, q<'.($is_abs?$if_name:$pack_name).'>;'),
2020 pod_para ('on your package and define methods and '.
2021 'attributes.');
2022 }
2023
2024 push @desc, get_isa_description ($node);
2025
2026 my $result = pod_block @desc;
2027
2028 my $has_role = $node->get_attribute ('Role');
2029
2030 for my $condition ((sort keys %{$Info->{Condition}}), '') {
2031 if ($condition =~ /^DOM(\d+)$/) {
2032 next if @level and $level[0] > $1;
2033 }
2034 local $Status->{Operator} = {};
2035 local $Status->{condition} = $condition;
2036 my $cond_if_pack_name = perl_package_name if => $if_name,
2037 condition => $condition;
2038 my $cond_iif_pack_name = perl_package_name iif => $if_name,
2039 condition => $condition;
2040 my $cond_pack_name = perl_package_name name => $if_name,
2041 condition => $condition;
2042 my $cond_int_pack_name = perl_package_name name => $if_name,
2043 condition => $condition,
2044 is_internal => 1;
2045 my $cond_iint_pack_name = perl_package_name name => $if_name,
2046 condition => $condition,
2047 is_internal => 1,
2048 is_for_inheriting => 1;
2049 $result .= perl_package full_name => $cond_int_pack_name;
2050 my @isa;
2051 for (@{$node->child_nodes}) {
2052 next unless $_->node_type eq '#element' and
2053 condition_match $_, condition => $condition,
2054 default_any => 1, ge => 1;
2055 if ($_->local_name eq 'ISA') {
2056 if (type_expanded_uri ($_->get_attribute_value ('Type',
2057 default => ExpandedURI q<DOMMain:any>))
2058 eq ExpandedURI q<lang:Perl>) {
2059 my $v = $_->value;
2060 if ($v =~ /[^\w:]|(?<!:):(?!:)/) {
2061 valid_err q<Invalid package name "$v">, node => $_;
2062 }
2063 push @isa, $v;
2064 } else {
2065 push @isa, perl_package_name qname_with_condition => $_->value,
2066 condition => $condition,
2067 is_internal => 1,
2068 is_for_inheriting => 1;
2069 }
2070 } elsif ($_->local_name eq 'Implement') {
2071 push @isa, perl_package_name if_qname_with_condition => $_->value,
2072 condition => $condition;
2073 }
2074 }
2075 push my @isag, perl_package_name (name => 'ManakaiDOMObject')
2076 unless $if_name eq 'ManakaiDOMObject';
2077 my @isaa;
2078 if ($condition) {
2079 for (@{$Info->{Condition}->{$condition}->{ISA}}) {
2080 push @isaa, perl_package_name name => $if_name,
2081 condition => $_,
2082 is_internal => 1;
2083 }
2084 $result .= perl_inherit [$cond_int_pack_name, @isaa, @isa, @isag]
2085 => $cond_pack_name;
2086 $result .= perl_inherit [@isaa, $cond_iif_pack_name]
2087 => $cond_int_pack_name;
2088 $result .= perl_inherit [$cond_int_pack_name, @isa]
2089 => $cond_iint_pack_name;
2090 $result .= perl_inherit [$cond_if_pack_name, $iif_pack_name]
2091 => $cond_iif_pack_name;
2092 $result .= perl_inherit [$if_pack_name] => $cond_if_pack_name;
2093 } else { ## No condition specified
2094 $result .= perl_inherit [$cond_int_pack_name, @isa, @isag]
2095 => $cond_pack_name;
2096 if ($Info->{NormalCondition}) {
2097 push @isaa, perl_package_name name => $if_name,
2098 condition => $Info->{NormalCondition},
2099 is_internal => 1;
2100 $result .= perl_inherit [@isaa]
2101 => $cond_int_pack_name;
2102 } else { ## Condition not used
2103 $result .= perl_inherit [$iif_pack_name] => $cond_int_pack_name;
2104 }
2105 $result .= perl_inherit [$cond_int_pack_name, @isa]
2106 => $cond_iint_pack_name;
2107 $result .= perl_inherit [$if_pack_name] => $iif_pack_name;
2108 }
2109 for my $pack ($cond_pack_name, $cond_int_pack_name,
2110 $cond_iif_pack_name, $cond_if_pack_name,
2111 $cond_iint_pack_name) {
2112 $result .= perl_statement perl_assign
2113 perl_var (type => '$',
2114 package => {full_name => $pack},
2115 local_name => 'VERSION')
2116 => version_date time;
2117 }
2118
2119 my @feature;
2120 for (@{$node->child_nodes}) {
2121 my $gt = 0;
2122 unless (condition_match $_, level_default => \@level,
2123 condition => $condition) {
2124 if (condition_match $_, level_default => \@level,
2125 condition => $condition, ge => 1) {
2126 $gt = 1;
2127 } else {
2128 next;
2129 }
2130 }
2131
2132 if ($_->local_name eq 'Method' or
2133 $_->local_name eq 'IntMethod' or
2134 $_->local_name eq 'ReMethod') {
2135 $result .= method2perl ($_, level => \@level, condition => $condition)
2136 unless $gt;
2137 } elsif ($_->local_name eq 'Attr' or
2138 $_->local_name eq 'IntAttr' or
2139 $_->local_name eq 'ReAttr') {
2140 $result .= attr2perl ($_, level => \@level, condition => $condition)
2141 unless $gt;
2142 } elsif ($_->local_name eq 'ConstGroup') {
2143 $result .= constgroup2perl ($_, level => \@level,
2144 condition => $condition,
2145 without_document => $gt,
2146 package => $cond_int_pack_name);
2147 } elsif ($_->local_name eq 'Const') {
2148 $result .= const2perl ($_, level => \@level, condition => $condition,
2149 package => $cond_int_pack_name)
2150 unless $gt;
2151 } elsif ($_->local_name eq 'Require') {
2152 $result .= req2perl ($_, level => \@level, condition => $condition);
2153 } elsif ($_->local_name eq 'Feature') {
2154 push @feature, $_;
2155 } elsif ({qw/Name 1 Spec 1 ISA 1 Description 1 Implement 1
2156 Level 1 SpecLevel 1 ImplNote 1 Role 1
2157 IsAbstract 1 IsFinal 1 ImplByApp 1/}->{$_->local_name}) {
2158 #
2159 } else {
2160 valid_warn qq{Element @{[$_->local_name]} not supported};
2161 }
2162 }
2163
2164 if ($has_role) {
2165 my $role = type_expanded_uri $has_role->value;
2166 if ($role eq ExpandedURI q<DOMCore:DOMImplementationSource>) {
2167 $result .= perl_statement
2168 q<push @org::w3c::dom::DOMImplementationSourceList, >.
2169 perl_literal $cond_pack_name;
2170 } else {
2171 my $var = q<@{>.perl_var (type => '$',
2172 local_name => $ManakaiDOMModulePrefix.'::Role').
2173 q<{>.perl_literal ($role).q<}}>;
2174 my %prop;
2175 if ($has_role->get_attribute ('compat')) {
2176 $prop{compat} = type_expanded_uri
2177 $has_role->get_attribute_value ('compat');
2178 } else {
2179 $prop{compat} = '';
2180 }
2181 $result .= perl_statement
2182 'push '.$var.q<, >.
2183 perl_list {
2184 class => $cond_pack_name,
2185 constructor => 'new',
2186 %prop,
2187 };
2188 }
2189 }
2190
2191 if (@feature or $has_role) {
2192 $result .= '{' . perl_statement 'our $Feature';
2193 for (@feature) {
2194 my $name = $_->get_attribute ('QName');
2195 if ($name) {
2196 $name = type_expanded_uri ($name->value);
2197 } else {
2198 $name = $_->get_attribute_value ('Name');
2199 }
2200 $result .= perl_statement '$Feature->{'.perl_literal ($name).'}->{'.
2201 perl_literal ($_->get_attribute_value ('Version')).
2202 '} = 1';
2203 }
2204
2205 $result .= perl_sub
2206 name => '___classHasFeature',
2207 prototype => '$%',
2208 code =>
2209 perl_statement ('my ($self, %f) = @_').
2210 q[
2211 for (keys %f) {
2212 if ($Feature->{$_}) {
2213 if (defined $f{$_}->{version}) {
2214 delete $f{$_}
2215 if $Feature->{$_}->{$f{$_}->{version}};
2216 } else {
2217 delete $f{$_} if keys %{$Feature->{$_}};
2218 }
2219 return 1 if keys (%f) == 0;
2220 }
2221 }
2222 ].
2223 (@isa + @isaa ?
2224 q[for (].perl_list (@isa, @isaa).q[) {
2225 if (my $c = $_->can ('___classHasFeature')) {
2226 if ($c->($self, %f)) {
2227 return 1;
2228 }
2229 }
2230 }] : '').
2231 (($has_role and $has_role->get_attribute ('compat'))?
2232 q[
2233 my %g;
2234 for (keys %f) {
2235 unless ($f{$_}->{plus}) {
2236 return 0;
2237 } else {
2238 $g{$_} = {version => $f{$_}->{version}};
2239 }
2240 }
2241 for (reverse @{$].$ManakaiDOMModulePrefix.'::Role{'.
2242 perl_literal (type_expanded_uri
2243 $has_role->value).'}'.q[||[]}) {
2244 if ($_->{compat} eq ].
2245 perl_literal ($has_role->get_attribute_value
2246 ('compat')).q[) {
2247 if ($_->{class}->___classHasFeature (%g)) {
2248 return 1;
2249 }
2250 }
2251 }
2252 ]:'').
2253 perl_statement (q<return 0>);
2254 $result .= '}';
2255 }
2256
2257 $result .= ops2perl;
2258 }
2259
2260 $result;
2261 } # if2perl
2262
2263 =head2 Method, IntMethod and ReMethod elements
2264
2265 C<Method>, C<IntMethod> and C<ReMethod> element defines a method.
2266 Methods defined by C<Method> are ones as defined in the DOM
2267 specification. Methods defined by C<IntMethod> are only for
2268 internal use and usually not defined by the specifications.
2269 Methods defined by C<ReMethod> do actually not belong
2270 to this interface but to ancestor interface in the specification
2271 but overriddenly re-defined for this type of descendant interfaces
2272 (for example, some methods defined in Node interface of the DOM
2273 Core Module are re-defined in Element, Attr or other node-type
2274 interfaces, since those methods work differently by type of
2275 the node).
2276
2277 Children elements:
2278
2279 =over 4
2280
2281 =item Name = name (1 - 1)
2282
2283 Method name. It should be taken from DOM specification
2284 if element type is C<Method> or C<ReMethod>. Method name
2285 for C<ReMethod> must be used as the name of the C<Method>
2286 defined in ancestor interface. Method name for C<IntMethod>
2287 must be different with any other C<Method>, C<IntMethod>
2288 or C<ReMethod> (including those defined by ancestor interfaces).
2289
2290 =item Description = text (0 - infinite)
2291
2292 Description for the method.
2293
2294 =back
2295
2296 =cut
2297
2298 sub method2perl ($;%) {
2299 my ($node, %opt) = @_;
2300 local $Status->{depth} = $Status->{depth} + 1;
2301 my $m_name = perl_name $node->get_attribute_value ('Name');
2302 my $level;
2303 my @level = @{$opt{level} || []};
2304 local $Status->{Method} = $m_name;
2305 local $Status->{is_implemented} = 1;
2306 my $result = '';
2307 if ($node->local_name eq 'IntMethod') {
2308 $m_name = perl_internal_name $m_name;
2309 $level = '';
2310 } else {
2311 $level = get_level_description $node, level => \@level;
2312 }
2313
2314 my @param_list;
2315 my $param_prototype = '$';
2316 my @param_desc;
2317 my @param_domstring;
2318 if ($node->get_attribute ('Param')) {
2319 for (@{$node->child_nodes}) {
2320 if ($_->local_name eq 'Param') {
2321 my $name = perl_name $_->get_attribute_value ('Name');
2322 my $type = type_expanded_uri $_->get_attribute_value
2323 ('Type',
2324 default => 'DOMMain:any');
2325 push @param_list, '$' . $name;
2326 push @param_desc, pod_item (pod_code '$' . $name);
2327 if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2328 push @param_domstring, [$name, $type];
2329 }
2330 push my @param_desc_val,
2331 pod_item (type_label $type, is_pod => 1),
2332 pod_para get_description $_;
2333 $param_prototype .= '$';
2334 for (@{$_->child_nodes}) {
2335 next unless $_->local_name eq 'InCase';
2336 push @param_desc_val, pod_item (get_incase_label $_, is_pod => 1),
2337 pod_para (get_description $_);
2338 }
2339 push @param_desc, pod_list 4, @param_desc_val;
2340 }
2341 }
2342 }
2343
2344 my $return = $node->get_attribute ('Return');
2345 unless ($return) {
2346 ## NOTE: A method without return value does not have 'Return'
2347 ## before its code is implemented.
2348 valid_warn q<Required "Return" element not found>, node => $node;
2349 $return = $node->get_attribute ('Return', make_new_node => 1);
2350 }
2351 my $has_return = $return->get_attribute_value ('Type', default => 0) ? 1 : 0;
2352 push my @desc,
2353 pod_head ($Status->{depth}, 'Method ' .
2354 pod_code (($has_return ? '$return = ' : '') .
2355 '$obj->' . $m_name .
2356 ' (' . join (', ', @param_list) . ')')),
2357 pod_paras (get_description ($node)),
2358 $level ? pod_para ('The method ' . pod_code ($m_name) .
2359 q< has been > . $level . '.') : ();
2360
2361 if (@param_list) {
2362 push @desc, pod_para ('This method requires ' .
2363 english_number (@param_list + 0,
2364 singular => q<parameter>,
2365 plural => q<parameters>) . ':'),
2366 pod_list (4, @param_desc);
2367 } else {
2368 push @desc, pod_para (q<This method has no parameter.>);
2369 }
2370
2371 my $is_abs = $node->get_attribute_value ('IsAbstract', default => 0);
2372 if ($is_abs) {
2373 unless (get_perl_definition_node $return,
2374 condition => $opt{condition},
2375 level_default => $opt{level_default},
2376 use_dis => 1) {
2377 for ($return->append_new_node (type => '#element',
2378 local_name => 'Def')) {
2379 $_->set_attribute ('Type' => ExpandedURI q<lang:dis>);
2380 $_->set_attribute ('Overridden' => 1);
2381 }
2382 }
2383 }
2384
2385 my @return;
2386 my @exception;
2387 my $has_exception = 0;
2388 my $code_node = get_perl_definition_node $return,
2389 condition => $opt{condition},
2390 level_default => $opt{level_default},
2391 use_dis => 1;
2392 my $int_code_node = get_perl_definition_node $return, name => 'IntDef',
2393 condition => $opt{condition},
2394 level_default => $opt{level_default},
2395 use_dis => 1;
2396 my $code;
2397 my $int_code;
2398 for ({code => \$code, code_node => $code_node,
2399 internal => sub {
2400 return get_internal_code $node, $_[0] if $_[0];
2401 if ($int_code_node) {
2402 perl_code $int_code_node->value,
2403 internal => sub {
2404 $_[0] ? get_internal_code $node, $_[0] :
2405 valid_err q<Preprocessing macro INT cannot be used here>;
2406 };
2407 } else {
2408 valid_err "<IF[Name = $Status->{IF}]/Method[Name = $m_name]/" .
2409 "Return/IntDef> required";
2410 }
2411 }},
2412 {code => \$int_code, code_node => $int_code_node,
2413 internal => sub {$_[0]?get_internal_code $node,$_[0]:
2414 valid_err q<Preprocessing macro INT cannot be> .
2415 q<used here>}}) {
2416 if ($_->{code_node}) {
2417 my $mcode;
2418 if (type_expanded_uri ($_->{code_node}->get_attribute_value
2419 ('Type', default => q<DOMMain:any>))
2420 eq ExpandedURI q<lang:dis>) {
2421 $mcode = dis2perl $_->{code_node};
2422 } else {
2423 $mcode = perl_code $_->{code_node}->value,
2424 internal => $_->{internal};
2425 }
2426 if ($mcode =~ /^\s*$/) {
2427 ${$_->{code}} = '';
2428 } else {
2429 ${$_->{code}} = perl_code_source ($mcode,
2430 path => $_->{code_node}->node_path
2431 (key => 'Name'));
2432 }
2433 }
2434 }
2435 if ($code_node) {
2436 if ($has_return) {
2437 $code = perl_statement (perl_assign 'my $r' => get_value_literal $return,
2438 name => 'DefaultValue',
2439 type_name => 'Type') .
2440 $code;
2441 if ($code_node->get_attribute_value ('cast-output', default => 1)) {
2442 my $type = type_normalize
2443 type_expanded_uri $return->get_attribute_value
2444 ('Type',
2445 default => q<DOMMain:any>);
2446 if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2447 $code .= perl_builtin_code $type,
2448 s => 'r', r => 'r',
2449 condition => $opt{condition};
2450 }
2451 }
2452 $code .= perl_statement ('$r');
2453 } else {
2454 $code .= perl_statement ('undef');
2455 }
2456 if ($code_node->get_attribute_value ('auto-argument', default => 1)) {
2457 if ($code_node->get_attribute_value ('cast-input', default => 1)) {
2458 for (@param_domstring) {
2459 $code = perl_builtin_code ($_->[1],
2460 s => $_->[0], r => $_->[0],
2461 condition => $opt{condition}) . $code;
2462 }
2463 }
2464 $code = perl_statement (perl_assign 'my (' .
2465 join (', ', '$self', @param_list) .
2466 ')' => '@_') .
2467 $code;
2468 }
2469 if ($int_code_node) {
2470 if ($has_return) {
2471 $int_code = perl_statement (perl_assign 'my $r' => perl_literal '') .
2472 $int_code .
2473 perl_statement ('$r');
2474 } else {
2475 $int_code .= perl_statement ('undef');
2476 }
2477 $int_code = perl_statement (perl_assign 'my (' .
2478 join (', ', '$self', @param_list) .
2479 ')' => '@_') .
2480 $int_code
2481 if $int_code_node->get_attribute_value ('auto-argument', default => 1);
2482 }
2483
2484 if ($has_return) {
2485 push @return, pod_item (type_label (type_expanded_uri
2486 ($return->get_attribute_value
2487 ('Type',
2488 default => 'DOMMain:any')),
2489 is_pod => 1)),
2490 pod_para (get_description $return);
2491 }
2492 for (@{$return->child_nodes}) {
2493 if ($_->local_name eq 'InCase') {
2494 push @return, pod_item ( get_incase_label $_, is_pod => 1),
2495 pod_para (get_description $_);
2496 $has_return++;
2497 } elsif ($_->local_name eq 'Exception') {
2498 push @exception, pod_item ('Exception: ' .
2499 (type_label ($_->get_attribute_value
2500 ('Type',
2501 default => 'DOMMain:any'),
2502 is_pod => 1)).
2503 '.' . pod_code $_->get_attribute_value
2504 ('Name',
2505 default => '<unknown>')),
2506 pod_para (get_description $_);
2507 my @st;
2508 for (@{$_->child_nodes}) {
2509 next unless $_->node_type eq '#element';
2510 if ($_->local_name eq 'SubType') {
2511 push @st, subtype2poditem ($_);
2512 } elsif ({qw/Name 1 Type 1
2513 Description 1 ImplNote 1
2514 Condition 1 Level 1 SpecLevel 1/}->{$_->local_name}) {
2515 #
2516 } else {
2517 valid_err qq{Element type "@{[$_->local_name]}" not supported},
2518 node => $_;
2519 }
2520 }
2521 push @exception, pod_list 4, @st if @st;
2522 $has_exception++;
2523 }
2524 }
2525 } else {
2526 $Status->{is_implemented} = 0;
2527 $int_code = $code
2528 = perl_statement ('my $self = shift').
2529 perl_statement perl_exception
2530 level => 'EXCEPTION',
2531 class => 'DOMException',
2532 type => 'NOT_SUPPORTED_ERR',
2533 subtype_uri
2534 => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_METHOD_NOT_IMPLEMENTED>,
2535 param => {
2536 ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
2537 ExpandedURI q<MDOM_EXCEPTION:method> => $Status->{Method},
2538 };
2539 @return = ();
2540 push @exception, pod_item ('Exception: ' . pod_code ('DOMException') . '.' .
2541 pod_code ('NOT_SUPPORTED_ERR')),
2542 pod_para ('Call of this method allways result in
2543 this exception raisen, since this
2544 method is not implemented yet.');
2545 $has_return = 0;
2546 $has_exception = 1;
2547 }
2548 is_implemented if => $Status->{IF}, method => $Status->{Method},
2549 condition => $opt{condition}, set => $Status->{is_implemented};
2550 if ($has_return or $has_exception) {
2551 if ($has_return) {
2552 push @desc, pod_para (q<This method results in > .
2553 ($has_return == 1 ? q<the value:>
2554 : q<either:>)),
2555 pod_list 4, pod_item (pod_code q<$return>),
2556 pod_list (4, @return),
2557 @exception;
2558 } elsif ($has_exception) {
2559 push @desc, pod_para (q<This method does not return any value,
2560 but it might raise > .
2561 ($has_exception == 1 ? q<an exception:>
2562 : q<one of exceptions from:>)),
2563 pod_list 4, @exception;
2564 }
2565 } else {
2566 push @desc, pod_para q<This method does not return any value
2567 nor does raise any exceptions.>;
2568 }
2569
2570 push @desc, get_alternate_description $node;
2571 push @desc, get_redef_description $node;
2572
2573 if ($node->local_name eq 'IntMethod' or
2574 $Status->{if}->{method_documented}->{$m_name}++) {
2575 $result .= pod_block pod_comment @desc;
2576 } else {
2577 $result .= pod_block @desc;
2578 }
2579
2580 $result .= perl_sub name => $m_name,
2581 prototype => $param_prototype,
2582 code => $code;
2583 $result .= perl_sub name => perl_internal_name $m_name,
2584 prototype => $param_prototype,
2585 code => $int_code
2586 if $int_code_node;
2587
2588 if (my $op = get_perl_definition_node $node, name => 'Operator') {
2589 my $value = $op->value;
2590 valid_err qq{Overloaded operator name not specified},
2591 node => $op
2592 unless defined $value;
2593 $Status->{Operator}->{$value} = '\\' . perl_var type => '&',
2594 local_name => $m_name;
2595 }
2596
2597 $result;
2598 } # method2perl
2599
2600 sub attr2perl ($;%) {
2601 my ($node, %opt) = @_;
2602 local $Status->{depth} = $Status->{depth} + 1;
2603 my $m_name = perl_name $node->get_attribute_value ('Name');
2604 my $level;
2605 my @level = @{$opt{level} || []};
2606 local $Status->{Method} = $m_name;
2607 local $Status->{is_implemented} = 1;
2608 my $result = '';
2609 if ($node->local_name eq 'IntAttr') {
2610 $m_name = perl_internal_name $m_name;
2611 $level = '';
2612 } else {
2613 $level = get_level_description $node, level => \@level;
2614 }
2615
2616 my $return = $node->get_attribute ('Get');
2617 unless ($return) {
2618 valid_err q<Required "Get" element not found>, node => $node;
2619 }
2620 my $set = $node->get_attribute ('Set');
2621 my $has_set = defined $set ? 1 : 0;
2622 push my @desc,
2623 pod_head ($Status->{depth}, 'Attribute ' .
2624 pod_code ('$obj->' . $m_name)),
2625 pod_paras (get_description ($node)),
2626 $level ? pod_para ('The method ' . pod_code ($m_name) .
2627 q< has been > . $level . '.') : ();
2628
2629 my $is_abs = $node->get_attribute_value ('IsAbstract', default => 0);
2630 if ($is_abs) {
2631 unless (get_perl_definition_node $return,
2632 condition => $opt{condition},
2633 level_default => $opt{level_default},
2634 use_dis => 1) {
2635 for ($return->append_new_node (type => '#element',
2636 local_name => 'Def')) {
2637 $_->set_attribute ('Type' => ExpandedURI q<lang:dis>);
2638 $_->set_attribute ('Overridden' => 1);
2639 }
2640 }
2641 }
2642
2643 my $code_node = get_perl_definition_node $return,
2644 condition => $opt{condition},
2645 level_default => $opt{level_default},
2646 use_dis => 1;
2647 my $int_code_node = get_perl_definition_node $return, name => 'IntDef',
2648 condition => $opt{condition},
2649 level_default => $opt{level_default},
2650 use_dis => 1;
2651 my ($set_code_node, $int_set_code_node);
2652 if ($has_set) {
2653 if ($is_abs) {
2654 unless (get_perl_definition_node $set,
2655 condition => $opt{condition},
2656 level_default => $opt{level_default},
2657 use_dis => 1) {
2658 for ($return->append_new_node (type => '#element',
2659 local_name => 'Def')) {
2660 $_->set_attribute ('Type' => ExpandedURI q<lang:dis>);
2661 $_->set_attribute ('Overridden' => 1);
2662 }
2663 }
2664 }
2665 $set_code_node = get_perl_definition_node $set,
2666 condition => $opt{condition},
2667 level_default => $opt{level_default},
2668 use_dis => 1;
2669 $int_set_code_node = get_perl_definition_node $set, name => 'IntDef',
2670 condition => $opt{condition},
2671 level_default => $opt{level_default},
2672 use_dis => 1;
2673 }
2674 my $code = '';
2675 my $int_code = '';
2676 my $set_code = '';
2677 my $int_set_code = '';
2678 for ({code => \$code, code_node => $code_node,
2679 internal => sub {
2680 return get_internal_code $node, $_[0] if $_[0];
2681 if ($int_code_node) {
2682 perl_code $int_code_node->value,
2683 internal => sub {
2684 $_[0] ? get_internal_code $node, $_[0] :
2685 valid_err q<Preprocessing macro INT cannot be used here>;
2686 };
2687 } else {
2688 valid_err "<IF[Name = $Status->{IF}]/Attr[Name = $m_name]/" .
2689 "Get/IntDef> required";
2690 }
2691 }},
2692 {code => \$int_code, code_node => $int_code_node,
2693 internal => sub {$_[0]?get_internal_code $node,$_[0]:
2694 valid_err q<Preprocessing macro INT cannot be> .
2695 q<used here>}},
2696 {code => \$set_code, code_node => $set_code_node,
2697 internal => sub {
2698 return get_internal_code $node, $_[0] if $_[0];
2699 if ($int_set_code_node) {
2700 perl_code $int_set_code_node->value,
2701 internal => sub {
2702 $_[0] ? get_internal_code $node, $_[0] :
2703 valid_err q<Preprocessing macro INT cannot be used here>;
2704 };
2705 } else {
2706 valid_err "<IF[Name = $Status->{IF}]/Attr[Name = $m_name]/" .
2707 "Set/IntDef> required";
2708 }
2709 }},
2710 {code => \$int_set_code, code_node => $int_set_code_node,
2711 internal => sub {$_[0]?get_internal_code $node,$_[0]:
2712 valid_err q<Preprocessing macro INT cannot be> .
2713 q<used here>}}) {
2714 if ($_->{code_node}) {
2715 my $mcode;
2716 if (type_expanded_uri ($_->{code_node}->get_attribute_value
2717 ('Type', default => q<DOMMain:any>))
2718 eq ExpandedURI q<lang:dis>) {
2719 $mcode = dis2perl $_->{code_node};
2720 } else {
2721 $mcode = perl_code $_->{code_node}->value,
2722 internal => $_->{internal},
2723 node => $_->{code_node};
2724 }
2725 if ($mcode =~ /^\s*$/) {
2726 ${$_->{code}} = '';
2727 } else {
2728 ${$_->{code}} = perl_code_source ($mcode,
2729 path => $_->{code_node}->node_path
2730 (key => 'Name'));
2731 }
2732 }
2733 }
2734
2735 my @return;
2736 my @return_xcept;
2737 if ($code_node) {
2738 is_implemented if => $Status->{IF}, attr => $Status->{Method},
2739 condition => $opt{condition}, set => 1, on => 'get';
2740 my $co = $code_node->get_attribute_value ('cast-output',
2741 default => $code eq '' ? 0 : 1);
2742 if ($code eq '' and not $co) {
2743 $code = perl_statement get_value_literal $return,
2744 name => 'DefaultValue',
2745 type_name => 'Type';
2746 } else {
2747 $code = perl_statement (perl_assign 'my $r' => get_value_literal $return,
2748 name => 'DefaultValue',
2749 type_name => 'Type') .
2750 $code;
2751 if ($co) {
2752 my $type = type_normalize
2753 type_expanded_uri $return->get_attribute_value
2754 ('Type',
2755 default => q<DOMMain:any>);
2756 if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2757 $code .= perl_builtin_code $type,
2758 s => 'r', r => 'r',
2759 condition => $opt{condition};
2760 }
2761 }
2762 $code .= perl_statement ('$r');
2763 }
2764 $code = get_warning_perl_code ($return) . $code;
2765 if ($int_code_node) {
2766 $int_code = perl_statement (perl_assign 'my $r' => perl_literal '') .
2767 $int_code .
2768 perl_statement ('$r');
2769 $int_code = perl_statement (perl_assign 'my ($self)' => '@_') . $int_code
2770 if $int_code_node->get_attribute_value ('auto-argument', default => 1);
2771 }
2772
2773 push @return, pod_item (type_label (type_expanded_uri
2774 $return->get_attribute_value
2775 ('Type',
2776 default => 'DOMMain:any'),
2777 is_pod => 1)),
2778 pod_para (get_description $return);
2779 for (@{$return->child_nodes}) {
2780 if ($_->local_name eq 'InCase') {
2781 push @return, pod_item (get_incase_label $_, is_pod => 1),
2782 pod_para (get_description $_);
2783 } elsif ($_->local_name eq 'Exception') {
2784 push @return_xcept, pod_item ('Exception: ' .
2785 (type_label ($_->get_attribute_value
2786 ('Type',
2787 default => 'DOMMain:any'),
2788 is_pod => 1)) .
2789 '.' . pod_code $_->get_attribute_value
2790 ('Name',
2791 default => '<unknown>')),
2792 pod_para (get_description $_);
2793 my @st;
2794 for (@{$_->child_nodes}) {
2795 next unless $_->node_type eq '#element';
2796 if ($_->local_name eq 'SubType') {
2797 push @st, subtype2poditem ($_);
2798 } elsif ({qw/Name 1 Type 1
2799 Description 1 ImplNote 1
2800 Condition 1 Level 1 SpecLevel 1/}->{$_->local_name}) {
2801 #
2802 } else {
2803 valid_err qq{Element type "@{[$_->local_name]}" not supported},
2804 node => $_;
2805 }
2806 }
2807 push @return_xcept, pod_list 4, @st if @st;
2808 }
2809 }
2810 } else {
2811 is_implemented if => $Status->{IF}, attr => $Status->{Method},
2812 condition => $opt{condition}, set => 0, on => 'get';
2813 $Status->{is_implemented} = 0;
2814 $int_code = $code
2815 = perl_statement perl_exception
2816 level => 'EXCEPTION',
2817 class => 'DOMException',
2818 type => 'NOT_SUPPORTED_ERR',
2819 subtype_uri
2820 => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_ATTR_NOT_IMPLEMENTED>,
2821 param => {
2822 ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
2823 ExpandedURI q<MDOM_EXCEPTION:attr> => $Status->{Method},
2824 ExpandedURI q<MDOM_EXCEPTION:on> => 'get',
2825 };
2826 @return = ();
2827 push @return_xcept,
2828 pod_item ('Exception: ' . pod_code ('DOMException') . '.' .
2829 pod_code ('NOT_SUPPORTED_ERR')),
2830 pod_para ('Getting of this attribute allways result in
2831 this exception raisen, since this
2832 attribute is not implemented yet.');
2833 }
2834 push @desc, pod_para ('DOM applications can get the value by:'),
2835 pod_pre (qq{\$return = \$obj->$m_name}),
2836 pod_list (4,
2837 @return ? (pod_item pod_code q<$return>,
2838 pod_list 4, @return): (),
2839 @return_xcept);
2840
2841 my @set_desc;
2842 my @set_xcept;
2843 if ($set_code_node) {
2844 is_implemented if => $Status->{IF}, attr => $Status->{Method},
2845 condition => $opt{condition}, set => 1, on => 'set';
2846 if ($set_code_node->get_attribute_value ('cast-input',
2847 default => $set_code eq '' ? 0 : 1)) {
2848 my $type = type_normalize
2849 type_expanded_uri $set->get_attribute_value
2850 ('Type',
2851 default => q<DOMMain:any>);
2852 if (type_isa $type, ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>) {
2853 $set_code = perl_builtin_code ($type,
2854 s => 'given', r => 'given',
2855 condition => $opt{condition})
2856 . $set_code;
2857 }
2858 }
2859 $set_code = get_warning_perl_code ($set) . $set_code;
2860
2861 push @set_desc, pod_item (type_label (type_expanded_uri
2862 ($set->get_attribute_value
2863 ('Type',
2864 default => 'DOMMain:any')),
2865 is_pod => 1)),
2866 pod_para (get_description $set);
2867 for (@{$set->child_nodes}) {
2868 if ($_->local_name eq 'InCase') {
2869 push @set_desc, pod_item (get_incase_label $_, is_pod => 1),
2870 pod_para (get_description $_);
2871 } elsif ($_->local_name eq 'Exception') {
2872 push @set_xcept, pod_item ('Exception: ' .
2873 (type_label ($_->get_attribute_value
2874 ('Type',
2875 default => 'DOMMain:any'),
2876 is_pod => 1)) .
2877 '.' . pod_code $_->get_attribute_value
2878 ('Name',
2879 default => '<unknown>')),
2880 pod_para (get_description $_);
2881 my @st;
2882 for (@{$_->child_nodes}) {
2883 next unless $_->node_type eq '#element';
2884 if ($_->local_name eq 'SubType') {
2885 push @st, subtype2poditem ($_);
2886 } elsif ({qw/Name 1 Type 1
2887 Description 1 ImplNote 1
2888 Condition 1 Level 1 SpecLevel 1/}->{$_->local_name}) {
2889 #
2890 } else {
2891 valid_err qq{Element type "@{[$_->local_name]}" not supported},
2892 node => $_;
2893 }
2894 }
2895 push @set_xcept, pod_list 4, @st if @st;
2896 }
2897 }
2898 } elsif ($has_set) {
2899 is_implemented if => $Status->{IF}, attr => $Status->{Method},
2900 condition => $opt{condition}, set => 0, on => 'set';
2901 $Status->{is_implemented} = 0;
2902 $int_set_code = $set_code
2903 = perl_statement perl_exception
2904 level => 'EXCEPTION',
2905 class => 'DOMException',
2906 type => 'NOT_SUPPORTED_ERR',
2907 subtype_uri
2908 => ExpandedURI q<MDOM_EXCEPTION:MDOM_IMPL_ATTR_NOT_IMPLEMENTED>,
2909 param => {
2910 ExpandedURI q<MDOM_EXCEPTION:if> => $Status->{IF},
2911 ExpandedURI q<MDOM_EXCEPTION:attr> => $Status->{Method},
2912 ExpandedURI q<MDOM_EXCEPTION:on> => 'set',
2913 };
2914 @set_desc = pod_item '(Not implemented yet)';
2915 @set_xcept = ();
2916 push @set_xcept, pod_item ('Exception: ' . pod_code ('DOMException') . '.' .
2917 pod_code ('NOT_SUPPORTED_ERR')),
2918 pod_para ('Setting of this attribute allways result in
2919 this exception raisen, since this
2920 attribute is not implemented yet.');
2921 }
2922
2923 if ($has_set) {
2924 push @desc, pod_para ('DOM applications can set the value by:'),
2925 pod_pre (qq{\$obj->$m_name (\$newValue)}),
2926 pod_list 4,
2927 pod_item (pod_code q<$newValue>),
2928 pod_list 4, @set_desc;
2929 push @desc, (@set_xcept ?
2930 (pod_para (q<Setting this attribute may raise exception:>),
2931 pod_list (4, @set_xcept)) :
2932 (pod_para (q<Setting this attribute does not raise >.
2933 q<exception in general.>)));
2934 } else {
2935 push @desc, pod_para ('This attribute is read-only.');
2936 }
2937 is_implemented if => $Status->{IF}, method => $Status->{Method},
2938 condition => $opt{condition}, set => $Status->{is_implemented};
2939
2940 push @desc, get_alternate_description $node;
2941 push @desc, get_redef_description $node, method => 'attribute';
2942
2943 if ($node->local_name eq 'IntAttr' or
2944 $Status->{if}->{method_documented}->{$m_name}++) {
2945 $result .= pod_block pod_comment @desc;
2946 } else {
2947 $result .= pod_block @desc;
2948 }
2949
2950 my $warn = get_warning_perl_code ($node);
2951 my $proto;
2952 if ($has_set) {
2953 $code = perl_statement (perl_assign
2954 perl_var (scope => 'my', type => '$', local_name => 'self')
2955 => 'shift').
2956 $warn.
2957 perl_if
2958 q<exists $_[0]>,
2959 ($set_code =~/\bgiven\b/ ?
2960 perl_statement (q<my $given = shift>) : '') . $set_code .
2961 perl_statement ('undef'),
2962 $code;
2963 $int_code = perl_statement (perl_assign
2964 perl_var (scope => 'my', type => '$', local_name => 'self')
2965 => 'shift').
2966 perl_if
2967 q<exists $_[0]>,
2968 perl_statement (q<my $given = shift>) . $int_set_code,
2969 $int_code;
2970 $proto = '$;$';
2971 } else {
2972 $code = q<my $self = shift; > . $warn . $code;
2973 $int_code = q<my $self = shift; > . $int_code;
2974 $proto = '$';
2975 }
2976 $result .= perl_sub name => $m_name,
2977 prototype => $proto,
2978 code => $code;
2979 $result .= perl_sub name => perl_internal_name $m_name,
2980 prototype => $proto,
2981 code => $int_code
2982 if $int_code_node;
2983
2984 if (my $op = get_perl_definition_node $node, name => 'Operator') {
2985 $Status->{Operator}->{$op->value} = '\\' . perl_var type => '&',
2986 local_name => $m_name;
2987 }
2988
2989 $result;
2990 } # attr2perl
2991
2992 =head2 DataType element
2993
2994 The C<DataType> element defines a datatype.
2995
2996 =cut
2997
2998 sub datatype2perl ($;%) {
2999 my ($node, %opt) = @_;
3000 local $Status->{depth} = $Status->{depth} + 1;
3001 my $pack_name = perl_package_name
3002 name => my $if_name
3003 = perl_name $node->get_attribute_value ('Name'),
3004 ucfirst => 1;
3005 local $Status->{IF} = $if_name;
3006 local $Status->{if} = {}; ## Temporary data
3007 local $Info->{Namespace} = {%{$Info->{Namespace}}};
3008 local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
3009 local $Info->{Require_perl_package_use} = {};
3010 local $Status->{Operator} = {};
3011 my $result = perl_package full_name => $pack_name;
3012 my @isa;
3013 for (@{$node->child_nodes}) {
3014 next unless $_->node_type eq '#element' and
3015 $_->local_name eq 'ISA' and
3016 condition_match $_, condition => $opt{condition},
3017 default_any => 1, ge => 1;
3018 push @isa, perl_package_name qname_with_condition => $_->value,
3019 condition => $opt{condition};
3020 }
3021 $result .= perl_inherit [@isa, perl_package_name (name => 'ManakaiDOMObject'),
3022 perl_package_name (if => $if_name)];
3023 for my $pack ({full_name => $pack_name}, {if => $if_name}) {
3024 $result .= perl_statement perl_assign
3025 perl_var (type => '$',
3026 package => $pack,
3027 local_name => 'VERSION')
3028 => version_date time;
3029 }
3030
3031 my @level = @{$opt{level} || []};
3032 my $mod = get_level_description $node, level => \@level;
3033 $result .= pod_block
3034 pod_head ($Status->{depth}, 'Type ' . pod_code $if_name),
3035 pod_paras (get_description ($node)),
3036 ($mod ? pod_para ('This type is ' . $mod) : ());
3037
3038 for (@{$node->child_nodes}) {
3039 if ($_->local_name eq 'Method' or
3040 $_->local_name eq 'IntMethod') {
3041 $result .= method2perl ($_, level => \@level,
3042 condition => $opt{condition});
3043 } elsif ($_->local_name eq 'Attr' or
3044 $_->local_name eq 'IntAttr') {
3045 $result .= attr2perl ($_, level => \@level, condition => $opt{condition});
3046 } elsif ($_->local_name eq 'ConstGroup') {
3047 $result .= constgroup2perl ($_, level => \@level,
3048 condition => $opt{condition},
3049 package => $pack_name);
3050 } elsif ($_->local_name eq 'Const') {
3051 $result .= const2perl ($_, level => \@level,
3052 condition => $opt{condition},
3053 package => $pack_name);
3054 } elsif ($_->local_name eq 'ISA') {
3055 push @{$Info->{DataTypeAlias}->{type_expanded_uri $if_name}
3056 ->{isa_uri}||=[]},
3057 type_expanded_uri $_->value;
3058 } elsif ({qw/Name 1 FullName 1 Spec 1 Description 1
3059 Level 1 SpecLevel 1 Def 1 ImplNote 1/}->{$_->local_name}) {
3060 #
3061 } else {
3062 valid_warn qq{Element @{[$_->local_name]} not supported};
3063 }
3064 }
3065
3066 $result .= ops2perl;
3067
3068 $result;
3069 } # datatype2perl
3070
3071 sub datatypealias2perl ($;%) {
3072 my ($node, %opt) = @_;
3073 local $Status->{depth} = $Status->{depth} + 1;
3074 my $if_name = $node->get_attribute_value ('Name');
3075 my $long_name = expanded_uri $if_name;
3076 my $real_long_name = type_expanded_uri
3077 (my $real_name = $node->get_attribute_value
3078 ('Type', default => 'DOMMain:any'));
3079 if (type_label ($real_long_name) eq type_label ($long_name)) {
3080 $Info->{DataTypeAlias}->{$long_name}->{canon_uri} = $real_long_name;
3081 return perl_comment sprintf '%s <%s> := %s <%s>',
3082 type_label ($long_name), $long_name,
3083 type_label ($real_long_name), $real_long_name;
3084 }
3085 $Info->{DataTypeAlias}->{$long_name}->{canon_uri} = $real_long_name;
3086
3087 $if_name = perl_name $if_name, ucfirst => 1;
3088 $real_name = type_package_name $real_name;
3089 my $pack_name = perl_package_name name => $if_name;
3090 local $Status->{IF} = $if_name;
3091 local $Status->{if} = {}; ## Temporary data
3092 local $Info->{Namespace} = {%{$Info->{Namespace}}};
3093 local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
3094 local $Info->{Require_perl_package_use} = {};
3095 my $result = perl_package full_name => $pack_name;
3096 $result .= perl_inherit [perl_package_name (full_name => $real_name),
3097 perl_package_name (if => $if_name)];
3098 for my $pack ({if => $if_name}) {
3099 $result .= perl_statement perl_assign
3100 perl_var (type => '$',
3101 package => $pack,
3102 local_name => 'VERSION')
3103 => version_date time;
3104 }
3105
3106 my @level = @{$opt{level} || []};
3107 my $mod = get_level_description $node, level => \@level;
3108 $result .= pod_block
3109 pod_head ($Status->{depth}, 'Type ' . pod_code $if_name),
3110 pod_paras (get_description ($node)),
3111 pod_para ('This type is an alias of the type ' .
3112 (type_label $real_long_name, is_pod => 1) . '.'),
3113 ($mod ? pod_para ('This type is ' . $mod) : ());
3114
3115 for (@{$node->child_nodes}) {
3116 if ({qw/Name 1 FullName 1 Spec 1 Type 1 Description 1
3117 Level 1 SpecLevel 1 Condition 1 ImplNote 1
3118 Def 1/}->{$_->local_name}) {
3119 #
3120 } else {
3121 valid_warn qq{Element @{[$_->local_name]} not supported};
3122 }
3123 }
3124
3125 $result;
3126 } # datatypealias2perl
3127
3128 =item Exception top-level element
3129
3130 =item Warning top-level element
3131
3132 =cut
3133
3134 sub exception2perl ($;%) {
3135 my ($node, %opt) = @_;
3136 local $Status->{depth} = $Status->{depth} + 1;
3137 local $Status->{const} = {};
3138 local $Status->{if} = {}; ## Temporary data
3139 local $Status->{in_exception} = 1;
3140 local $Info->{Namespace} = {%{$Info->{Namespace}}};
3141 local $Info->{Require_perl_package} = {%{$Info->{Require_perl_package}}};
3142 local $Info->{Require_perl_package_use} = {};
3143 my $pack_name = perl_package_name
3144 name => my $if_name
3145 = perl_name $node->get_attribute_value ('Name'),
3146 ucfirst => 1;
3147 my $type = $node->local_name eq 'Exception' ? 'Exception' : 'Warning';
3148 local $Status->{IF} = $if_name;
3149 my $result = perl_package full_name => $pack_name;
3150 $result .= perl_statement perl_assign 'our $VERSION', version_date time;
3151 my @isa = perl_package_name (if => $if_name);
3152 if ($if_name eq 'ManakaiDOM'.$type) {
3153 push @isa, perl_package_name name => 'ManakaiDOMExceptionOrWarning';
3154 } elsif ($if_name eq 'ManakaiDOMExceptionOrWarning') {
3155 push @isa, 'Message::Util::Error';
3156 } else {
3157 push @isa, perl_package_name name => 'ManakaiDOM'.$type
3158 }
3159 $result .= perl_inherit [@isa];
3160 $result .= perl_statement perl_assign
3161 perl_var (type => '$',
3162 package => {if => $if_name},
3163 local_name => 'VERSION')
3164 => version_date time;
3165 my @level = @{$opt{level} || []};
3166 my $mod = get_level_description $node, level => \@level;
3167 $result .= pod_block
3168 pod_head ($Status->{depth}, $type . ' ' . pod_code $if_name),
3169 pod_paras (get_description ($node)),
3170 ($mod ? pod_para ('This ' . lc ($type) . ' is introduced in ' .
3171 $mod . '.') : ()),
3172 ($type eq 'Exception' ?
3173 (pod_para ('To catch this class of exceptions:'),
3174 pod_pre (join "\n",
3175 q|try { |,
3176 q| ... |,
3177 q|} catch | . $pack_name . q| with { |,
3178 q| my $err = shift; |,
3179 q| if ($err->{type} eq 'ERROR_NAME') { |,
3180 q| ... # Recover from some error, |,
3181 q| } else { |,
3182 q| $err->throw; # rethrow if other |,
3183 q| } |,
3184 q|}; # Don't forget semicolon! |))
3185 : ());
3186
3187 for (@{$node->child_nodes}) {
3188 if ($_->local_name eq 'Method' or
3189 $_->local_name eq 'IntMethod' or
3190 $_->local_name eq 'ReMethod') {
3191 $result .= method2perl ($_, level => \@level,
3192 condition => $opt{condition},
3193 any_unless_condition => 1);
3194 } elsif ($_->local_name eq 'Attr' or
3195 $_->local_name eq 'IntAttr' or
3196 $_->local_name eq 'ReAttr') {
3197 my $get;
3198 if ($_->local_name eq 'Attr' and
3199 $_->get_attribute_value ('Name') eq 'code' and
3200 $get = $_->get_attribute ('Get') and
3201 not get_perl_definition_node $get, name => 'Def') {
3202 for ($get->append_new_node (type => '#element',
3203 local_name => 'Def',
3204 value => q{
3205 $r = $self->{<Q:ManakaiDOM:code>};
3206 })) {
3207 $_->set_attribute (type => 'lang:Perl'); ## ISSUE: NS prefix assoc.
3208 }
3209 }
3210 $result .= attr2perl ($_, level => \@level, condition => $opt{condition},
3211 any_unless_condition => 1);
3212 } elsif ($_->local_name eq 'ConstGroup') {
3213 $result .= constgroup2perl ($_, level => \@level,
3214 condition => $opt{condition},
3215 package => $pack_name,
3216 any_unless_condition => 1);
3217 } elsif ($_->local_name eq 'Const') {
3218 $result .= const2perl ($_, level => \@level,
3219 condition => $opt{condition},
3220 package => $pack_name,
3221 any_unless_condition => 1);
3222 } elsif ({qw/Name 1 Spec 1 Description 1
3223 Level 1 SpecLevel 1 Condition 1
3224 ImplNote 1/}->{$_->local_name}) {
3225 #
3226 } else {
3227 valid_warn qq{Element @{[$_->local_name]} not supported};
3228 }
3229 }
3230
3231 $result .= perl_sub
3232 name => '___error_def', prototype => '',
3233 code => perl_list {
3234 map {
3235 $_ => {
3236 ExpandedURI q<DOMCore:code> => perl_code_literal
3237 ($Status->{const}->{$_}->{code_literal}),
3238 description
3239 => $Status->{const}->{$_}->{description},
3240 ExpandedURI q<MDOM_EXCEPTION:subtype>
3241 => $Status->{const}->{$_}->{subtype},
3242 }
3243 } sort keys %{$Status->{const}}
3244 };
3245
3246 $result;
3247 } # exception2perl
3248
3249 sub constgroup2perl ($;%);
3250 sub constgroup2perl ($;%) {
3251 my ($node, %opt) = @_;
3252 local $Status->{depth} = $Status->{depth} + 1;
3253 my $name = $node->get_attribute ('Name');
3254 if (defined $name) {
3255 $name = perl_name $name->value, ucfirst => 1;
3256 }
3257 local $Status->{IF} = $name || q<[anonymous constant group]>;
3258 my @level = @{$opt{level} || []};
3259 my $mod = get_level_description $node, level => \@level;
3260 my $result = '';
3261 my $consts = {};
3262 $Info->{DataTypeAlias}->{expanded_uri $node->get_attribute_value ('Name')}
3263 ->{isa_uri} = [type_expanded_uri $node->get_attribute_value
3264 ('Type', default => q<DOMMain:any>)]
3265 if defined $name;
3266
3267 my $i = 0;
3268 {
3269 local $Status->{EXPORT_OK} = $consts;
3270 for (@{$node->child_nodes}) {
3271 my $only_document = $opt{only_document} || 0;
3272 unless ($_->node_type eq '#element' and
3273 condition_match $_, level_default => \@level,
3274 condition => $opt{condition},
3275 any_unless_condition
3276 => $opt{any_unless_condition}) {
3277 $only_document = 1;
3278 }
3279
3280 if ($_->local_name eq 'ConstGroup') {
3281 $result .= constgroup2perl ($_, level => \@level,
3282 condition => $opt{condition},
3283 without_document => $opt{without_document},
3284 only_document => $only_document,
3285 package => $opt{package},
3286 any_unless_condition
3287 => $opt{any_unless_condition});
3288 $i++;
3289 } elsif ($_->local_name eq 'Const') {
3290 $result .= const2perl ($_, level => \@level,
3291 condition => $opt{condition},
3292 without_document => $opt{without_document},
3293 only_document => $only_document,
3294 package => $opt{package},
3295 any_unless_condition
3296 => $opt{any_unless_condition});
3297 $i++;
3298 } elsif ({qw/Name 1 Spec 1 ISA 1 Description 1 Type 1 IsBitMask 1
3299 Level 1 SpecLevel 1 Def 1 ImplNote 1
3300 FullName 1/}->{$_->local_name}) {
3301 #
3302 } else {
3303 valid_warn qq{Element @{[$_->local_name]} not supported};
3304 }
3305 }
3306 }
3307
3308 for (keys %$consts) {
3309 $Status->{EXPORT_OK}->{$_} = 1;
3310 $Status->{EXPORT_TAGS}->{$name}->{$_} = 1 if defined $name;
3311 }
3312
3313 return $result if $opt{without_document};
3314
3315 my @desc;
3316 if (defined $name) {
3317 push @desc, pod_head $Status->{depth}, 'Constant Group ' . pod_code $name;
3318 } else {
3319 push @desc, pod_head $Status->{depth}, 'Constant Group: ' .
3320 get_description ($node,
3321 name => 'FullName');
3322 }
3323
3324 push @desc, pod_paras (get_description ($node)),
3325 ($mod ? pod_para ('This constant group has been ' . $mod . '.')
3326 : ()),
3327 pod_para ('This constant group has ' .
3328 english_number $i, singular => q<value.>,
3329 plural => q<values.>);
3330
3331 push @desc, pod_para ('To export all constant values in this group:'),
3332 pod_pre (perl_statement "use $Info->{Package} qw/:$name/")
3333 if defined $name;
3334
3335 $result = pod_block (@desc) . $result;
3336
3337 $result;
3338 } # constgroup2perl
3339
3340 sub const2perl ($;%) {
3341 my ($node, %opt) = @_;
3342 local $Status->{depth} = $Status->{depth} + 1;
3343 my $name = perl_name $node->get_attribute_value ('Name');
3344 my $longname = perl_var local_name => $name,
3345 package => {full_name => $opt{package} ||
3346 $Info->{Package}};
3347 local $Status->{IF} = $name;
3348 local $Status->{const_subtype} = {};
3349 my @level = @{$opt{level} || []};
3350 my $mod = get_level_description $node, level => \@level;
3351 my @desc;
3352 unless ($opt{without_document}) {
3353 @desc = (pod_head ($Status->{depth}, 'Constant Value ' . pod_code $name),
3354 pod_paras (get_description ($node)),
3355 ($mod ? pod_para ('This constant value has been ' . $mod . '.')
3356 : ()));
3357
3358 if ($Status->{in_exception}) { ## Is Exception/Warning code
3359 #
3360 } else { ## Is NOT Exception/Warning code
3361 push @desc, pod_para ('To export this constant value:'),
3362 pod_pre (perl_statement "use $Info->{Package} qw/$name/");
3363 }
3364
3365 my @param;
3366 for (@{$node->child_nodes}) {
3367 next unless $_->node_type eq '#element';
3368 if ($_->local_name eq 'Param') {
3369 if ($Status->{in_exception}) {
3370 push @param, param2poditem ($_);
3371 } else {
3372 valid_err qq{Element "Param" may not be used with non-Exception}.
3373 qq{/Warning constants},
3374 node => $node;
3375 }
3376 } elsif ($_->local_name eq 'SubType') {
3377 if ($Status->{in_exception}) {
3378 push @param, subtype2poditem ($_);
3379 } else {
3380 valid_err qq{Element "SubType" may not be used with non-Exception}.
3381 qq{/Warning constants},
3382 node => $node;
3383 }
3384 } elsif ({qw/Name 1 Spec 1 Description 1
3385 Condition 1 Level 1 SpecLevel 1
3386 Type 1 Value 1 ImplNote 1/}->{$_->local_name}) {
3387 #
3388 } else {
3389 valid_err qq{Element type "@{[$_->local_name]}" not supported},
3390 node => $node;
3391 }
3392 }
3393 push @desc, pod_list 4, @param if @param;
3394 }
3395
3396 my $result = '';
3397 unless ($opt{only_document}) {
3398 $result = perl_sub name => $longname, prototype => '',
3399 code => my $code = get_value_literal
3400 $node, name => 'Value';
3401 $result .= perl_sub name => perl_var (package => {full_name
3402 => $Info->{Package}},
3403 local_name => $name), prototype => '',
3404 code => $code
3405 if $opt{package} and $Info->{Package} ne $opt{package};
3406 my $desc_template = get_description $node,
3407 type => ExpandedURI q<lang:muf>,
3408 default => $name;
3409 $Status->{const}->{$name} = {
3410 description => $desc_template,
3411 code_literal => $code,
3412 subtype => $Status->{const_subtype} || {},
3413 };
3414 }
3415
3416 $Status->{EXPORT_OK}->{$name} = 1;
3417
3418 unless ($opt{without_document}) {
3419 $result = pod_block (@desc) . $result;
3420 }
3421
3422 $result;
3423 } # const2perl
3424
3425 sub param2poditem ($;%) {
3426 my ($node, %opt) = @_;
3427 my @desc;
3428 $opt{name_prefix} = 'Parameter: ' unless defined $opt{name_prefix};
3429 if ($node->get_attribute ('Name')) {
3430 push @desc, $opt{name_prefix} . pod_code $node->get_attribute_value ('Name');
3431 } elsif ($node->get_attribute ('QName')) {
3432 push @desc, pod_item $opt{name_prefix} .
3433 qname_label ($node,
3434 out_type => ExpandedURI q<lang:pod>);
3435 } else {
3436 valid_err q<Attribute "Name" or "QName" required>,
3437 node => $node;
3438 }
3439
3440 my @val;
3441 push @val, pod_item (type_label (type_expanded_uri
3442 ($node->get_attribute_value
3443 ('Type',
3444 default => 'DOMMain:any')),
3445 is_pod => 1)),
3446 pod_para (get_description $node);
3447 for (@{$node->child_nodes}) {
3448 last unless $_->node_type eq '#element';
3449 if ($_->local_name eq 'InCase') {
3450 push @val, pod_item (get_incase_label $_, is_pod => 1),
3451 pod_para (get_description $_);
3452 } elsif ({qw/Name 1 QName 1 Type 1
3453 Description 1 ImplNote 1/}->{$_->local_name}) {
3454 #
3455 } else {
3456 valid_err qq{Element type "@{[$_->local_name]}" not supported},
3457 node => $_;
3458 }
3459 }
3460
3461 if (@val) {
3462 push @desc, pod_list 4, @val;
3463 }
3464
3465 @desc;
3466 } # param2poditem
3467
3468 sub subtype2poditem ($;%) {
3469 my ($node, %opt) = @_;
3470 my @desc;
3471 $opt{name_prefix} = 'SubType: ' unless defined $opt{name_prefix};
3472 my $qname = $node->get_attribute_value ('QName');
3473 if (defined $qname) {
3474 push @desc, pod_item $opt{name_prefix} .
3475 qname_label ($node, qname => $qname,
3476 out_type => ExpandedURI q<lang:pod>);
3477 } else {
3478 valid_err q<Attribute "QName" required>,
3479 node => $node;
3480 }
3481
3482 push @desc, pod_para (get_description $node);
3483 my @param;
3484 for (@{$node->child_nodes}) {
3485 last unless $_->node_type eq '#element';
3486 if ($_->local_name eq 'Param') {
3487 push @param, param2poditem ($_);
3488 } elsif ({qw/QName 1 Type 1 SpecLevel 1
3489 Description 1 ImplNote 1/}->{$_->local_name}) {
3490 #
3491 } else {
3492 valid_err qq{Element type "@{[$_->local_name]}" not supported},
3493 node => $_;
3494 }
3495 }
3496
3497 if (@param) {
3498 push @desc, pod_list 4, @param;
3499 }
3500
3501 my $desc_template = get_description $node,
3502 type => ExpandedURI q<lang:muf>,
3503 default => $qname;
3504 $Status->{const_subtype}->{type_expanded_uri $qname} = {
3505 description => $desc_template,
3506 };
3507
3508
3509 @desc;
3510 } # subtype2poditem
3511
3512 =head2 Require element
3513
3514 The C<Require> element indicates that some external modules
3515 are required. Both DOM-implementing modules and language-specific
3516 library modules are allowed.
3517
3518 Children:
3519
3520 =over 4
3521
3522 =item Require/Module (0 - infinite)
3523
3524 A required module.
3525
3526 Children:
3527
3528 =over 4
3529
3530 =item Require/Module/Name = name (0 - 1)
3531
3532 The DOM module name. Iif it is a DOM-implementing module,
3533 this attribute MUST be specified.
3534
3535 =item Require/Module/Namespace = namespace-uri (0 - 1)
3536
3537 The namespace URI for the module, if any. Namespace prefix
3538 C<Name> is to be binded with C<Namespace> if both
3539 C<Name> and C<Namespace> are available.
3540
3541 =item Require/Module/Def = Type-dependent (0 - infinite)
3542
3543 Language-depending definition of loading of the required module.
3544 If no appropriate C<Type> of C<Def> element is available,
3545 loading code is generated from C<Name> attribute.
3546
3547 =back
3548
3549 =back
3550
3551 =cut
3552
3553 sub req2perl ($) {
3554 my $node = shift;
3555 my $reqnode = $node->local_name eq 'Require' ? $node :
3556 $node->get_attribute ('Require', make_new_node => 1);
3557 my $result = '';
3558 for (@{$reqnode->child_nodes}) {
3559 if ($_->local_name eq 'Module') {
3560 my $m_name = $_->get_attribute_value ('Name', default => '<anon>');
3561 my $ns_uri = $_->get_attribute_value ('Namespace');
3562 $Info->{Namespace}->{$m_name} = $ns_uri if defined $ns_uri;
3563 $m_name = perl_name $m_name, ucfirst => 1;
3564 my $desc = get_description $_;
3565 $result .= perl_comment (($m_name ne '<anon>' ? $m_name : '') .
3566 ($desc ? ' - ' . $desc : ''))
3567 if $desc or $m_name ne '<anon>';
3568 my $def = get_perl_definition_node $_, name => 'Def';
3569 if ($def) {
3570 my $s;
3571 my $req;
3572 my $pack_name;
3573 if ($req = $def->get_attribute ('require')) {
3574 $s = 'require ' . ($pack_name = perl_code $req->value);
3575 $Info->{uri_to_perl_package}->{$ns_uri} = $pack_name if $ns_uri;
3576 $Info->{Require_perl_package}->{$pack_name} = 1;
3577 } elsif ($req = $def->get_attribute ('use')) {
3578 $s = 'use ' . ($pack_name = perl_code $req->value);
3579 $Info->{uri_to_perl_package}->{$ns_uri} = $pack_name if $ns_uri;
3580 $Info->{Require_perl_package}->{$pack_name} = 1;
3581 $Info->{Require_perl_package_use}->{$pack_name} = 1;
3582 } elsif (defined ($s = $def->value)) {
3583 #
3584 } else {
3585 valid_warn qq<Required module definition for $m_name is empty>;
3586 }
3587 if ($req and my $list = $req->get_attribute_value ('Import',
3588 as_array => 1)) {
3589 if (@$list) {
3590 $s .= ' ' . perl_list @$list;
3591 $Info->{Require_perl_package_use}
3592 ->{$pack_name . '::::Import'}->{$_} = 1 for @$list;
3593 }
3594 }
3595 $result .= perl_statement $s;
3596 } else {
3597 $result .= perl_statement 'require ' .
3598 perl_code "__CLASS{$m_name}__";
3599 }
3600 } elsif ($_->local_name eq 'Condition') {
3601 } else {
3602 valid_warn qq[Requiredness type @{[$_->local_name]} not supported];
3603 }
3604 }
3605 $result;
3606 }
3607
3608 =head2 Module element
3609
3610 A "dis" file requires one (and only one) C<Module> top-level element.
3611 Other elements, such as C<Require>, may include C<Module> elements
3612 as their children.
3613
3614 Children:
3615
3616 =over 4
3617
3618 =item Module/Name = name (0 - 1)
3619
3620 The module name. Usually DOM IDL module name is used.
3621
3622 This attribute is required when C<Module> element is used as
3623 a top-level element. It is optional if C<Module> is a child
3624 of other element.
3625
3626 =item Module/Package = Type-dependent (0 - infinite)
3627
3628 The module package name. For example,
3629
3630 Module:
3631 @Name: module1
3632 @Package:
3633 @@@: Module1
3634 @@Type:
3635 lang:Perl
3636
3637 means that general module name is C<module1> and Perl-specific
3638 module name is C<Module1>.
3639
3640 =item Module/Namespace = namespace (1 - 1)
3641
3642 The namespace URI (an absolute URI with optional fragment identifier)
3643 that is assigned to this module. Datatypes defined by this module
3644 (such as C<DataType> or C<Interface>) are considered to belong to
3645 this namespace.
3646
3647 In addition, the default namespace is binding to this namespace name
3648 (in other word, special namespace prefix C<#default> is associated
3649 with the URI reference).
3650
3651 =item Module/FullName = text (0 - infinite)
3652
3653 A human-readable module name.
3654
3655 =item Module/Description = text (0 - infinite)
3656
3657 A human-readable module description.
3658
3659 =item Module/License = qname (1 - 1)
3660
3661 A qname that identify the license term.
3662
3663 =item Module/Date.RCS = <rcs date> (1 - 1)
3664
3665 The last-modified date-time of this module,
3666 represented in RCS format (text C<Date:> with date and time,
3667 enclosed by C<$>s).
3668
3669 =item Module/Require (0 - infinite)
3670
3671 A list of modules (DOM modules or other liburary modules)
3672 that is required by entire module.
3673
3674 =back
3675
3676 =cut
3677
3678 ## Get general information
3679 $Info->{source_filename} = $ARGV;
3680
3681 ## Initial Namespace bindings
3682 for ([ManakaiDOM => ExpandedURI q<ManakaiDOM:>],
3683 [http => q<http:>]) {
3684 $Info->{Namespace}->{$_->[0]} = $_->[1];
3685 }
3686
3687 ## Initial DataType aliasing and inheritance
3688 for (ExpandedURI q<ManakaiDOM:ManakaiDOMURI>,
3689 ExpandedURI q<ManakaiDOM:ManakaiDOMNamespaceURI>,
3690 ExpandedURI q<ManakaiDOM:ManakaiDOMFeatureName>,
3691 ExpandedURI q<ManakaiDOM:ManakaiDOMFeatureVersion>,
3692 ExpandedURI q<ManakaiDOM:ManakaiDOMFeatures>) {
3693 $Info->{DataTypeAlias}->{$_}
3694 ->{isa_uri} = [ExpandedURI q<DOMMain:DOMString>];
3695 }
3696
3697 register_namespace_declaration ($source);
3698
3699 my $Module = $source->get_attribute ('Module', make_new_node => 1);
3700 $Info->{Name} = perl_name $Module->get_attribute_value ('Name'), ucfirst => 1
3701 or valid_err q<Module name (/Module/Name) MUST be specified>;
3702 $Info->{Namespace}->{(DEFAULT_PFX)}
3703 = $Module->get_attribute_value ('Namespace')
3704 or valid_err q<Module namespace URI (/Module/Namespace) MUST be specified>;
3705 $Info->{Namespace}->{$Module->get_attribute_value ('Name')}
3706 = $Info->{Namespace}->{(DEFAULT_PFX)};
3707 my $pack_node = get_perl_definition_node $Module, name => 'BindingName';
3708 if ($pack_node) {
3709 $Info->{Package} = perl_code $pack_node->value;
3710 } else {
3711 $Info->{Package} = perl_package_name name => $Info->{Name};
3712 }
3713 $Info->{uri_to_perl_package}->{$Info->{Namespace}->{(DEFAULT_PFX)}}
3714 = $Info->{Package};
3715 $Info->{Require_perl_package} = {};
3716 $Info->{Require_perl_package_use} = {};
3717
3718 ## Make source code
3719 $result .= perl_comment q<This file is automatically generated from> . "\n" .
3720 q<"> . $Info->{source_filename} . q<" at > .
3721 rfc3339_date (time) . qq<.\n> .
3722 q<Don't edit by hand!>;
3723
3724 $result .= perl_statement q<use strict>;
3725
3726 local $Status->{depth} = $Status->{depth} + 1;
3727 $result .= perl_package full_name => $Info->{Package};
3728 $result .= perl_statement perl_assign 'our $VERSION' => version_date time;
3729
3730 $result .= pod_block
3731 pod_head (1, 'NAME'),
3732 pod_para ($Info->{Package} .
3733 ' - ' . get_description ($Module, name => 'FullName')),
3734 section (
3735 opt => pod_head (1, 'DESCRIPTION'),
3736 req => pod_para (get_description ($Module)),
3737 ),
3738 pod_head (1, 'DOM INTERFACES');
3739
3740 ## Conditions
3741 my $defcond = 0;
3742 for my $cond (@{$Module->child_nodes}) {
3743 next unless $cond->node_type eq '#element' and
3744 $cond->local_name eq 'ConditionDef';
3745 my $name = $cond->get_attribute_value ('Name', default => '');
3746 my $isa = $cond->get_attribute_value ('ISA', default => []);
3747 my $fullname = get_description $cond, name => 'FullName';
3748 $isa = [$isa] unless ref $isa;
3749 if ($name =~ /^DOM(\d+)$/) {
3750 $defcond = $1 if $1 > $defcond;
3751 $fullname ||= "DOM Level " . (0 + $1);
3752 }
3753 $Info->{Condition}->{$name}->{ISA} = $isa;
3754 $Info->{Condition}->{$name}->{FullName} = $fullname || $name;
3755 }
3756 if (keys %{$Info->{Condition}}) {
3757 $Info->{NormalCondition} = $Module->get_attribute_value
3758 ('NormalCondition') ||
3759 $defcond ? 'DOM' . $defcond :
3760 valid_err q<Module/NormalCondition required>;
3761 }
3762
3763 ## 'require'ing external modules
3764 {
3765 my $req = $Module->get_attribute ('Require', make_new_node => 1);
3766 my $reqModule = sub {
3767 my ($name, $me, $you) = @_;
3768 if ($you->get_attribute_value ('Name', default => '') eq $name) {
3769 return 1;
3770 } else {
3771 return 0;
3772 }
3773 };
3774 if (not $req->get_element_by (sub {$reqModule->('ManakaiDOMMain', @_)})) {
3775 for ($req->append_new_node (type => '#element',
3776 local_name => 'Module')) {
3777 $_->set_attribute (Name => 'ManakaiDOMMain');
3778 $_->set_attribute (Namespace => ExpandedURI q<ManakaiDOM:>);
3779 }
3780 }
3781 if (not $req->get_element_by (sub {$reqModule->('DOMMain', @_)})) {
3782 for ($req->append_new_node (type => '#element',
3783 local_name => 'Module')) {
3784 $_->set_attribute (Name => 'DOMMain');
3785 $_->set_attribute (Namespace => ExpandedURI q<DOMMain:>);
3786 }
3787 }
3788 $result .= req2perl $Module;
3789 }
3790
3791 for my $node (@{$source->child_nodes}) {
3792 if ($node->node_type ne '#element') {
3793 ##
3794 } elsif ($node->local_name eq 'IF') {
3795 $result .= if2perl $node;
3796 } elsif ($node->local_name eq 'Exception' or
3797 $node->local_name eq 'Warning') {
3798 $result .= exception2perl $node;
3799 } elsif ($node->local_name eq 'DataType') {
3800 $result .= datatype2perl $node;
3801 } elsif ($node->local_name eq 'DataTypeAlias') {
3802 $result .= datatypealias2perl $node;
3803 } elsif ($node->local_name eq 'ConstGroup') {
3804 $result .= constgroup2perl $node;
3805 } elsif ($node->local_name eq 'Const') {
3806 $result .= const2perl $node;
3807 } elsif ({qw/Module 1 Namespace 1 ImplNote 1/}->{$node->local_name}) {
3808 #
3809 } else {
3810 valid_warn qq{Top-level element type "@{[$node->local_name]}" not supported};
3811 }
3812 }
3813
3814 ## Export
3815 if (keys %{$Status->{EXPORT_OK}||{}}) {
3816 $result .= perl_package full_name => $Info->{Package};
3817 $result .= perl_statement 'require Exporter';
3818 $result .= perl_inherit ['Exporter'];
3819 $result .= perl_statement
3820 perl_assign
3821 perl_var (type => '@', scope => 'our',
3822 local_name => 'EXPORT_OK')
3823 => '(' . perl_list (keys %{$Status->{EXPORT_OK}}) . ')';
3824 if (keys %{$Status->{EXPORT_TAGS}||{}}) {
3825 $result .= perl_statement
3826 perl_assign
3827 perl_var (type => '%', scope => 'our',
3828 local_name => 'EXPORT_TAGS')
3829 => '(' . perl_list (map {
3830 $_ => [keys %{$Status->{EXPORT_TAGS}->{$_}}]
3831 } keys %{$Status->{EXPORT_TAGS}}) . ')';
3832 }
3833 }
3834
3835 ## Feature
3836 my @feature_desc;
3837 my $features = 0;
3838 for my $condition (sort keys %{$Info->{Condition}}, '') {
3839 for my $Feature (@{$Module->child_nodes}) {
3840 next unless $Feature->node_type eq '#element' and
3841 $Feature->local_name eq 'Feature' and
3842 condition_match $Feature, condition => $condition;
3843 is_all_implemented condition => $condition,
3844 not_implemented => (my $not_implemented = []);
3845
3846 my $f_name = $Feature->get_attribute_value ('Name', default => '');
3847 unless (length $f_name) {
3848 $f_name = expanded_uri $Feature->get_attribute_value ('QName');
3849 }
3850 my $f_ver = $Feature->get_attribute_value ('Version');
3851
3852 push @feature_desc, pod_item ('Feature ' . pod_code ($f_name) .
3853 ' version ' . pod_code ($f_ver) .
3854 ($Info->{Condition}->{$condition}->{FullName} ?
3855 ' [' . $Info->{Condition}->{$condition}
3856 ->{FullName} . ']' : '')),
3857 pod_paras (get_description $Feature);
3858
3859 if (@$not_implemented) {
3860 push @feature_desc, pod_para ('This module provides interfaces '.
3861 'of this feature but not yet fully ' .
3862 'implemented.');
3863 $result .= perl_comment "$f_name, $f_ver: $not_implemented->[0]." .
3864 "$not_implemented->[1]<$not_implemented->[2]>" .
3865 " not implemented.";
3866 } else {
3867 push @feature_desc, pod_para ('This module implements this feature, ' .
3868 'so that the method calls such as ' .
3869 pod_code ('$DOMImplementation' .
3870 '->hasFeature (' .
3871 perl_literal ($f_name) .
3872 ', ' . perl_literal ($f_ver) .
3873 ')') . ' or ' .
3874 pod_code ('$DOMImplementation' .
3875 '->hasFeature (' .
3876 perl_literal ($f_name) .
3877 ', null)') .
3878 ' will return ' . pod_code ('true') . '.');
3879 }
3880
3881 for (@{$Feature->child_nodes}) {
3882 next unless $_->node_type eq '#element';
3883 if ($_->local_name eq 'Contrib') {
3884 my $n = $_->value;
3885 my $ccondition;
3886 if ($n =~ s/::([^:]*)$//) {
3887 $ccondition = $1;
3888 }
3889 if ($n =~ s/^[^:]*://) {
3890 # currently prefix is not used
3891 }
3892 $result .= perl_statement
3893 perl_assign
3894 perl_var (type => '$',
3895 package => {
3896 name => $n,
3897 condition => $ccondition,
3898 is_internal => 1,
3899 },
3900 local_name => 'Feature').
3901 ## Feature name is case-insensitive
3902 '->{'.perl_literal (lc $f_name).'}->{'.
3903 perl_literal (@$not_implemented ? '+dummy+' : $f_ver) . '}'
3904 => 1;
3905 } elsif ({
3906 qw/Name 1 QName 1 FullName 1 Version 1
3907 Description 1 ImplNote 1 Spec 1
3908 Condition 1 /
3909 }->{$_->local_name}) {
3910 } else {
3911 valid_err q<Unknown element type>, node => $_;
3912 }
3913 }
3914
3915 $features++;
3916 }
3917 }
3918 if (@feature_desc) {
3919 $result .= pod_block
3920 pod_head (1, 'DOM FEATURE'.($features>1?'S':'')),
3921 pod_list 4, @feature_desc;
3922 }
3923
3924 ## TODO list
3925 my @todo;
3926 ## From not-implemented list
3927 for my $if (sort keys %{$Info->{is_implemented}}) {
3928 for my $mem (sort keys %{$Info->{is_implemented}->{$if}}) {
3929 for my $cond (sort keys %{$Info->{is_implemented}->{$if}->{$mem}}) {
3930 if (not $Info->{is_implemented}->{$if}->{$mem}->{$cond}) {
3931 push @todo, pod_item ('Implement '.pod_code ($if).'.'.
3932 pod_code ($mem).'.'),
3933 pod_para ('Condition = '.
3934 ($Info->{Condition}->{$cond}->{FullName} ||
3935 '(empty)'));
3936 }
3937 }
3938 }
3939 }
3940 ## From Description, ImplNote, Def
3941 my $a;
3942 $a = sub {
3943 my $n = shift;
3944 for (@{$n->child_nodes}) {
3945 if ($_->node_type eq '#element') {
3946 $a->($_);
3947 }
3948 }
3949 if (($n->node_type eq '#element' and
3950 {qw/Description 1 ImplNote 1
3951 Def 1 IntDef 1/}->{$n->local_name}) or
3952 $n->node_type eq '#comment') {
3953 my $v = $n->value;
3954 if (defined $v) {
3955 if (ref $v eq 'ARRAY') {
3956 $v = join "\n", @$v;
3957 }
3958 if ($v =~ /\b(TODO|ISSUE|BUG):/) {
3959 push @todo, pod_item ($1.': '.pod_code $n->node_path(key => 'Name'));
3960 my $t = $n->node_type eq '#comment' ? ExpandedURI q<DOMMain:any> :
3961 $n->get_attribute_value
3962 ('Type',
3963 default => {
3964 Description => ExpandedURI q<lang:disdoc>,
3965 ImplNote => ExpandedURI q<lang:disdoc>,
3966 Def => ExpandedURI q<DOMMain:any>,
3967 IntDef => ExpandedURI q<DOMMain:any>,
3968 }->{$n->local_name});
3969 if ($t eq ExpandedURI q<lang:disdoc>) {
3970 push @todo, disdoc2pod $v;
3971 } else {
3972 push @todo, pod_pre ($v);
3973 }
3974 }
3975 }
3976 }
3977 };
3978 $a->($source);
3979 if (@todo) {
3980 $result .= pod_block
3981 pod_head (1, 'TO DO'),
3982 pod_list 4, @todo;
3983 }
3984
3985
3986 ## Namespace bindings for documentation
3987 if (my $n = keys %{$Status->{ns_in_doc}}) {
3988 my @desc = (pod_head (1, 'NAMESPACE BINDING'.($n > 1 ? 'S' : '')),
3989 pod_para ('In this documentation, namespace prefix'.
3990 ($n > 1 ? 'es ' : ' ').
3991 ($n > 1 ? 'are' : 'is').' bound to:'));
3992 push @desc,
3993 pod_list 4, map {
3994 pod_item (pod_code $_),
3995 pod_para (pod_code ($Status->{ns_in_doc}->{$_})),
3996 } keys %{$Status->{ns_in_doc}};
3997 $result .= pod_block @desc;
3998 }
3999
4000 ## See also
4001 ## TODO: implement this.
4002
4003 ## Author
4004 my @desc;
4005 my @author;
4006 my $author;
4007 my $authors = 0;
4008 for (@{$Module->child_nodes}) {
4009 if ($_->node_type eq '#element' and $_->local_name eq 'Author') {
4010 my $n = get_description ($_, name => 'FullName');
4011 push @author, pod_item $n;
4012 my @d;
4013 $author = defined $author ? $authors ? $author
4014 : ($authors++, $author . ', et al.')
4015 : $n;
4016 for (@{$_->child_nodes}) {
4017 next unless $_->node_type eq '#element';
4018 if ($_->local_name eq 'Mail') {
4019 push @d, pod_item ('Mail'), pod_para (pod_mail $_->value);
4020 } elsif ({qw/FullName 1/}->{$_->local_name}) {
4021 #
4022 } else {
4023 valid_err q<Unknown element type>, node => $_;
4024 }
4025 }
4026 push @author, pod_list 6, @d if @d;
4027 }
4028 }
4029 $author = 'AUTHORS' unless defined $author;
4030 if (@author) {
4031 push @desc, pod_head (1, 'AUTHOR'.($authors?'S':'')),
4032 pod_list (4, @author);
4033 }
4034
4035 ## License
4036 push @desc, pod_head (1, 'LICENSE');
4037 my $year = (gmtime)[5]+1900;
4038 my $license = expanded_uri
4039 $Module->get_attribute_value ('License', default => '');
4040 if ($license eq ExpandedURI q<license:Perl>) {
4041 push @desc,
4042 pod_para (qq<Copyright $year $author. All rights reserved.>),
4043 pod_para q<This program is free software; you can redistribute it and/or
4044 modify it under the same terms as Perl itself.>;
4045 } elsif ($license eq ExpandedURI q<license:Perl+MPL>) {
4046 push @desc,
4047 pod_para (qq<Copyright $year $author. All rights reserved.>),
4048 pod_para (q<This program is free software; you can redistribute it and/or >.
4049 q<modify it under the same terms as Perl itself.>),
4050
4051 pod_para (q<Alternatively, the contents of this file may be used >.
4052 q<under the following terms (the >.pod_dfn (q<MPL/GPL/LGPL>).
4053 q<, in which case the provisions of the MPL/GPL/LGPL are applicable instead >.
4054 q<of those above. If you wish to allow use of your version of this file only >.
4055 q<under the terms of the MPL/GPL/LGPL, and not to allow others to >.
4056 q<use your version of this file under the terms of the Perl, indicate your >.
4057 q<decision by deleting the provisions above and replace them with the notice >.
4058 q<and other provisions required by the MPL/GPL/LGPL. If you do not delete >.
4059 q<the provisions above, a recipient may use your version of this file under >.
4060 q<the terms of any one of the Perl or the MPL/GPL/LGPL. >),
4061
4062 pod_head (2, 'MPL/GPL/LGPL'),
4063
4064 # q<***** BEGIN LICENSE BLOCK *****>
4065 pod_para (q<Version: MPL 1.1/GPL 2.0/LGPL 2.1>),
4066
4067 pod_para
4068 (q<The contents of this file are subject to the Mozilla Public License Version >.
4069 q<1.1 (the >.pod_dfn (q<License>).q<); you may not use this file except in >.
4070 q<compliance with >.
4071 q<the License. You may obtain a copy of the License at >.
4072 pod_uri (q<http://www.mozilla.org/MPL/>).q<.>),
4073
4074 pod_para
4075 (q<Software distributed under the License is distributed on an ">.
4076 pod_em (q<AS IS>).q<" basis, >.
4077 pod_em (q<WITHOUT WARRANTY OF ANY KIND>).
4078 q<, either express or implied. See the License >.
4079 q<for the specific language governing rights and limitations under the >.
4080 q<License. >);
4081
4082 my $orig = $Module->get_attribute ('License')->get_attribute ('Original');
4083 if ($orig) {
4084 push @desc, pod_para ('The Original Code is the '.
4085 get_description ($orig, name => 'FullName').'.');
4086 push @desc, pod_para ('The Initial Developer of the Original Code is '.
4087 get_description ($orig->get_attribute ('Author'),
4088 name => 'FullName').'. '.
4089 q<Portions created by the Initial Developer are >.
4090 q<Copyright >.pod_char (name => 'copy').' '.
4091 $orig->get_attribute_value ('Year',
4092 default => $year).
4093 q< the Initial Developer. All Rights Reserved.>);
4094 } else {
4095 my $a = $author;
4096 $a =~ /, et al\.$/ if $authors;
4097
4098 push @desc, pod_para
4099 (q<The Original Code is the manakai DOM module.>),
4100
4101 pod_para (qq<The Initial Developer of the Original Code is $a. >.
4102 q<Portions created by the Initial Developer are Copyright >.
4103 pod_char (name => 'copy').qq< $year >.
4104 ## ISSUE: Should first created year provided from some source?
4105 q<the Initial Developer. All Rights Reserved.>);
4106 }
4107
4108 push @desc, pod_list 4,
4109 pod_item (q<Contributor(s):>),
4110 pod_para (q<See >.
4111 pod_link (section => 'AUTHOR'.($authors?'S':'')).
4112 q<.>);
4113
4114 push @desc, pod_para
4115 q<Alternatively, the contents of this file may be used under the terms of >.
4116 q<either the GNU General Public License Version 2 or later (the ">.
4117 pod_dfn (q<GPL>).q<"), or >.
4118 q<the GNU Lesser General Public License Version 2.1 or later (the ">.
4119 pod_dfn (q<LGPL>).q<"), >.
4120 q<in which case the provisions of the GPL or the LGPL are applicable instead >.
4121 q<of those above. If you wish to allow use of your version of this file only >.
4122 q<under the terms of either the GPL or the LGPL, and not to allow others to >.
4123 q<use your version of this file under the terms of the MPL, indicate your >.
4124 q<decision by deleting the provisions above and replace them with the notice >.
4125 q<and other provisions required by the GPL or the LGPL. If you do not delete >.
4126 q<the provisions above, a recipient may use your version of this file under >.
4127 q<the terms of any one of the MPL, the GPL or the LGPL. >;
4128
4129 # ***** END LICENSE BLOCK *****
4130 } elsif ($license) {
4131 valid_warn q<Unknown license: <$license>>;
4132 push @desc,
4133 pod_para (qq<Copyright $year $author. All rights reserved.>),
4134 pod_para (qq<License: >.pod_uri ($license).q<.>);
4135 } else {
4136 valid_err q<Required attribute "/Module/License" not specified>;
4137 }
4138 $result .= pod_block @desc;
4139
4140
4141 $result .= perl_statement 1;
4142
4143 output_result $result;
4144
4145
4146 __END__
4147
4148 =head1 SEE ALSO
4149
4150 W3C DOM Specifications <http://www.w3.org/DOM/DOMTR>
4151
4152 SuikaWiki:DOM <http://suika.fam.cx/~wakaba/-temp/wiki/wiki?DOM>
4153
4154 C<idl2dis.pl>: This script generates "dis" files,
4155 that can be used as a template for the DOM implementation,
4156 from DOM IDL files.
4157
4158 =head1 LICENSE
4159
4160 Copyright 2004 Wakaba <w@suika.fam.cx>. All rights reserved.
4161
4162 This program is free software; you can redistribute it and/or
4163 modify it under the same terms as Perl itself.
4164
4165 Note that copyright holder(s) of this script does not claim
4166 any rights for materials outputed by this script, although it will
4167 contain some fragments from this script. License terms for them should be
4168 defined by the copyright holder of the source document.
4169
4170 =cut
4171
4172 # $Date: 2004/10/10 00:01:08 $
4173
4174

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24