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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24