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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations) (download)
Wed Jan 5 12:19:38 2005 UTC (19 years, 10 months ago) by wakaba
Branch: MAIN
Changes since 1.16: +483 -106 lines
File MIME type: text/plain
Assertion in dis perl code implemented; DISPerl:raiseException implemented; Scripts updated for new dis format; NodeList perl array representation implemented

1 wakaba 1.1 #!/usr/bin/perl -w
2     use strict;
3 wakaba 1.17
4     =head1 NAME
5    
6     cdis2pm - Generating Perl Module from a Compiled "dis"
7    
8     =head1 SYNOPSIS
9    
10     perl path/to/cdis2pm.pl input.cdis \
11     {--module-name=ModuleName | --module-uri=module-uri} \
12     [--for=for-uri] [options] > ModuleName.pm
13     perl path/to/cdis2pm.pl --help
14    
15     =head1 DESCRIPTION
16    
17     The C<cdis2pm> script generates a Perl module from a compiled "dis"
18     ("cdis") file. It is intended to be used to generate a manakai
19     DOM Perl module files, although it might be useful for other purpose.
20    
21     This script is part of manakai.
22    
23     =cut
24    
25 wakaba 1.1 use Message::Util::QName::Filter {
26     d => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#dis-->,
27     dis2pm => q<http://suika.fam.cx/~wakaba/archive/2004/11/8/dis2pm#>,
28 wakaba 1.10 DISCore => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Core#>,
29     DISLang => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Lang#>,
30 wakaba 1.9 DISPerl => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Perl#>,
31 wakaba 1.4 disPerl => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#dis--Perl-->,
32 wakaba 1.1 DOMCore => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/dom-core#>,
33 wakaba 1.15 DOMEvents => q<http://suika.fam.cx/~wakaba/archive/2004/dom/events#>,
34 wakaba 1.1 DOMMain => q<http://suika.fam.cx/~wakaba/archive/2004/dom/main#>,
35 wakaba 1.12 DOMXML => q<http://suika.fam.cx/~wakaba/archive/2004/dom/xml#>,
36 wakaba 1.1 lang => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#>,
37     Perl => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#Perl-->,
38     license => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/license#>,
39     ManakaiDOM => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/manakai-dom#>,
40 wakaba 1.3 MDOMX => q<http://suika.fam.cx/~wakaba/archive/2004/8/4/manakai-dom-exception#>,
41 wakaba 1.1 owl => q<http://www.w3.org/2002/07/owl#>,
42     rdf => q<http://www.w3.org/1999/02/22-rdf-syntax-ns#>,
43     rdfs => q<http://www.w3.org/2000/01/rdf-schema#>,
44 wakaba 1.10 TreeCore => q<>,
45 wakaba 1.1 };
46    
47 wakaba 1.17 =head1 OPTIONS
48    
49     =over 4
50    
51     =item --enable-assertion / --noenable-assertion (default)
52    
53     Whether assertion codes should be outputed or not.
54    
55     =item --for=I<for-uri> (Optional)
56    
57     Specifies the "For" URI reference for which the outputed module is.
58     If this parameter is ommitted, the default "For" URI reference
59     for the module, if any, or the C<ManakaiDOM:all> is assumed.
60    
61     =item --help
62    
63     Shows the help message.
64    
65     =item --module-name=I<ModuleName>
66    
67     The name of module to output. It is the local name part of
68     the C<Module> C<QName> in the source "dis" file. Either
69     C<--module-name> or C<--module-uri> is required.
70    
71     =item --module-uri=I<module-uri>
72    
73     A URI reference that identifies a module to output. Either
74     C<--module-name> or C<--module-uri> is required.
75    
76     =item --output-module-version (default) / --nooutput-module-version
77    
78     Whether the C<$VERSION> special variable should be generated or not.
79    
80     =item --verbose / --noverbose (default)
81    
82     Whether a verbose message mode should be selected or not.
83    
84     =back
85    
86     =cut
87    
88 wakaba 1.1 use Getopt::Long;
89     use Pod::Usage;
90     use Storable;
91     my %Opt;
92     GetOptions (
93 wakaba 1.17 'enable-assertion!' => \$Opt{outputAssertion},
94 wakaba 1.1 'for=s' => \$Opt{For},
95     'help' => \$Opt{help},
96     'module-name=s' => \$Opt{module_name},
97     'module-uri=s' => \$Opt{module_uri},
98 wakaba 1.17 'output-module-version!' => \$Opt{outputModuleVersion},
99 wakaba 1.1 'verbose!' => $Opt{verbose},
100     ) or pod2usage (2);
101     pod2usage ({-exitval => 0, -verbose => 1}) if $Opt{help};
102     $Opt{file_name} = shift;
103     pod2usage ({-exitval => 2, -verbose => 0}) unless $Opt{file_name};
104     pod2usage (2) if not $Opt{module_uri} and not $Opt{module_name};
105 wakaba 1.17 $Opt{outputModuleVersion} = 1 unless defined $Opt{outputModuleVersion};
106 wakaba 1.1
107     BEGIN {
108     require 'manakai/genlib.pl';
109     require 'manakai/dis.pl';
110     }
111     our $State = retrieve ($Opt{file_name})
112     or die "$0: $Opt{file_name}: Cannot load";
113    
114     eval q{
115     sub impl_msg ($;%) {
116     warn shift () . "\n";
117     }
118     } unless $Opt{verbose};
119    
120 wakaba 1.17 =head1 FUNCTIONS
121    
122     This section describes utility functions defined in this script
123     for the sake of developer.
124    
125     =over 4
126    
127     =item $result = perl_change_package (full_name => I<fully qualified Perl package name>)
128    
129     Changes the current Perl package in the output Perl code.
130     C<dispm_package_declarations> is also called in this function.
131    
132     =cut
133    
134 wakaba 1.1 sub perl_change_package (%) {
135     my %opt = @_;
136     my $fn = $opt{full_name};
137     impl_err (qq<$fn: Bad package name>) unless $fn;
138     unless ($fn eq $State->{ExpandedURI q<dis2pm:currentPackage>}) {
139 wakaba 1.11 my $r = dispm_package_declarations (%opt);
140 wakaba 1.1 $State->{ExpandedURI q<dis2pm:currentPackage>} = $fn;
141 wakaba 1.11 $State->{ExpandedURI q<dis2pm:referredPackage>}->{$fn} = -1;
142     return $r . perl_statement qq<package $fn>;
143 wakaba 1.1 } else {
144     return '';
145     }
146     } # perl_change_package
147    
148 wakaba 1.11 =item $code = dispm_package_declarations (%opt)
149    
150     Generates a code fragment that declares what is required
151     in the current package, including import statements for
152     character classes.
153    
154     =cut
155    
156     sub dispm_package_declarations (%) {
157     my %opt = @_;
158     my $pack_name = $State->{ExpandedURI q<dis2pm:currentPackage>};
159     my $pack = $State->{ExpandedURI q<dis2pm:Package>}->{$pack_name};
160     my $r = '';
161     my @xml_class;
162     for (keys %{$pack->{ExpandedURI q<dis2pm:requiredCharClass>}||{}}) {
163     my $val = $pack->{ExpandedURI q<dis2pm:requiredCharClass>}->{$_};
164     next if not ref $val and $val <= 0;
165     if (/^InXML/) {
166     push @xml_class, $_;
167     $pack->{ExpandedURI q<dis2pm:requiredCharClass>}->{$_} = -1;
168     } else {
169     valid_err (qq<"$_": Unknown character class>,
170     node => ref $val ? $val : $opt{node});
171     }
172     }
173     if (@xml_class) {
174     $State->{Module}->{$State->{module}}
175     ->{ExpandedURI q<dis2pm:requiredModule>}
176     ->{'Char::Class::XML'} = 1;
177     $r .= perl_statement 'Char::Class::XML->import ('.
178     perl_list (@xml_class).')';
179     }
180     $r;
181     } # dispm_package_declarations
182    
183 wakaba 1.3 =item $code = dispm_perl_throws (%opt)
184    
185     Generates a code to throw an exception.
186    
187     =cut
188    
189     sub dispm_perl_throws (%) {
190     my %opt = @_;
191 wakaba 1.8 my $x = $opt{class_resource} || $State->{Type}->{$opt{class}};
192 wakaba 1.3 my $r = 'report ';
193     unless (defined $x->{Name}) {
194     $opt{class} = dis_typeforuris_to_uri ($opt{class}, $opt{class_for}, %opt);
195     $x = $State->{Type}->{$opt{class}};
196     }
197     valid_err (qq<Exception class <$opt{class}> is not defined>,
198     node => $opt{node}) unless defined $x->{Name};
199     if ($x->{ExpandedURI q<dis2pm:type>} and
200     {
201     ExpandedURI q<ManakaiDOM:ExceptionClass> => 1,
202     ExpandedURI q<ManakaiDOM:WarningClass> => 1,
203     }->{$x->{ExpandedURI q<dis2pm:type>}}) {
204 wakaba 1.8 $opt{type} = $opt{type_resource}->{Name} unless defined $opt{type};
205     valid_err qq{Exception code must be specified},
206     node => $opt{type_resource}->{src} || $opt{node}
207     unless defined $opt{type};
208 wakaba 1.10 $opt{subtype} = $opt{subtype_resource}->{NameURI} ||
209     $opt{subtype_resource}->{URI} unless defined $opt{subtype};
210 wakaba 1.8 $opt{xparam}->{ExpandedURI q<MDOMX:subtype>} = $opt{subtype}
211     if defined $opt{subtype};
212 wakaba 1.3 $r .= $x->{ExpandedURI q<dis2pm:packageName>} . ' ' .
213     perl_list -type => $opt{type},
214     -object => perl_code_literal ('$self'),
215     %{$opt{xparam} || {}};
216     } else {
217     no warnings 'uninitialized';
218 wakaba 1.8 valid_err (qq{Resource <$opt{class}> [<$x->{ExpandedURI q<dis2pm:type>}>] }.
219     q<is neither an exception class nor >.
220     q<a warning class>, node => $opt{node});
221 wakaba 1.3 }
222     return $r;
223     } # dispm_perl_throw
224    
225 wakaba 1.17 =item Lexical Variable $RegQNameChar
226    
227     The regular expression pattern for a QName character.
228    
229     =item Lexical Variable $RegBlockContent
230    
231     The regular expression pattern for a "block", i.e. a nestable section
232     of "{" ... "}".
233    
234     =cut
235    
236 wakaba 1.11 my $RegQNameChar = qr/[^\s<>"'\\\[\]\{\},=]/;
237 wakaba 1.3 use re 'eval';
238     my $RegBlockContent;
239     $RegBlockContent = qr/(?>[^{}\\]*)(?>(?>[^{}\\]+|\\.|\{(??{$RegBlockContent})\})*)/s;
240 wakaba 1.17
241     =item $result = perl_code ($code, %opt)
242    
243     Converts preprocessing instructions in the <$code> and returns it.
244    
245     Note that this function is also defined in F<genlib.pl> but
246     redefined here for the purpose of this script.
247    
248     =cut
249    
250 wakaba 1.3 sub perl_code ($;%) {
251     my ($s, %opt) = @_;
252     valid_err q<Uninitialized value in perl_code>,
253     node => $opt{node} unless defined $s;
254 wakaba 1.17 $s = $$s if ref $s eq '__code';
255 wakaba 1.3 local $State->{Namespace}
256     = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding};
257 wakaba 1.11 $s =~ s[(?<![qwr])<($RegQNameChar[^<>]+)>|\b(null|true|false)\b][
258 wakaba 1.3 my ($q, $l) = ($1, $2);
259 wakaba 1.4 my $r;
260 wakaba 1.3 if (defined $q) {
261     if ($q =~ /\}/) {
262 wakaba 1.11 valid_warn qq<Inline element "<$q>" has a "}" - it might be a typo>;
263     }
264     if ($q =~ /=$/) {
265     valid_warn qq<Inline element "<$q>" ends with a "=" - >.
266     q{should "=" be used place of "=>"?};
267 wakaba 1.4 }
268     if ($q =~ s/^(.+?):://) {
269     my $et = dis_qname_to_uri
270     ($1, %opt,
271     use_default_namespace => ExpandedURI q<disPerl:>);
272     if ($et eq ExpandedURI q<disPerl:Q>) { ## QName constant
273     $r = perl_literal (dis_qname_to_uri ($q, use_default_namespace => 1,
274     %opt));
275 wakaba 1.10 } elsif ({
276     ExpandedURI q<disPerl:M> => 1,
277     ExpandedURI q<disPerl:ClassM> => 1,
278     ExpandedURI q<disPerl:AG> => 1,
279     ExpandedURI q<disPerl:AS> => 1,
280     }->{$et}) { ## Method call
281 wakaba 1.6 my ($clsq, $mtdq) = split /\s*\.\s*/, $q, 2;
282 wakaba 1.4 my $clsu = dis_typeforqnames_to_uri ($clsq,
283     use_default_namespace => 1, %opt);
284     my $cls = $State->{Type}->{$clsu};
285     my $clsp = $cls->{ExpandedURI q<dis2pm:packageName>};
286 wakaba 1.6 if ($cls->{ExpandedURI q<dis2pm:type>} and
287     {
288     ExpandedURI q<ManakaiDOM:IF> => 1,
289     ExpandedURI q<ManakaiDOM:ExceptionIF> => 1,
290     }->{$cls->{ExpandedURI q<dis2pm:type>}}) {
291     valid_err q<"disPerl:ClassM" cannot be used for interface methods>,
292     node => $opt{node} if $et eq ExpandedURI q<disPerl:ClassM>;
293     $clsp = '';
294     } else {
295     valid_err qq<Package name of class <$clsu> must be defined>,
296     node => $opt{node} unless defined $clsp;
297     $State->{Module}->{$State->{module}}
298     ->{ExpandedURI q<dis2pm:requiredModule>}
299     ->{$State->{Module}->{$cls->{parentModule}}
300     ->{ExpandedURI q<dis2pm:packageName>}} = 1;
301     }
302 wakaba 1.4 if ($mtdq =~ /:/) {
303     valid_err qq<$mtdq: Prefixed method name not supported>,
304     node => $opt{node};
305     } else {
306     my $mtd;
307     for (values %{$cls->{ExpandedURI q<dis2pm:method>}}) {
308     if (defined $_->{Name} and $_->{Name} eq $mtdq) {
309     $mtd = $_;
310     last;
311     }
312     }
313     valid_err qq<Perl method name for method "$clsp.$mtdq" must >.
314     q<be defined>, node => $mtd->{src} || $opt{node}
315     if not defined $mtd or
316     not defined $mtd->{ExpandedURI q<dis2pm:methodName>};
317 wakaba 1.6 $r = ' ' . ($clsp ? $clsp .
318 wakaba 1.10 {
319     ExpandedURI q<disPerl:M> => '::',
320     ExpandedURI q<disPerl:AG> => '::',
321     ExpandedURI q<disPerl:AS> => '::',
322     ExpandedURI q<disPerl:ClassM> => '->',
323     }->{$et}
324 wakaba 1.6 : '') .
325 wakaba 1.4 $mtd->{ExpandedURI q<dis2pm:methodName>} . ' ';
326     }
327 wakaba 1.12 } elsif ({
328     ExpandedURI q<disPerl:Class> => 1,
329     ExpandedURI q<disPerl:IF> => 1,
330     ExpandedURI q<disPerl:ClassName> => 1,
331     ExpandedURI q<disPerl:IFName> => 1,
332     }->{$et}) { ## Perl package name
333 wakaba 1.4 my $uri = dis_typeforqnames_to_uri ($q,
334     use_default_namespace => 1, %opt);
335     if (defined $State->{Type}->{$uri}->{Name} and
336     defined $State->{Type}->{$uri}
337     ->{ExpandedURI q<dis2pm:packageName>}) {
338 wakaba 1.12 $r = $State->{Type}->{$uri}->{ExpandedURI q<dis2pm:packageName>};
339     if ({
340     ExpandedURI q<disPerl:ClassName> => 1,
341     ExpandedURI q<disPerl:IFName> => 1,
342     }->{$et}) {
343     $r = perl_literal $r;
344     }
345 wakaba 1.4 } else {
346     valid_err qq<Package name of class <$uri> must be defined>,
347     node => $opt{node};
348     }
349 wakaba 1.9 } elsif ($et eq ExpandedURI q<disPerl:Code>) { ## CODE constant
350 wakaba 1.11 my ($nm);
351     $q =~ s/^\s+//;
352     if ($q =~ s/^((?>(?!::).)+)//) {
353     $nm = $1;
354     } else {
355     valid_err qq<"$q": Code name required>, node => $opt{node};
356     }
357     $q =~ s/^::\s*//;
358     my $param = dispm_parse_param (\$q, %opt,
359     ExpandedURI q<dis2pm:endOrErr> => 1,
360     use_default_namespace => '');
361     my $uri = dis_typeforqnames_to_uri
362     ($nm, use_default_namespace => 1,
363     %opt);
364 wakaba 1.4 if (defined $State->{Type}->{$uri}->{Name} and
365     dis_resource_ctype_match (ExpandedURI q<dis2pm:InlineCode>,
366     $State->{Type}->{$uri}, %opt)) {
367 wakaba 1.11 local $State->{ExpandedURI q<dis2pm:blockCodeParam>} = $param;
368 wakaba 1.5 ## ISSUE: It might be required to check loop referring
369 wakaba 1.4 $r = dispm_get_code (%opt, resource => $State->{Type}->{$uri},
370     For => [keys %{$State->{Type}->{$uri}
371     ->{For}}]->[0],
372 wakaba 1.14 'For+' => [keys %{$State->{Type}->{$uri}
373     ->{'For+'}||{}}],
374 wakaba 1.11 is_inline => 1,
375     ExpandedURI q<dis2pm:selParent> => $param,
376     ExpandedURI q<dis2pm:DefKeyName>
377     => ExpandedURI q<d:Def>);
378     for (grep {/^\$/} keys %$param) {
379 wakaba 1.17 $r =~ s/\Q$_\E\b/$param->{$_}/g;
380 wakaba 1.11 }
381 wakaba 1.4 } else {
382     valid_err qq<Inline code constant <$uri> must be defined>,
383     node => $opt{node};
384     }
385 wakaba 1.11 } elsif ($et eq ExpandedURI q<disPerl:C>) {
386     if ($q =~ /^((?>(?!\.)$RegQNameChar)*)\.($RegQNameChar+)$/o) {
387     my ($cls, $constn) = ($1, $2);
388     if (length $cls) {
389     my $clsu = dis_typeforqnames_to_uri ($cls, %opt,
390     use_default_namespace => 1,
391     node => $_);
392     $cls = $State->{Type}->{$clsu};
393     valid_err qq<Class/IF <$clsu> must be defined>, node => $_
394     unless defined $cls->{Name};
395     } else {
396     $cls = $State->{ExpandedURI q<dis2pm:thisClass>};
397     valid_err q<Class/IF name required in this context>, node => $_
398     unless defined $cls->{Name};
399     }
400    
401     my $const = $cls->{ExpandedURI q<dis2pm:const>}->{$constn};
402     valid_err qq<Constant value "$constn" not defined in class/IF >.
403     qq{"$cls->{Name}" (<$cls->{URI}>)}, node => $_
404     unless defined $const->{Name};
405     $r = dispm_const_value (resource => $const);
406     } else {
407     valid_err qq<"$q": Syntax error>, node => $opt{node};
408     }
409 wakaba 1.4 } else {
410     valid_err qq<"$et": Unknown element type>, node => $opt{node};
411     }
412     } else {
413     valid_err qq<"<$q>": Element type must be specified>, node => $opt{node};
414 wakaba 1.3 }
415     } else {
416 wakaba 1.4 $r = {true => 1, false => 0, null => 'undef'}->{$l};
417 wakaba 1.3 }
418 wakaba 1.4 $r;
419 wakaba 1.3 ]ge;
420     ## TODO: Ensure Message::Util::Error imported if "try"ing.
421     ## ISSUE: __FILE__ & __LINE__ will break if multiline substition happens.
422     $s =~ s{
423 wakaba 1.11 \b__($RegQNameChar+)
424 wakaba 1.3 (?:\{($RegBlockContent)\})?
425     __\b
426     }{
427     my ($name, $data) = ($1, $2);
428     my $r;
429 wakaba 1.7 my $et = dis_qname_to_uri
430     ($name, %opt,
431     use_default_namespace => ExpandedURI q<disPerl:>);
432 wakaba 1.11 if ($et eq ExpandedURI q<disPerl:DEEP>) { ## Deep Method Call
433 wakaba 1.6 $r = '{'.perl_statement ('local $Error::Depth = $Error::Depth + 1').
434     perl_code ($data) .
435 wakaba 1.3 '}';
436 wakaba 1.11 } elsif ({
437     ExpandedURI q<disPerl:EXCEPTION> => 1,
438     ExpandedURI q<disPerl:WARNING> => 1,
439     }->{$et}) {
440 wakaba 1.3 ## Raising an Exception or Warning
441 wakaba 1.8 if ($data =~ s/^ \s* ((?>(?! ::|\.)$RegQNameChar)+) \s*
442     (?: \. \s* ((?>(?! ::|\.)$RegQNameChar)+) \s*
443     (?: \. \s* ((?>(>! ::|\.)$RegQNameChar)+) \s*
444     )?
445     )?
446     (?: ::\s* | $)//ox) {
447     my ($q, $constq, $subtypeq) = ($1, $2, $3);
448 wakaba 1.17 s/\|/:/g for $q, $constq, $subtypeq;
449     my ($cls, $const, $subtype) = dispm_xcref_to_resources
450     ([$q, $constq, $subtypeq], %opt);
451 wakaba 1.8
452     ## Parameter
453     my %xparam;
454     while ($data =~ s/^\s*($RegQNameChar+)\s*//) {
455     my $pnameuri = dis_qname_to_uri ($1, use_default_namespace => 1, %opt);
456     if (defined $xparam{$pnameuri}) {
457     valid_err qq<Exception parameter <$pnameuri> is already specified>,
458     node => $opt{node};
459     }
460     if ($data =~ s/^=>\s*'([^']*)'\s*//) { ## String
461     $xparam{$pnameuri} = $1;
462     } elsif ($data =~ s/^=>\s*\{($RegBlockContent)\}\s*//) { ## Code
463     $xparam{$pnameuri} = perl_code_literal ($1);
464     } elsif ($data =~ /^,|$/) { ## Boolean
465     $xparam{$pnameuri} = 1;
466     } else {
467     valid_err qq<<$pnameuri>: Parameter value is expected>,
468     node => $opt{node};
469     }
470     $data =~ s/^\,\s*// or last;
471     }
472     valid_err qq<"$data": Broken exception parameter specification>,
473     node => $opt{node} if length $data;
474     for (
475     ExpandedURI q<MDOMX:class>,
476     ExpandedURI q<MDOMX:method>,
477     ExpandedURI q<MDOMX:attr>,
478     ExpandedURI q<MDOMX:on>,
479     ) {
480     $xparam{$_} = $opt{$_} if defined $opt{$_};
481     }
482    
483     $r = dispm_perl_throws
484     (%opt,
485     class_resource => $cls,
486     type_resource => $const,
487     subtype_resource => $subtype,
488     xparam => \%xparam);
489 wakaba 1.3 } else {
490     valid_err qq<Exception type and name required: "$data">,
491     node => $opt{node};
492     }
493 wakaba 1.7 } elsif ($et eq ExpandedURI q<disPerl:CODE>) {
494 wakaba 1.11 my ($nm);
495 wakaba 1.7 $data =~ s/^\s+//;
496     if ($data =~ s/^((?>(?!::).)+)//) {
497 wakaba 1.3 $nm = $1;
498     } else {
499 wakaba 1.7 valid_err q<Code name required>, node => $opt{node};
500 wakaba 1.3 }
501 wakaba 1.17 $data =~ s/^::\s*//;
502 wakaba 1.11 my $param = dispm_parse_param (\$data, %opt,
503     use_default_namespace => '',
504     ExpandedURI q<dis2pm:endOrErr> => 1);
505 wakaba 1.7 my $uri = dis_typeforqnames_to_uri ($nm, use_default_namespace => 1,
506     %opt);
507     if (defined $State->{Type}->{$uri}->{Name} and
508     dis_resource_ctype_match (ExpandedURI q<dis2pm:BlockCode>,
509     $State->{Type}->{$uri}, %opt)) {
510 wakaba 1.11 local $State->{ExpandedURI q<dis2pm:blockCodeParam>} = $param;
511 wakaba 1.10 ## ISSUE: It might be required to detect a loop
512 wakaba 1.7 $r = dispm_get_code (%opt, resource => $State->{Type}->{$uri},
513     For => [keys %{$State->{Type}->{$uri}
514 wakaba 1.11 ->{For}}]->[0],
515 wakaba 1.14 'For+' => [keys %{$State->{Type}->{$uri}
516     ->{'For+'}||{}}],
517 wakaba 1.11 ExpandedURI q<dis2pm:selParent> => $param,
518     ExpandedURI q<dis2pm:DefKeyName>
519     => ExpandedURI q<d:Def>);
520     for (grep {/^\$/} keys %$param) {
521 wakaba 1.17 $r =~ s/\Q$_\E\b/$param->{$_}/g;
522 wakaba 1.7 }
523 wakaba 1.11 valid_err qq<Block code <$uri> is empty>, node => $opt{node}
524     unless length $r;
525 wakaba 1.7 $r = "\n{\n$r\n}\n";
526     } else {
527     valid_err qq<Block code constant <$uri> must be defined>,
528     node => $opt{node};
529     }
530 wakaba 1.11 } elsif ($et eq ExpandedURI q<ManakaiDOM:InputNormalize>) {
531     my $method = $opt{ExpandedURI q<dis2pm:currentMethodResource>};
532     valid_err q<Element <ManakaiDOM:InputNroamlize> cannot be used here>,
533     node => $opt{node} unless defined $method->{Name};
534     PARAM: {
535     for my $param (@{$method->{ExpandedURI q<dis2pm:param>}||[]}) {
536     if ($data eq $param->{ExpandedURI q<dis2pm:paramName>}) {
537     ## NOTE: <ManakaiDOM:noInputNormalize> property is not
538     ## checked for this element.
539     my $nm = dispm_get_code
540     (%opt, resource => $State->{Type}
541     ->{$param->{ExpandedURI q<d:actualType>}},
542     ExpandedURI q<dis2pm:DefKeyName>
543     => ExpandedURI q<ManakaiDOM:inputNormalizer>,
544     ExpandedURI q<dis2pm:getCodeNoTypeCheck> => 1,
545     ExpandedURI q<dis2pm:selParent>
546     => $param->{ExpandedURI q<dis2pm:actualTypeNode>});
547     if (defined $nm) {
548     $nm =~ s[\$INPUT\b][\$$param->{ExpandedURI q<dis2pm:paramName>} ]g;
549     $r = $nm;
550     } else {
551     $r = '';
552     }
553     last PARAM;
554     }
555     }
556     valid_err q<Parameter "$data" is not found>, node => $opt{node};
557 wakaba 1.3 }
558 wakaba 1.10 } elsif ($et eq ExpandedURI q<disPerl:WHEN>) {
559 wakaba 1.3 if ($data =~ s/^\s*IS\s*\{($RegBlockContent)\}::\s*//o) {
560 wakaba 1.10 my $v = dis_qname_to_uri ($1, use_default_namespace => 1, %opt);
561     if ($State->{ExpandedURI q<dis2pm:blockCodeParam>}->{$v}) {
562     $r = perl_code ($data, %opt);
563 wakaba 1.3 }
564     } else {
565     valid_err qq<Syntax for preprocessing macro "WHEN" is invalid>,
566     node => $opt{node};
567     }
568 wakaba 1.10 } elsif ($et eq ExpandedURI q<disPerl:FOR>) {
569     if ($data =~ s/^((?>(?!::).)*)::\s*//) {
570     my @For = ($opt{For} || ExpandedURI q<ManakaiDOM:all>,
571     @{$opt{'For+'} || []});
572     V: for (split /\s*\|\s*/, $1) {
573     my $for = dis_qname_to_uri ($_, %opt, use_default_namespace => 1,
574     node => $opt{node});
575     for (@For) {
576     if (dis_uri_for_match ($for, $_, %opt)) {
577     $r = perl_code ($data, %opt);
578     last V;
579     }
580     }
581     }
582     } else {
583     valid_err (qq<Broken <$et> block: "$data">, node => $opt{node});
584     }
585 wakaba 1.17 } elsif ($et eq ExpandedURI q<disPerl:ASSERT>) {
586     my $atype;
587     if ($data =~ s/^\s*($RegQNameChar+)\s*::\s*//) {
588     $atype = dis_qname_to_uri ($1, %opt, use_default_namespace => 1);
589     } else {
590     valid_err (qq<"$data": Assertion type QName is required>,
591     node => $opt{node});
592     }
593     my $param = dispm_parse_param (\$data, %opt,
594     use_default_namespace => '',
595     ExpandedURI q<dis2pm:endOrErr> => 1);
596     my %xparam;
597     my $cond;
598     my $pre = '';
599     my $post = '';
600     if ($atype eq ExpandedURI q<DISPerl:isPositive>) {
601     $pre = perl_statement
602     perl_assign
603     'my $asActual' =>
604     '('.perl_code ($param->{actual}, %opt).')';
605     $cond = '$asActual > 0';
606     $xparam{ExpandedURI q<DOMMain:expectedLabel>} = 'a positive value';
607     $xparam{ExpandedURI q<DOMMain:actualValue>}
608     = perl_code_literal q<$asActual>;
609     } elsif ($atype eq ExpandedURI q<DISPerl:invariant>) {
610     $cond = '0';
611     $xparam{ExpandedURI q<DOMMain:expectedLabel>} = $param->{msg};
612     $xparam{ExpandedURI q<DOMMain:actualValue>} = '(invariant)';
613     } else {
614     valid_err (qq<Assertion type <$atype> is not supported>,
615     node => $opt{node});
616     }
617     if (defined $param->{pre}) {
618     $pre = perl_code ($param->{pre}, %opt) . $pre;
619     }
620     if (defined $param->{post}) {
621     $post .= perl_code ($param->{post}, %opt);
622     }
623    
624     for (
625     ExpandedURI q<MDOMX:class>,
626     ExpandedURI q<MDOMX:method>,
627     ExpandedURI q<MDOMX:attr>,
628     ExpandedURI q<MDOMX:on>,
629     ) {
630     $xparam{$_} = $opt{$_} if defined $opt{$_};
631     }
632     if ($Opt{outputAssertion}) {
633     $r = $pre . perl_if
634     $cond,
635     undef,
636     perl_statement
637     dispm_perl_throws
638     class =>
639     ExpandedURI q<ManakaiDOM:ManakaiDOMImplementationException>,
640     class_for => ExpandedURI q<ManakaiDOM:ManakaiDOMCommon>,
641     type => 'MDOM_DEBUG_BUG',
642     subtype => ExpandedURI q<DOMMain:ASSERTION_ERR>,
643     xparam => {
644     ExpandedURI q<DOMMain:assertionType> => $atype,
645     ExpandedURI q<DOMMain:traceText>
646     => perl_code_literal
647     q<(sprintf 'at %s line %s%s%s',
648     __FILE__, __LINE__, "\n\t",
649     Carp::longmess ())>,
650     %xparam,
651     };
652     $r .= $post;
653     $r = "{$r}";
654     } else {
655     $r = '';
656     }
657 wakaba 1.11 } elsif ({
658     ExpandedURI q<disPerl:FILE> => 1,
659     ExpandedURI q<disPerl:LINE> => 1,
660     ExpandedURI q<disPerl:PACKAGE> => 1,
661     }->{$et}) {
662 wakaba 1.3 $r = qq<__${name}__>;
663 wakaba 1.11 valid_err (q<Block element content cannot be specified for >.
664     qq<element type <$et>>, node => $opt{node})
665     if length $data;
666 wakaba 1.3 } else {
667 wakaba 1.10 valid_err qq<Preprocessing macro <$et> not supported>, node => $opt{node};
668 wakaba 1.3 }
669     $r;
670     }goex;
671 wakaba 1.11
672     ## Checks \p character classes
673     while ($s =~ /\\p{([^{}]+)}/gs) {
674     my $name = $1;
675     $State->{ExpandedURI q<dis2pm:Package>}
676     ->{$State->{ExpandedURI q<dis2pm:currentPackage>}}
677     ->{ExpandedURI q<dis2pm:requiredCharClass>}
678     ->{$name} ||= $opt{node} || 1;
679     }
680    
681 wakaba 1.3 $s;
682     }
683    
684 wakaba 1.11 =item {%param} = dispm_parse_param (\$paramspec, %opt)
685    
686     Parses parameter specification and returns it as a reference
687     to hash.
688    
689     =cut
690    
691     sub dispm_parse_param ($%) {
692     my ($src, %opt) = @_;
693     my %param;
694     while ($$src =~ s/^
695     ## Parameter name
696     (\$? $RegQNameChar+)\s*
697    
698     (?: =>? \s*
699    
700     ## Parameter value
701     (
702     ## Bare string
703 wakaba 1.17 $RegQNameChar+
704     |
705 wakaba 1.11 ## Quoted string
706     '(?>[^'\\]*)' ## ISSUE: escape mechanism required?
707 wakaba 1.17 |
708     ## Code
709     \{$RegBlockContent\}
710 wakaba 1.11
711     )
712    
713     \s*)?
714    
715     (?:,\s*|$)//ox) {
716     my ($n, $v) = ($1, $2);
717     if (defined $v) {
718     if ($v =~ /^'/) {
719     $v = substr ($v, 1, length ($v) - 2);
720 wakaba 1.17 } elsif ($v =~ /^\{/) {
721     $v = perl_code_literal substr ($v, 1, length ($v) - 2);
722 wakaba 1.11 } else {
723     #
724     }
725     } else {
726     $v = 1;
727     }
728    
729     if ($n =~ /^\$/) {
730     $param{$n} = $v;
731     } else {
732     $param{dis_qname_to_uri ($n, %opt)} = $v;
733     }
734     }
735     if ($opt{ExpandedURI q<dis2pm:endOrErr>} and length $$src) {
736     valid_err qq<Broken parameter specification: "$$src">, node => $opt{node};
737     }
738     \%param;
739     } # dispm_parse_param
740    
741 wakaba 1.17 =item $result = perl_code_source ($code, %opt)
742    
743     Attaches the source file information to a Perl code fragment.
744    
745     Note that the same name function is defined in F<genlib.pl>
746     but redefined here for the purpose of this script.
747    
748     TODO: Non-debug purpose output should remove source information; otherwise
749     it is too verbose.
750    
751     =cut
752    
753 wakaba 1.3 sub perl_code_source ($%) {
754     my ($s, %opt) = @_;
755     my $npk = [qw/Name QName Label/];
756     my $f1 = sprintf q<File <%s> Node <%s> [Chunk #%d]>,
757     $opt{file} || $State->{Module}->{$opt{resource}->{parentModule}}->{FileName},
758     $opt{path} || ($opt{resource}->{src}
759     ? $opt{resource}->{src}->node_path (key => $npk)
760     : $opt{node} ? $opt{node}->node_path (key => $npk)
761     : 'x:unknown ()'),
762     ++($State->{ExpandedURI q<dis2pm:generatedChunk>} ||= 0);
763     my $f2 = sprintf q<Module <%s> [Chunk #%d]>,
764     $opt{file} || $State->{Module}->{$State->{module}}->{URI},
765     ++($State->{ExpandedURI q<dis2pm:generatedChunk>} ||= 0);
766     $f1 =~ s/"/\"/g; $f2 =~ s/"/\"/g;
767     sprintf qq<\n#line %d "%s"\n%s\n#line 1 "%s"\n>,
768     $opt{line} || 1, $f1, $s, $f2;
769 wakaba 1.17 } # perl_code_source
770 wakaba 1.3
771    
772    
773    
774     =item $code = dispm_get_code (resource => $res, %opt)
775    
776     Generates a Perl code fragment from resource(s).
777    
778     =cut
779    
780     sub dispm_get_code (%) {
781     my %opt = @_;
782 wakaba 1.7 if (($opt{ExpandedURI q<dis2pm:getCodeNoTypeCheck>} and
783     defined $opt{resource}->{Name}) or
784     ($opt{resource}->{ExpandedURI q<dis2pm:type>} and
785 wakaba 1.4 {
786     ExpandedURI q<ManakaiDOM:DOMMethodReturn> => 1,
787     ExpandedURI q<ManakaiDOM:DOMAttrGet> => 1,
788     ExpandedURI q<ManakaiDOM:DOMAttrSet> => 1,
789     }->{$opt{resource}->{ExpandedURI q<dis2pm:type>}}) or
790     (dis_resource_ctype_match ([ExpandedURI q<dis2pm:InlineCode>,
791     ExpandedURI q<dis2pm:BlockCode>],
792     $opt{resource}, %opt,
793     node => $opt{resource}->{src}))) {
794 wakaba 1.10 local $State->{Namespace}
795     = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding}
796     if defined $opt{resource}->{Name};
797 wakaba 1.4 my $key = $opt{ExpandedURI q<dis2pm:DefKeyName>} || ExpandedURI q<d:Def>;
798 wakaba 1.9
799 wakaba 1.4 my $n = dis_get_attr_node (%opt, parent => $opt{resource}->{src},
800     name => {uri => $key},
801 wakaba 1.10 ContentType => ExpandedURI q<d:Perl>) ||
802     dis_get_attr_node (%opt, parent => $opt{resource}->{src},
803     name => {uri => $key},
804     ContentType => ExpandedURI q<lang:dis>);
805 wakaba 1.9 if ($n) {
806     return disperl_to_perl (%opt, node => $n);
807     }
808    
809     $n = dis_get_attr_node (%opt, parent => $opt{resource}->{src},
810     name => {uri => $key},
811 wakaba 1.4 ContentType => ExpandedURI q<lang:Perl>);
812     if ($n) {
813 wakaba 1.6 my $code = '';
814     for (@{dis_get_elements_nodes (%opt, parent => $n,
815     name => 'require')}) {
816     $code .= perl_statement 'require ' . $_->value;
817     }
818 wakaba 1.11 my $v = $n->value;
819     valid_err q<Perl code is required>, node => $n unless defined $v;
820     $code .= perl_code ($v, %opt, node => $n);
821 wakaba 1.4 if ($opt{is_inline} and
822     dis_resource_ctype_match ([ExpandedURI q<dis2pm:InlineCode>],
823     $opt{resource}, %opt,
824     node => $opt{resource}->{src})) {
825     $code =~ s/\n/\x20/g;
826     return $code;
827     } else {
828     return perl_code_source ($code, %opt, node => $n);
829     }
830     }
831     return undef;
832     } else {
833     impl_err ("Bad resource for dispm_get_code: ".
834     $opt{resource}->{ExpandedURI q<dis2pm:type>},
835     node => $opt{resource}->{src});
836 wakaba 1.3 }
837     } # dispm_get_code
838    
839     =item $code = dispm_get_value (%opt)
840    
841     Gets value property and returns it as a Perl code fragment.
842    
843     =cut
844    
845     sub dispm_get_value (%) {
846     my %opt = @_;
847 wakaba 1.16 my $key = $opt{ExpandedURI q<dis2pm:ValueKeyName>} || ExpandedURI q<d:Value>;
848 wakaba 1.3 my $vt = $opt{ExpandedURI q<dis2pm:valueType>} || ExpandedURI q<DOMMain:any>;
849 wakaba 1.10 local $State->{Namespace}
850     = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding}
851     if defined $opt{resource}->{Name};
852 wakaba 1.16 local $opt{For} = [keys %{$opt{resource}->{For}}]->[0]
853     if defined $opt{resource}->{Name};
854     local $opt{'For+'} = [keys %{$opt{resource}->{'For+'}||{}}]
855     if defined $opt{resource}->{Name};
856 wakaba 1.10 my $n = $opt{node} ? [$opt{node}]
857     : dis_get_elements_nodes
858     (%opt, parent => $opt{resource}->{src},
859 wakaba 1.3 name => {uri => $key});
860     for my $n (@$n) {
861     my $t = dis_get_attr_node (%opt, parent => $n, name => 'ContentType');
862     my $type;
863     if ($t) {
864     $type = dis_qname_to_uri ($t->value, %opt, node => $t);
865 wakaba 1.17 } elsif ($opt{resource}->{ExpandedURI q<d:actualType>}) {
866     $type = $opt{resource}->{ExpandedURI q<d:actualType>};
867 wakaba 1.3 } else {
868 wakaba 1.5 $type = ExpandedURI q<lang:dis>;
869 wakaba 1.3 }
870     valid_err (qq<Type <$type> is not defined>, node => $t || $n)
871     unless defined $State->{Type}->{$type}->{Name};
872    
873     if (dis_uri_ctype_match (ExpandedURI q<lang:Perl>, $type, %opt)) {
874 wakaba 1.16 return perl_code ($n->value, %opt, node => $n);
875     } elsif (dis_uri_ctype_match (ExpandedURI q<DISCore:String>, $type, %opt) or
876     dis_uri_ctype_match (ExpandedURI q<DOMMain:DOMString>, $type, %opt)) {
877     return perl_literal $n->value;
878     } elsif (dis_uri_ctype_match (ExpandedURI q<DOMMain:unsigned-short>, $type, %opt) or
879     dis_uri_ctype_match (ExpandedURI q<DOMMain:unsigned-long>, $type, %opt) or
880     dis_uri_ctype_match (ExpandedURI q<DOMMain:short>, $type, %opt) or
881     dis_uri_ctype_match (ExpandedURI q<DOMMain:long>, $type, %opt)) {
882 wakaba 1.3 return $n->value;
883 wakaba 1.17 } elsif (dis_uri_ctype_match (ExpandedURI q<DOMMain:boolean>, $type, %opt)) {
884     return ($n->value and ($n->value eq 'true' or $n->value eq '1')) ? 1 : 0;
885     } elsif (dis_uri_ctype_match (ExpandedURI q<d:Boolean>, $type, %opt)) {
886     return $n->value ? 1 : 0;
887 wakaba 1.16 } elsif (dis_uri_ctype_match (ExpandedURI q<lang:dis>, $type, %opt)) {
888 wakaba 1.10 return perl_literal $n->value;
889 wakaba 1.5 }
890 wakaba 1.3 }
891    
892     ## No explicit value specified
893     if ($opt{ExpandedURI q<dis2pm:useDefaultValue>}) {
894     if (dis_uri_ctype_match (ExpandedURI q<DOMMain:DOMString>, $vt, %opt)) {
895     return q<"">;
896 wakaba 1.17 } elsif (dis_uri_ctype_match (ExpandedURI q<DOMMain:unsigned-short>, $vt, %opt) or
897     dis_uri_ctype_match (ExpandedURI q<DOMMain:unsigned-long>, $vt, %opt) or
898     dis_uri_ctype_match (ExpandedURI q<DOMMain:short>, $vt, %opt) or
899     dis_uri_ctype_match (ExpandedURI q<DOMMain:long>, $vt, %opt) or
900     dis_uri_ctype_match (ExpandedURI q<DOMMain:boolean>, $vt, %opt)) {
901     return q<0>;
902     } elsif (dis_uri_ctype_match (ExpandedURI q<Perl:ARRAY>, $vt, %opt)) {
903     return q<[]>;
904     } elsif (dis_uri_ctype_match (ExpandedURI q<Perl:hash>, $vt, %opt)) {
905     return q<{}>;
906 wakaba 1.3 }
907     }
908     return undef;
909     } # dispm_get_value
910    
911    
912 wakaba 1.5
913     =item $code = dispm_const_value (resource => $const, %opt)
914    
915 wakaba 1.10 Returns a code fragment corresponding to the vaue of C<$const>.
916 wakaba 1.5
917     =cut
918    
919     sub dispm_const_value (%) {
920 wakaba 1.16 my %opt = @_;
921 wakaba 1.5 my $for = [keys %{$opt{resource}->{For}}]->[0];
922 wakaba 1.14 local $opt{'For+'} = [keys %{$opt{resource}->{'For+'}||{}}];
923 wakaba 1.5 my $value = dispm_get_value
924     (%opt,
925     ExpandedURI q<dis2pm:ValueKeyName>
926     => ExpandedURI q<d:Value>,
927     ExpandedURI q<dis2pm:valueType>
928     => $opt{resource}
929     ->{ExpandedURI q<dis2pm:actualType>},
930     For => $for);
931     valid_err q<Constant value must be specified>, node => $opt{resource}->{src}
932     unless defined $value;
933 wakaba 1.10 return $value;
934     } # dispm_const_value
935    
936     =item $code = dispm_const_value_sub (resource => $const, %opt)
937    
938     Returns a code fragment to declare and define a constant function
939     corresponding to the definition of C<$const>.
940    
941     =cut
942    
943     sub dispm_const_value_sub (%) {
944     my %opt = @_;
945     my $value = dispm_const_value (%opt);
946 wakaba 1.16 my $name = $opt{resource}->{ExpandedURI q<dis2pm:constName>};
947     my $pc = $State->{ExpandedURI q<dis2pm:Package>}
948     ->{$State->{Module}->{$State->{module}}
949     ->{ExpandedURI q<dis2pm:packageName>}}
950     ->{ExpandedURI q<dis2pm:const>} ||= {};
951     valid_err qq<Constant value "$name" is already defined in the same module>,
952     node => $opt{resource}->{src} if defined $pc->{$name}->{resource}->{Name};
953     $pc->{$name} = {
954     name => $name, resource => $opt{resource},
955     package => $State->{ExpandedURI q<dis2pm:currentPackage>},
956     };
957 wakaba 1.5 return perl_sub
958 wakaba 1.16 (name => $name,
959 wakaba 1.5 prototype => '',
960     code => $value);
961 wakaba 1.10 } # dispm_const_value_sub
962 wakaba 1.5
963     =item $code = dispm_const_group (resource => $const_group, %opt)
964    
965     Returns a code fragment to define a constant value group.
966    
967     =cut
968    
969     sub dispm_const_group (%) {
970     my %opt = @_;
971     my $name = $opt{resource}->{ExpandedURI q<dis2pm:constGroupName>};
972     for my $cg (values %{$opt{resource}->{ExpandedURI q<dis2pm:constGroup>}}) {
973     if (defined $cg->{ExpandedURI q<dis2pm:constGroupName>}) {
974     valid_err (qq{"$name"."$cg->{ExpandedURI q<dis2pm:constGroupName>}": }.
975     qq{Nesting constant group not supported},
976     node => $cg->{src});
977     }
978     }
979 wakaba 1.16
980 wakaba 1.5 my $result = '';
981     my @cname;
982     if (length $name) {
983     if (defined $opt{ExpandedURI q<dis2pm:constGroupParentPackage>}->{$name}) {
984     valid_err qq<Const group "$name" is already defined>,
985     node => $opt{resource}->{src};
986     }
987     $opt{ExpandedURI q<dis2pm:constGroupParentPackage>}->{$name} = \@cname;
988     }
989 wakaba 1.16
990     my $pc = $State->{ExpandedURI q<dis2pm:Package>}
991     ->{$State->{Module}->{$State->{module}}
992     ->{ExpandedURI q<dis2pm:packageName>}}
993     ->{ExpandedURI q<dis2pm:constGroup>} ||= {};
994     valid_err qq<Constant group "$name" is already defined in the same module>,
995     node => $opt{resource}->{src} if defined $pc->{$name}->{resource}->{Name};
996     $pc->{$name} = {
997     name => $name, resource => $opt{resource},
998     member => \@cname,
999     };
1000    
1001 wakaba 1.5 for my $cv (values %{$opt{resource}->{ExpandedURI q<dis2pm:const>}}) {
1002     next unless defined $cv->{ExpandedURI q<dis2pm:constName>};
1003 wakaba 1.11 #$result .= dispm_const_value_sub (%opt, resource => $cv);
1004 wakaba 1.5 push @cname, $cv->{ExpandedURI q<dis2pm:constName>};
1005     }
1006     return $result;
1007     } # dispm_const_group
1008 wakaba 1.9
1009 wakaba 1.17 =item $desc = dispm_muf_description (%opt, resource => $res)
1010    
1011     Gets a <IF::Message::Util::Formatter> template for a resource.
1012    
1013     =cut
1014    
1015     sub dispm_muf_description (%) {
1016     my %opt = @_;
1017     my $key = $opt{ExpandedURI q<dis2pm:DefKeyName>} || ExpandedURI q<d:Def>;
1018    
1019     local $State->{Namespace}
1020     = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding};
1021     local $opt{For} = [keys %{$opt{resource}->{For}}]->[0];
1022     local $opt{'For+'} = [keys %{$opt{resource}->{'For+'}||{}}];
1023    
1024     my $def = dis_get_attr_node (%opt, parent => $opt{resource}->{src},
1025     name => {uri => $key},
1026     ContentType => ExpandedURI q<lang:muf>);
1027     if ($def) {
1028     my $template = $def->value;
1029     $template =~ s/<Q::([^<>]+)>/dis_qname_to_uri ($1, %opt,
1030     node => $opt{resource}
1031     ->{src})/ge;
1032     $template =~ s/\s+/ /g;
1033     $template =~ s/^ //;
1034     $template =~ s/ $//;
1035     return $template;
1036     }
1037    
1038     $key = $opt{ExpandedURI q<dis2pm:DescriptionKeyName>} ||
1039     ExpandedURI q<d:Description>;
1040    
1041     my $template = '';
1042     for $def (@{dis_get_elements_nodes
1043     (%opt, parent => $opt{resource}->{src},
1044     name => {uri => $key},
1045     ContentType => ExpandedURI q<lang:disdoc>,
1046     defaultContentType => ExpandedURI q<lang:disdoc>)}) {
1047     $template .= disdoc2text ($def->value, %opt, node => $def);
1048     }
1049     $template =~ s/\s+/ /g;
1050     $template =~ s/^ //;
1051     $template =~ s/ $//;
1052     return $template;
1053     } # dispm_muf_description
1054    
1055 wakaba 1.9 =item $code = disperl_to_perl (node => $node, %opt)
1056    
1057     Converts a C<d:Perl> node to a Perl code fragment.
1058    
1059     =cut
1060    
1061     sub disperl_to_perl (%) {
1062     my %opt = @_;
1063     my $code = '';
1064     for (@{$opt{node}->child_nodes}) {
1065     next unless $_->node_type eq '#element';
1066     next unless dis_node_for_match ($_, $opt{For}, %opt);
1067     my $et = dis_element_type_to_uri ($_->local_name, %opt, node => $_);
1068 wakaba 1.10 if ($et eq ExpandedURI q<DISLang:constValue>) {
1069     my $cn = $_->value;
1070     if ($cn =~ /^((?>(?!\.)$RegQNameChar)*)\.($RegQNameChar+)$/o) {
1071     my ($cls, $constn) = ($1, $2);
1072     if (length $cls) {
1073     my $clsu = dis_typeforqnames_to_uri ($cls, %opt,
1074     use_default_namespace => 1,
1075     node => $_);
1076     $cls = $State->{Type}->{$clsu};
1077     valid_err qq<Class/IF <$clsu> must be defined>, node => $_
1078     unless defined $cls->{Name};
1079     } else {
1080     $cls = $State->{ExpandedURI q<dis2pm:thisClass>};
1081     valid_err q<Class/IF name required in this context>, node => $_
1082     unless defined $cls->{Name};
1083     }
1084    
1085     my $const = $cls->{ExpandedURI q<dis2pm:const>}->{$constn};
1086     valid_err qq<Constant value "$constn" not defined in class/IF >.
1087     qq{"$cls->{Name}" (<$cls->{URI}>)}, node => $_
1088     unless defined $const->{Name};
1089     $code .= perl_statement
1090     perl_assign
1091     perl_var (type => '$', local_name => 'r')
1092     => dispm_const_value (resource => $const);
1093     } else {
1094     valid_err q<Syntax error>, node => $_;
1095     }
1096     } elsif ($et eq ExpandedURI q<DISLang:value>) {
1097     my $v = dispm_get_value (%opt, node => $_);
1098     $code .= perl_statement
1099     perl_assign
1100     perl_var (type => '$', local_name => 'r') => $v;
1101     } elsif ($et eq ExpandedURI q<d:GetProp> or
1102     $et eq ExpandedURI q<d:GetPropNode>) {
1103     my $uri = dis_qname_to_uri ($_->value, %opt, node => $_,
1104     use_default_namespace => 1);
1105     $code .= perl_statement
1106     perl_assign
1107     perl_var (type => '$', local_name => 'r')
1108     => '$self->{'.(ExpandedURI q<TreeCore:node>).
1109     '}->{'.(perl_literal $uri).'}';
1110     if ($et eq ExpandedURI q<d:GetPropNode>) {
1111     $code .= perl_if
1112     'defined $r',
1113 wakaba 1.17 perl_code (q{$r = <ClassM::DOMCore:ManakaiDOMNode
1114 wakaba 1.16 .getNodeReference> ($r)},
1115 wakaba 1.10 %opt, node => $_);
1116     }
1117 wakaba 1.11 } elsif ($et eq ExpandedURI q<d:SetProp>) {
1118     my $uri = dis_qname_to_uri ($_->value, %opt, node => $_,
1119     use_default_namespace => 1);
1120     my $chk = dis_get_attr_node (%opt, parent => $_, name => 'CheckReadOnly');
1121     if ($chk and $chk->value) {
1122     my $for1 = $opt{For} || ExpandedURI q<ManakaiDOM:all>;
1123     unless (dis_uri_for_match (ExpandedURI q<ManakaiDOM:ManakaiDOM1>,
1124     $for1, node => $_)) {
1125     $for1 = ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>;
1126     }
1127     $code .= perl_if
1128     q[$self->{].(perl_literal ExpandedURI q<TreeCore:node>).
1129     q[}->{].(perl_literal ExpandedURI q<DOMCore:read-only>).
1130     q[}],
1131     perl_statement
1132     dispm_perl_throws
1133     (%opt, class_for => $for1,
1134     class => ExpandedURI q<DOMCore:ManakaiDOMException>,
1135     type => 'NO_MODIFICATION_ALLOWED_ERR',
1136     subtype => ExpandedURI q<MDOMX:NOMOD_THIS>);
1137     }
1138     $code .= perl_statement
1139     perl_assign
1140     '$self->{'.(ExpandedURI q<TreeCore:node>).
1141     '}->{'.(perl_literal $uri).'}'
1142     => perl_var (type => '$', local_name => 'given');
1143     } elsif ($et eq ExpandedURI q<DISPerl:cloneCode>) {
1144     my $memref = $_->value;
1145     my $mem = dispm_memref_to_resource
1146     ($memref, %opt, node => $_,
1147 wakaba 1.14 return_method_returner => 1,
1148 wakaba 1.11 use_default_type_resource =>
1149     $State->{ExpandedURI q<dis2pm:thisClass>},
1150     ## ISSUE: Reference in a resource that is
1151     ## referred from another resource might
1152     ## not be interpreted correctly.
1153     );
1154     ## ISSUE: It might be required to detect a loop
1155     $code .= dispm_get_code (%opt, resource => $mem,
1156     For => [keys %{$mem->{For}}]->[0],
1157 wakaba 1.14 'For+' => [keys %{$mem->{'For+'}||{}}],
1158 wakaba 1.11 ExpandedURI q<dis2pm:DefKeyName>
1159     => ExpandedURI q<d:Def>);
1160 wakaba 1.17 } elsif ($et eq ExpandedURI q<DOMMain:raiseException>) {
1161     my ($cls, $type, $subtype) = dispm_xcref_to_resources
1162     ($_->value, %opt, node => $_);
1163     ## TODO: Parameter
1164     my %xparam;
1165    
1166     for (
1167     ExpandedURI q<MDOMX:class>,
1168     ExpandedURI q<MDOMX:method>,
1169     ExpandedURI q<MDOMX:attr>,
1170     ExpandedURI q<MDOMX:on>,
1171     ) {
1172     $xparam{$_} = $opt{$_} if defined $opt{$_};
1173     }
1174    
1175     $code .= perl_statement dispm_perl_throws
1176     (%opt,
1177     class_resource => $cls,
1178     type_resource => $type,
1179     subtype_resource => $subtype,
1180     xparam => \%xparam);
1181 wakaba 1.10 } elsif ($et eq ExpandedURI q<DISPerl:selectByProp>) {
1182 wakaba 1.11 my $cprop = dis_get_attr_node
1183 wakaba 1.9 (%opt, parent => $_,
1184     name => {uri => ExpandedURI q<DISPerl:propName>});
1185 wakaba 1.11 my $propvalue;
1186     if ($cprop) {
1187     my $cpropuri = dis_qname_to_uri ($cprop->value,
1188     use_default_namespace => 1,
1189     %opt, node => $cprop);
1190     my $prop;
1191     if ($opt{ExpandedURI q<dis2pm:selParent>}) {
1192     if (ref $opt{ExpandedURI q<dis2pm:selParent>} eq 'HASH') {
1193     $prop = $opt{ExpandedURI q<dis2pm:selParent>};
1194     if (defined $prop->{$cpropuri}) {
1195     $propvalue = $prop->{$cpropuri};
1196     } else {
1197     $propvalue = '';
1198     }
1199     } else {
1200 wakaba 1.9 $prop = dis_get_attr_node
1201 wakaba 1.11 (%opt, parent => $opt{ExpandedURI q<dis2pm:selParent>},
1202     name => {uri => $cpropuri});
1203     if ($prop) {
1204     $propvalue = $prop->value;
1205 wakaba 1.9 } else {
1206 wakaba 1.11 $propvalue = '';
1207 wakaba 1.9 }
1208     }
1209 wakaba 1.11 } else {
1210     valid_err q<Element "DISPerl:selectByProp" cannot be used here>,
1211     node => $_;
1212     }
1213     } else {
1214     valid_err q<Attribute "DISPerl:propName" required>,
1215     node => $_;
1216     }
1217     my $selcase;
1218     for my $case (@{$_->child_nodes}) {
1219     next unless $case->node_type eq '#element';
1220     next unless dis_node_for_match ($case, $opt{For}, %opt);
1221     my $et = dis_element_type_to_uri ($case->local_name,
1222     %opt, node => $case);
1223     if ($et eq ExpandedURI q<DISPerl:case>) {
1224     my $val = dis_get_attr_node
1225 wakaba 1.9 (%opt, parent => $case,
1226     name => 'Value',
1227     ContentType => ExpandedURI q<lang:dis>,
1228     defaultContentType => ExpandedURI q<lang:dis>);
1229 wakaba 1.11 if ($val and $val->value eq $propvalue) {
1230     $selcase = $case; last;
1231     } elsif ($propvalue eq '' and (not $val or not $val->value)) {
1232     $selcase = $case; last;
1233 wakaba 1.9 }
1234 wakaba 1.11 } elsif ($et eq ExpandedURI q<DISPerl:else>) {
1235     $selcase = $case; last;
1236     } elsif ({
1237     ExpandedURI q<DISPerl:propName> => 1,
1238     }->{$et}) {
1239     #
1240     } else {
1241     valid_err qq<Element type <$et> not allowed here>,
1242     node => $case;
1243     }
1244     }
1245 wakaba 1.9 if ($selcase) {
1246     my $lcode = perl_code ($selcase->value, %opt, node => $selcase);
1247 wakaba 1.11 if ($opt{is_inline}) {
1248     $code .= $lcode;
1249     } else {
1250     $code .= perl_code_source ($lcode, %opt, node => $selcase);
1251     }
1252 wakaba 1.9 }
1253     } elsif ({
1254     ExpandedURI q<d:ContentType> => 1,
1255     ExpandedURI q<d:For> => 1,
1256     ExpandedURI q<d:ForCheck> => 1,
1257     ExpandedURI q<d:ImplNote> => 1,
1258 wakaba 1.16 ExpandedURI q<DISLang:nop> => 1,
1259 wakaba 1.9 }->{$et}) {
1260     #
1261     } else {
1262     valid_err qq<Element type <$et> not supported>,
1263     node => $opt{node};
1264     }
1265     }
1266    
1267     my $val = $opt{node}->value;
1268 wakaba 1.10 if (defined $val and length $val) {
1269 wakaba 1.11 my $lcode = perl_code ($val, %opt);
1270     if ($opt{is_inline}) {
1271     $code .= $lcode;
1272     } else {
1273     $code .= perl_code_source ($lcode, %opt);
1274     }
1275 wakaba 1.9 }
1276     return $code;
1277     } # disperl_to_perl
1278 wakaba 1.5
1279 wakaba 1.11 =item $res = dispm_memref_to_resource ($memref, %opt)
1280    
1281     Converts a C<DISPerl:MemRef> (a reference to a class member,
1282     i.e. either method, attribute, attribute getter or attribute
1283     setter) to a resource.
1284    
1285     =cut
1286    
1287     sub dispm_memref_to_resource ($%) {
1288     my ($memref, %opt) = @_;
1289     my ($clsq, $memq) = split /\./, $memref, 2;
1290     unless (defined $memq) {
1291     valid_err qq<"$memref": Member name required>. node => $opt{node};
1292     } elsif ($memq =~ /:/) {
1293     valid_err qq<"$memref": Prefixed member name not supported>,
1294     node => $opt{node};
1295     }
1296    
1297     ## Class
1298     my $cls;
1299     my $clsuri;
1300     if ($clsq eq '') {
1301     if (defined $opt{use_default_type_resource}->{Name}) {
1302     $cls = $opt{use_default_type_resource};
1303     $clsuri = $cls->{URI};
1304     } elsif ($opt{use_default_type}) {
1305     $clsuri = $opt{use_default_type};
1306     } else {
1307     $clsuri = dis_typeforqnames_to_uri
1308     ($clsq, use_default_namespace => 1, %opt);
1309     }
1310     } else {
1311     $clsuri = dis_typeforqnames_to_uri
1312     ($clsq, use_default_namespace => 1, %opt);
1313     }
1314     unless ($cls) {
1315     $cls = $State->{Type}->{$clsuri};
1316     valid_err qq<Class <$clsuri> must be defined>, node => $opt{node}
1317     unless defined $cls->{Name};
1318     }
1319    
1320     ## Method or attribute
1321     my $memname = $memq;
1322     my $mem;
1323     for (values %{$cls->{ExpandedURI q<dis2pm:method>}||{}}) {
1324     if (defined $_->{Name} and $_->{Name} eq $memname) {
1325     $mem = $_;
1326     last;
1327     }
1328     }
1329     if ($mem) {
1330     if ($opt{return_method_returner}) {
1331     if (defined $mem->{ExpandedURI q<dis2pm:return>}->{Name}) {
1332     $mem = $mem->{ExpandedURI q<dis2pm:return>};
1333     } elsif (defined $mem->{ExpandedURI q<dis2pm:getter>}->{Name}) {
1334     $mem = $mem->{ExpandedURI q<dis2pm:getter>};
1335     } else {
1336     valid_err qq{Neither "return" nor "getter" is defined for }.
1337     qq{the class "$cls->{Name}" <$cls->{URI}>},
1338     node => $opt{node};
1339     }
1340     }
1341     } elsif ($memname =~ s/^([gs]et)(?=.)//) {
1342     my $gs = $1;
1343     $memname = lcfirst $memname;
1344     my $memp;
1345     for (values %{$cls->{ExpandedURI q<dis2pm:method>}||{}}) {
1346     if (defined $_->{Name} and $_->{Name} eq $memname) {
1347     $memp = $_;
1348     last;
1349     }
1350     }
1351     if ($memp) {
1352     if ($gs eq 'set') {
1353     $mem = $memp->{ExpandedURI q<dis2pm:setter>};
1354     unless (defined $mem->{Name}) {
1355     valid_err qq{Setter for "$memp->{Name}" <$memp->{URI}> is not defined},
1356     node => $opt{node};
1357     }
1358     } else {
1359     $mem = $memp->{ExpandedURI q<dis2pm:getter>};
1360     unless (defined $mem->{Name}) {
1361     valid_err qq{Getter for "$memp->{Name}" <$memp->{URI}> is not defined},
1362     node => $opt{node};
1363     }
1364     }
1365     }
1366     }
1367     valid_err qq<Member "$memq" for class <$clsuri> is not defined>,
1368     node => $opt{node} unless defined $mem->{Name};
1369     return $mem;
1370     } # dispm_memref_to_resource
1371    
1372 wakaba 1.17 =item ($clsres, $coderef, $subcoderef) = dispm_xcref_to_resources ($xcref, %opt)
1373    
1374     Converts a "DOMMain:XCodeRef" (exception or warning code reference)
1375     to its "resource" objects.
1376    
1377     =over 4
1378    
1379     =item $clsres
1380    
1381     The resource object for the exception or warning class or interface identified
1382     by the XCodeRef.
1383    
1384     =item $coderef
1385    
1386     The resource object for the exception or warning code identified
1387     by the XCodeRef.
1388    
1389     =item $subcoderef
1390    
1391     The resource object for the exception or warning code idnetified by
1392     the XCodeRef, if any. If the XCodeRef identifies no subtype resource,
1393     an C<undef> is returned as C<$subcodref>.
1394    
1395     =back
1396    
1397     =cut
1398    
1399     sub dispm_xcref_to_resources ($%) {
1400     my ($xcref, %opt) = @_;
1401     my $q;
1402     my $constq;
1403     my $subtypeq;
1404     if (ref $xcref) {
1405     ($q, $constq, $subtypeq) = @$xcref;
1406     } else {
1407     ($q, $constq, $subtypeq) = split /\./, $xcref, 3;
1408     }
1409     my $clsuri;
1410     my $cls;
1411     my $consturi;
1412     my $const;
1413     my $subtypeuri;
1414     my $subtype;
1415     if (defined $constq and not defined $subtypeq) {
1416     $clsuri = dis_typeforqnames_to_uri ($q,
1417     use_default_namespace => 1,
1418     %opt);
1419     $cls = $State->{Type}->{$clsuri};
1420     valid_err qq{Exception/warning class definition for }.
1421     qq{<$clsuri> is required}, node => $opt{node}
1422     unless defined $cls->{Name};
1423     my ($consttq, $constfq) = split /\|\|/, $constq, 2;
1424     if (defined $constfq) {
1425     if ($consttq !~ /:/) {
1426     valid_err qq<"$constq": Unprefixed exception code QName must >.
1427     q<not be followed by a "For" QName>,
1428     node => $opt{node};
1429     } else {
1430     $consturi = dis_typeforqnames_to_uri ($consttq.'::'.$constfq,
1431     use_default_namespace => 1,
1432     %opt);
1433     }
1434     } else {
1435     if ($consttq !~ /:/) {
1436     $consturi = $consttq;
1437     CONSTCLS: {
1438     for (values %{$cls->{ExpandedURI q<dis2pm:xConst>}}) {
1439     if (defined $_->{Name} and $_->{Name} eq $consturi) {
1440     $const = $_;
1441     last CONSTCLS;
1442     }
1443     }
1444     valid_err qq{Exception/warning code "$consturi" must be }.
1445     qq{defined in the exception/warning class }.
1446     qq{<$clsuri>}, node => $opt{node};
1447     }
1448     } else {
1449     $consturi = dis_typeforqnames_to_uri ($consttq.'::'.$constfq,
1450     use_default_namespace => 1,
1451     %opt);
1452     }
1453     }
1454     unless ($const) {
1455     CONSTCLS: {
1456     for (values %{$cls->{ExpandedURI q<dis2pm:xConst>}}) {
1457     if (defined $_->{Name} and $_->{URI} and
1458     $_->{URI} eq $consturi) {
1459     $const = $_;
1460     last CONSTCLS;
1461     }
1462     }
1463     valid_err qq{Exception/warning code <$consturi> must be }.
1464     qq{defined in the exception/warning class }.
1465     qq{<$clsuri>}, node => $opt{node};
1466     }
1467     }
1468     } else { ## By code/subtype QName
1469     $subtypeq = $q unless defined $constq;
1470     $subtypeuri = dis_typeforqnames_to_uri ($subtypeq,
1471     use_default_namespace => 1,
1472     %opt);
1473     $subtype = $State->{Type}->{$subtypeuri};
1474     valid_err qq{Exception/warning code/subtype <$subtypeuri> must }.
1475     qq{be defined}, node => $opt{node}
1476     unless defined $subtype->{Name} and
1477     defined $subtype->{ExpandedURI q<dis2pm:type>};
1478     if ($subtype->{ExpandedURI q<dis2pm:type>} eq
1479     ExpandedURI q<ManakaiDOM:ExceptionOrWarningSubType>) {
1480     $const = $subtype->{ExpandedURI q<dis2pm:parentResource>};
1481     $cls = $subtype->{ExpandedURI q<dis2pm:grandGrandParentResource>};
1482     } elsif ($subtype->{ExpandedURI q<dis2pm:type>} eq
1483     ExpandedURI q<ManakaiDOM:Const>) {
1484     $const = $subtype;
1485     $subtype = undef;
1486     $cls = $const->{ExpandedURI q<dis2pm:grandParentResource>};
1487     } else {
1488     valid_err qq{Type of <$subtypeuri> must be either }.
1489     q{"ManakaiDOM:Const" or }.
1490     q{"ManakaiDOM:ExceptionOrWarningSubType"},
1491     node => $opt{node};
1492     }
1493     }
1494     return ($cls, $const, $subtype);
1495     } # dispm_xcref_to_resources
1496    
1497 wakaba 1.12 =item $hash = dispm_collect_hash_prop_value ($resource, $propuri, %opt)
1498    
1499     Get property values from a resource and its superclasses
1500     (C<dis:ISA>s - C<dis:Implement>s are not checked).
1501    
1502     =cut
1503    
1504     ## TODO: Loop test might be required
1505     sub dispm_collect_hash_prop_value ($$%) {
1506     my ($res, $propu, %opt) = @_;
1507     my %r;
1508     for (@{$res->{ISA}||[]}) {
1509     %r = (%{dispm_collect_hash_prop_value ($State->{Type}->{$_}, $propu, %opt)},
1510     %r);
1511     }
1512     %r = (%r, %{$res->{$propu}||{}});
1513     \%r;
1514     } # dispm_collect_hash_prop_value
1515 wakaba 1.5
1516 wakaba 1.17 =back
1517    
1518     =cut
1519    
1520 wakaba 1.1 ## Outputed module and "For"
1521     my $mf = dis_get_module_uri (module_name => $Opt{module_name},
1522     module_uri => $Opt{module_uri},
1523     For => $Opt{For});
1524     $State->{DefaultFor} = $mf->{For};
1525     $State->{module} = $mf->{module};
1526 wakaba 1.11 our $result = '';
1527 wakaba 1.1
1528 wakaba 1.3 valid_err
1529     (qq{Perl module <$State->{module}> not defined for <$State->{DefaultFor}>},
1530     node => $State->{Module}->{$State->{module}}->{src})
1531     unless $State->{Module}->{$State->{module}}
1532     ->{ExpandedURI q<dis2pm:packageName>};
1533    
1534 wakaba 1.1 $State->{ExpandedURI q<dis2pm:currentPackage>} = 'main';
1535 wakaba 1.11 my $header = "#!/usr/bin/perl \n";
1536     $header .= perl_comment q<This file is automatically generated from> . "\n" .
1537 wakaba 1.1 q<"> . $Opt{file_name} . q<" at > .
1538     rfc3339_date (time) . qq<.\n> .
1539     q<Don't edit by hand!>;
1540 wakaba 1.11 $header .= perl_comment qq{Module <$State->{module}>};
1541     $header .= perl_comment qq{For <$State->{DefaultFor}>};
1542     $header .= perl_statement q<use strict>;
1543     $header .= perl_change_package
1544 wakaba 1.1 (full_name => $State->{Module}->{$State->{module}}
1545     ->{ExpandedURI q<dis2pm:packageName>});
1546 wakaba 1.11 $header .= perl_statement
1547 wakaba 1.1 perl_assign
1548     perl_var (type => '$', local_name => 'VERSION',
1549     scope => 'our')
1550 wakaba 1.17 => perl_literal version_date time
1551     if $Opt{outputModuleVersion};
1552 wakaba 1.1
1553 wakaba 1.5 ## -- Classes
1554 wakaba 1.8 my %opt;
1555 wakaba 1.1 for my $pack (values %{$State->{Module}->{$State->{module}}
1556     ->{ExpandedURI q<dis2pm:package>}||{}}) {
1557     next unless defined $pack->{Name};
1558     if ({
1559     ExpandedURI q<ManakaiDOM:Class> => 1,
1560     ExpandedURI q<ManakaiDOM:IF> => 1,
1561     ExpandedURI q<ManakaiDOM:ExceptionClass> => 1,
1562     ExpandedURI q<ManakaiDOM:ExceptionIF> => 1,
1563 wakaba 1.5 ExpandedURI q<ManakaiDOM:WarningClass> => 1,
1564 wakaba 1.1 }->{$pack->{ExpandedURI q<dis2pm:type>}}) {
1565     ## Package name and version
1566     $result .= perl_change_package
1567     (full_name => $pack->{ExpandedURI q<dis2pm:packageName>});
1568     $result .= perl_statement
1569     perl_assign
1570     perl_var (type => '$', local_name => 'VERSION',
1571     scope => 'our')
1572     => perl_literal version_date time;
1573     ## Inheritance
1574 wakaba 1.5 ## TODO: IF "isa" should be expanded
1575 wakaba 1.12 my $isa = $pack->{ExpandedURI q<dis2pm:AppISA>} || [];
1576     for (@$isa) {
1577     $State->{Module}->{$State->{module}}
1578     ->{ExpandedURI q<dis2pm:requiredModule>}->{$_} ||= 1;
1579     }
1580 wakaba 1.17 for my $uri (@{$pack->{ISA}||[]},
1581     @{$pack->{Implement}||[]}) {
1582 wakaba 1.1 my $pack = $State->{Type}->{$uri};
1583     if (defined $pack->{ExpandedURI q<dis2pm:packageName>}) {
1584 wakaba 1.2 push @$isa, $pack->{ExpandedURI q<dis2pm:packageName>};
1585 wakaba 1.1 } else {
1586     impl_msg ("Inheriting package name for <$uri> not defined",
1587     node => $pack->{src}) if $Opt{verbose};
1588     }
1589     }
1590 wakaba 1.2 $isa = array_uniq $isa;
1591     $result .= perl_inherit $isa;
1592 wakaba 1.11 $State->{ExpandedURI q<dis2pm:referredPackage>}->{$_} ||= $pack->{src} || 1
1593     for @$isa;
1594 wakaba 1.12
1595     ## Role
1596     my $role = dispm_collect_hash_prop_value
1597     ($pack, ExpandedURI q<d:Role>, %opt);
1598     my $feature;
1599     for (values %$role) {
1600     my $roleres = $State->{Type}->{$_->{Role}};
1601     my $compatres;
1602     $compatres = $State->{Type}->{$_->{compat}} if defined $_->{compat};
1603     valid_err qq{Perl package name for interface <$_->{Role}> must be defined},
1604     node => $roleres->{src}
1605     unless defined $roleres->{ExpandedURI q<dis2pm:packageName>};
1606     valid_err qq{Perl package name for class <$_->{compat}> must be defined},
1607     node => $compatres->{src}
1608     if $compatres and
1609     not defined $compatres->{ExpandedURI q<dis2pm:packageName>};
1610     if ({
1611     dis_typeforuris_to_uri
1612     (ExpandedURI q<DOMCore:DOMImplementation>,
1613     ExpandedURI q<ManakaiDOM:ManakaiDOM>, %opt) => 1,
1614    
1615     dis_typeforuris_to_uri
1616     (ExpandedURI q<DOMCore:ManakaiDOMNode>,
1617     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1618     dis_typeforuris_to_uri
1619     (ExpandedURI q<DOMCore:ManakaiDOMAttr>,
1620     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1621     dis_typeforuris_to_uri
1622     (ExpandedURI q<DOMXML:ManakaiDOMCDATASection>,
1623     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1624     dis_typeforuris_to_uri
1625     (ExpandedURI q<DOMCore:ManakaiDOMComment>,
1626     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1627     dis_typeforuris_to_uri
1628     (ExpandedURI q<DOMCore:ManakaiDOMDocument>,
1629     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1630     dis_typeforuris_to_uri
1631     (ExpandedURI q<DOMCore:ManakaiDOMDocumentFragment>,
1632     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1633     dis_typeforuris_to_uri
1634     (ExpandedURI q<DOMXML:ManakaiDOMDocumentType>,
1635     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1636     dis_typeforuris_to_uri
1637     (ExpandedURI q<DOMCore:ManakaiDOMElement>,
1638     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1639     dis_typeforuris_to_uri
1640     (ExpandedURI q<DOMXML:ManakaiDOMEntity>,
1641     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1642     dis_typeforuris_to_uri
1643     (ExpandedURI q<DOMXML:ManakaiDOMEntityReference>,
1644     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1645     dis_typeforuris_to_uri
1646     (ExpandedURI q<DOMXML:ManakaiDOMNotation>,
1647     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1648     dis_typeforuris_to_uri
1649     (ExpandedURI q<DOMXML:ManakaiDOMProcessingInstruction>,
1650     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1651     dis_typeforuris_to_uri
1652     (ExpandedURI q<DOMCore:ManakaiDOMText>,
1653     ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt) => 1,
1654 wakaba 1.15
1655 wakaba 1.16 (my $ev = dis_typeforuris_to_uri
1656 wakaba 1.15 (ExpandedURI q<DOMEvents:ManakaiDOMEvent>,
1657 wakaba 1.16 ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>, %opt)) => 1,
1658 wakaba 1.12 }->{$_->{Role}}) {
1659     unless ($feature) {
1660     $feature = {};
1661     for (keys %{dispm_collect_hash_prop_value
1662     ($pack, ExpandedURI q<DOMMain:implementFeature>, %opt)}) {
1663 wakaba 1.16 my @f = ([$State->{Type}->{$_}, [], 1]);
1664 wakaba 1.13 while (defined (my $f = shift @f)) {
1665     my $version = $f->[0]->{ExpandedURI q<d:Version>};
1666     $version = '' unless defined $version;
1667 wakaba 1.16 $f->[0]->{ExpandedURI q<dis2pm:notImplemented>}
1668 wakaba 1.13 = length $version
1669     ? $f->[0]->{ExpandedURI q<dis2pm:notImplemented>}
1670 wakaba 1.16 ? 1 : 0
1671     : 0;
1672     for my $fname (keys %{$f->[0]
1673     ->{ExpandedURI q<dis2pm:featureName>}}) {
1674     $feature->{$fname}->{$version}
1675     = $f->[0]->{ExpandedURI q<dis2pm:notImplemented>} ? 0 : 1
1676     if $f->[2];
1677     unless ($feature->{$fname}->{$version}) {
1678     $feature->{$_->[0]}->{$_->[1]} = 0 for @{$f->[1]};
1679 wakaba 1.13 }
1680     }
1681     push @f,
1682     map {[$State->{Type}->{$_},
1683 wakaba 1.16 ($f->[2]
1684     ? [@{$f->[1]},
1685     map {[$_, $version]}
1686     keys %{$f->[0]
1687     ->{ExpandedURI q<dis2pm:featureName>}}]
1688     : $f->[1]),
1689     $f->[2]]}
1690 wakaba 1.13 @{$f->[0]->{ISA}||[]};
1691 wakaba 1.16 push @f,
1692     map {[$State->{Type}->{$_},
1693     ($f->[2]
1694     ? [@{$f->[1]},
1695     map {[$_, $version]}
1696     keys %{$f->[0]
1697     ->{ExpandedURI q<dis2pm:featureName>}}]
1698     : $f->[1]), 0]}
1699     keys %{$f->[0]->{ExpandedURI q<dis2pm:requireFeature>}||{}}
1700     if not $f->[0]->{ExpandedURI q<dis2pm:notImplemented>};
1701 wakaba 1.12 }
1702     }
1703     }
1704     my %f = (
1705     packageName => $pack->{ExpandedURI q<dis2pm:packageName>},
1706     feature => $feature,
1707     );
1708 wakaba 1.16
1709     if ($_->{Role} eq $ev) {
1710     my @p = ($pack);
1711     my %pu;
1712     while (defined (my $p = shift @p)) {
1713     if ($p->{ExpandedURI q<dis2pm:type>} eq
1714     ExpandedURI q<ManakaiDOM:IF>) {
1715     $f{eventType}->{$p->{Name}} = 1;
1716     }
1717     $f{eventType}->{$_} = 1
1718     for keys %{$p->{ExpandedURI q<DOMEvents:createEventType>}||{}};
1719     $pu{defined $p->{URI} ? $p->{URI} : ''} = 1;
1720     push @p, grep {!$pu{defined $_->{URI} ? $_->{URI} : ''}}
1721     map {$State->{Type}->{$_}}
1722     (@{$p->{ISA}||[]}, @{$p->{Implement}||[]});
1723     }
1724     }
1725 wakaba 1.12
1726     $result .= perl_statement
1727     (($compatres
1728     ? perl_var (type => '$',
1729     package => $compatres
1730     ->{ExpandedURI q<dis2pm:packageName>},
1731     local_name => 'Class').
1732     '{'.(perl_literal ($f{packageName})).'} = '
1733     : '').
1734     perl_var (type => '$',
1735     package => $roleres
1736     ->{ExpandedURI q<dis2pm:packageName>},
1737     local_name => 'Class').
1738     '{'.(perl_literal ($f{packageName})).'} = '.
1739     perl_literal \%f);
1740     } elsif ({
1741     dis_typeforuris_to_uri
1742     (ExpandedURI q<DOMCore:DOMImplementationSource>,
1743     ExpandedURI q<ManakaiDOM:ManakaiDOM>, %opt) => 1,
1744     }->{$_->{Role}}) {
1745     $result .= perl_statement
1746     'push @org::w3c::dom::DOMImplementationSourceList, '.
1747     perl_literal ($pack->{ExpandedURI q<dis2pm:packageName>});
1748     } else {
1749     valid_err qq{Role <$_->{Role}> not supported}, $_->{node};
1750     }
1751     }
1752    
1753 wakaba 1.1 ## Members
1754     if ({
1755     ExpandedURI q<ManakaiDOM:Class> => 1,
1756     ExpandedURI q<ManakaiDOM:ExceptionClass> => 1,
1757     ExpandedURI q<ManakaiDOM:WarningClass> => 1,
1758     }->{$pack->{ExpandedURI q<dis2pm:type>}}) {
1759 wakaba 1.11 local $State->{ExpandedURI q<dis2pm:thisClass>} = $pack;
1760 wakaba 1.8 local $opt{ExpandedURI q<MDOMX:class>}
1761     = $pack->{ExpandedURI q<dis2pm:packageName>};
1762 wakaba 1.1 for my $method (values %{$pack->{ExpandedURI q<dis2pm:method>}}) {
1763     next unless defined $method->{Name};
1764     if ($method->{ExpandedURI q<dis2pm:type>} eq
1765     ExpandedURI q<ManakaiDOM:DOMMethod>) {
1766 wakaba 1.8 local $opt{ExpandedURI q<MDOMX:method>}
1767 wakaba 1.14 = $method->{ExpandedURI q<dis2pm:methodName+>};
1768 wakaba 1.11 local $opt{ExpandedURI q<dis2pm:currentMethodResource>} = $method;
1769 wakaba 1.3 my $proto = '$';
1770 wakaba 1.11 my @param = ('$self');
1771 wakaba 1.7 my $param_norm = '';
1772 wakaba 1.3 my $param_opt = 0;
1773 wakaba 1.7 my $for = [keys %{$method->{For}}]->[0];
1774 wakaba 1.14 local $opt{'For+'} = [keys %{$method->{'For+'}||{}}];
1775 wakaba 1.3 for my $param (@{$method->{ExpandedURI q<dis2pm:param>}||[]}) {
1776 wakaba 1.11 my $atype = $param->{ExpandedURI q<d:actualType>};
1777 wakaba 1.3 if ($param->{ExpandedURI q<dis2pm:nullable>}) {
1778     $proto .= ';' unless $param_opt;
1779     $param_opt++;
1780     }
1781 wakaba 1.12 if (dis_uri_ctype_match (ExpandedURI q<Perl:Array>, $atype, %opt)) {
1782 wakaba 1.11 $proto .= '@';
1783     push @param, '@'.$param->{ExpandedURI q<dis2pm:paramName>};
1784 wakaba 1.12 } elsif (dis_uri_ctype_match (ExpandedURI q<Perl:Hash>, $atype,
1785 wakaba 1.11 %opt)) {
1786     $proto .= '%';
1787     push @param, '%'.$param->{ExpandedURI q<dis2pm:paramName>};
1788     } else {
1789     $proto .= '$';
1790     push @param, '$'.$param->{ExpandedURI q<dis2pm:paramName>};
1791     }
1792     my $nin = dis_get_attr_node
1793     (%opt,
1794     parent =>
1795     $param->{ExpandedURI q<dis2pm:actualTypeNode>},
1796     name => {uri =>
1797     ExpandedURI q<ManakaiDOM:noInputNormalize>},
1798     );
1799     if ($nin and $nin->value) {
1800     ## No input normalizing
1801     } else {
1802     my $nm = dispm_get_code
1803     (%opt, resource => $State->{Type}->{$atype},
1804 wakaba 1.7 ExpandedURI q<dis2pm:DefKeyName>
1805     => ExpandedURI q<ManakaiDOM:inputNormalizer>,
1806     For => $for,
1807 wakaba 1.11 ExpandedURI q<dis2pm:getCodeNoTypeCheck> => 1,
1808     ExpandedURI q<dis2pm:selParent>
1809     => $param->{ExpandedURI q<dis2pm:actualTypeNode>});
1810     if (defined $nm) {
1811 wakaba 1.17 $nm =~ s/\$INPUT\b/$param[-1]/g;
1812 wakaba 1.12 ## NOTE: "Perl:Array" or "Perl:Hash" is not supported.
1813 wakaba 1.11 $param_norm .= $nm;
1814     }
1815 wakaba 1.7 }
1816 wakaba 1.3 }
1817     my $code = dispm_get_code
1818 wakaba 1.8 (%opt,
1819     resource => $method->{ExpandedURI q<dis2pm:return>},
1820 wakaba 1.11 For => $for,
1821     ExpandedURI q<dis2pm:DefKeyName>
1822     => ExpandedURI q<d:Def>);
1823 wakaba 1.3 if (defined $code) {
1824 wakaba 1.11 my $my = perl_statement ('my ('.join (", ", @param).
1825 wakaba 1.3 ') = @_');
1826     my $return = defined $method->{ExpandedURI q<dis2pm:return>}->{Name}
1827     ? $method->{ExpandedURI q<dis2pm:return>} : undef;
1828     if ($return->{ExpandedURI q<d:actualType>} ? 1 : 0) {
1829     my $default = dispm_get_value
1830 wakaba 1.8 (%opt, resource => $return,
1831 wakaba 1.3 ExpandedURI q<dis2pm:ValueKeyName>
1832     => ExpandedURI q<d:DefaultValue>,
1833     ExpandedURI q<dis2pm:useDefaultValue> => 1,
1834     ExpandedURI q<dis2pm:valueType>
1835     => $return->{ExpandedURI q<d:actualType>});
1836 wakaba 1.7 $code = $my . $param_norm .
1837 wakaba 1.3 perl_statement
1838     (defined $default ? 'my $r = '.$default : 'my $r').
1839     $code . "\n" .
1840     perl_statement ('$r');
1841     } else {
1842     $code = $my . $code;
1843     }
1844     } else { ## Code not defined
1845 wakaba 1.4 my $for1 = $for;
1846 wakaba 1.3 unless (dis_uri_for_match (ExpandedURI q<ManakaiDOM:ManakaiDOM1>,
1847     $for, node => $method->{src})) {
1848 wakaba 1.4 $for1 = ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>;
1849 wakaba 1.3 }
1850 wakaba 1.11 $code = perl_statement 'my $self = shift;';
1851     $code .= perl_statement
1852 wakaba 1.3 dispm_perl_throws
1853     class => ExpandedURI q<DOMCore:ManakaiDOMException>,
1854 wakaba 1.4 class_for => $for1,
1855 wakaba 1.3 type => 'NOT_SUPPORTED_ERR',
1856     subtype =>
1857     ExpandedURI q<MDOMX:MDOM_IMPL_METHOD_NOT_IMPLEMENTED>,
1858     xparam => {
1859     ExpandedURI q<MDOMX:class>
1860     => $pack->{ExpandedURI q<dis2pm:packageName>},
1861     ExpandedURI q<MDOMX:method>
1862 wakaba 1.14 => $method->{ExpandedURI q<dis2pm:methodName+>},
1863 wakaba 1.3 };
1864     }
1865 wakaba 1.14 if (length $method->{ExpandedURI q<dis2pm:methodName>}) {
1866     $result .= perl_sub
1867     (name => $method->{ExpandedURI q<dis2pm:methodName>},
1868     code => $code, prototype => $proto);
1869     } else {
1870     $method->{ExpandedURI q<dis2pm:methodCodeRef>}
1871     = perl_sub (name => '', code => $code, prototype => $proto);
1872     }
1873 wakaba 1.1 } elsif ($method->{ExpandedURI q<dis2pm:type>} eq
1874     ExpandedURI q<ManakaiDOM:DOMAttribute>) {
1875 wakaba 1.8 local $opt{ExpandedURI q<MDOMX:attr>}
1876 wakaba 1.14 = $method->{ExpandedURI q<dis2pm:methodName+>};
1877 wakaba 1.3 my $getter = $method->{ExpandedURI q<dis2pm:getter>};
1878 wakaba 1.5 valid_err qq{Getter for attribute "$method->{Name}" must be }.
1879     q{defined}, node => $method->{src} unless $getter;
1880 wakaba 1.3 my $setter = defined $method->{ExpandedURI q<dis2pm:setter>}->{Name}
1881     ? $method->{ExpandedURI q<dis2pm:setter>} : undef;
1882     my $for = [keys %{$method->{For}}]->[0];
1883 wakaba 1.14 local $opt{'For+'} = [keys %{$method->{'For+'}||{}}];
1884 wakaba 1.4 my $for1 = $for;
1885 wakaba 1.3 unless (dis_uri_for_match (ExpandedURI q<ManakaiDOM:ManakaiDOM1>,
1886     $for, node => $method->{src})) {
1887 wakaba 1.4 $for1 = ExpandedURI q<ManakaiDOM:ManakaiDOMLatest>;
1888 wakaba 1.3 }
1889 wakaba 1.8 local $opt{ExpandedURI q<MDOMX:on>} = 'get';
1890 wakaba 1.14 my $get_code = dispm_get_code (%opt, resource => $getter, For => $for,
1891 wakaba 1.11 ExpandedURI q<dis2pm:DefKeyName>
1892     => ExpandedURI q<d:Def>);
1893 wakaba 1.3 if (defined $get_code) {
1894     my $default = dispm_get_value
1895 wakaba 1.8 (%opt, resource => $getter,
1896 wakaba 1.3 ExpandedURI q<dis2pm:ValueKeyName>
1897     => ExpandedURI q<d:DefaultValue>,
1898     ExpandedURI q<dis2pm:useDefaultValue> => 1,
1899     ExpandedURI q<dis2pm:valueType>
1900     => $getter->{ExpandedURI q<d:actualType>});
1901     $get_code = perl_statement
1902     (defined $default ? 'my $r = '.$default : 'my $r').
1903     $get_code. "\n" .
1904     perl_statement ('$r');
1905     } else { ## Get code not defined
1906     $get_code = perl_statement
1907     dispm_perl_throws
1908     class => ExpandedURI q<DOMCore:ManakaiDOMException>,
1909 wakaba 1.4 class_for => $for1,
1910 wakaba 1.3 type => 'NOT_SUPPORTED_ERR',
1911     subtype =>
1912     ExpandedURI q<MDOMX:MDOM_IMPL_ATTR_NOT_IMPLEMENTED>,
1913     xparam => {
1914     ExpandedURI q<MDOMX:class>
1915     => $pack->{ExpandedURI q<dis2pm:packageName>},
1916     ExpandedURI q<MDOMX:attr>
1917 wakaba 1.14 => $method->{ExpandedURI q<dis2pm:methodName+>},
1918 wakaba 1.3 ExpandedURI q<MDOMX:on> => 'get',
1919     };
1920     }
1921     if ($setter) {
1922 wakaba 1.8 local $opt{ExpandedURI q<MDOMX:on>} = 'set';
1923     my $set_code = dispm_get_code
1924 wakaba 1.11 (%opt, resource => $setter, For => $for,
1925     ExpandedURI q<dis2pm:DefKeyName>
1926     => ExpandedURI q<d:Def>);
1927 wakaba 1.3 if (defined $set_code) {
1928 wakaba 1.7 my $nm = dispm_get_code
1929 wakaba 1.8 (%opt, resource => $State->{Type}
1930 wakaba 1.7 ->{$setter->{ExpandedURI q<d:actualType>}},
1931     ExpandedURI q<dis2pm:DefKeyName>
1932     => ExpandedURI q<ManakaiDOM:inputNormalizer>,
1933     For => $for,
1934     ExpandedURI q<dis2pm:getCodeNoTypeCheck> => 1);
1935     if (defined $nm) {
1936 wakaba 1.17 $nm =~ s/\$INPUT\b/\$given/g;
1937 wakaba 1.7 } else {
1938     $nm = '';
1939     }
1940     $set_code = $nm .
1941 wakaba 1.15 $set_code. "\n";
1942 wakaba 1.3 } else { ## Set code not defined
1943     $set_code = perl_statement
1944     dispm_perl_throws
1945     class => ExpandedURI q<DOMCore:ManakaiDOMException>,
1946 wakaba 1.4 class_for => $for1,
1947 wakaba 1.3 type => 'NOT_SUPPORTED_ERR',
1948     subtype =>
1949     ExpandedURI q<MDOMX:MDOM_IMPL_ATTR_NOT_IMPLEMENTED>,
1950     xparam => {
1951     ExpandedURI q<MDOMX:class>
1952     => $pack->{ExpandedURI q<dis2pm:packageName>},
1953     ExpandedURI q<MDOMX:attr>
1954 wakaba 1.14 => $method->{ExpandedURI q<dis2pm:methodName+>},
1955 wakaba 1.3 ExpandedURI q<MDOMX:on> => 'set',
1956     };
1957     }
1958     $get_code = perl_if '@_ == 2',
1959     perl_statement ('my ($self, $given) = @_').
1960     $set_code,
1961     perl_statement ('my ($self) = @_').
1962     $get_code;
1963     } else {
1964     $get_code = perl_statement ('my ($self) = @_').
1965     $get_code;
1966     }
1967 wakaba 1.14 if (length $method->{ExpandedURI q<dis2pm:methodName>}) {
1968     $result .= perl_sub
1969     (name => $method->{ExpandedURI q<dis2pm:methodName>},
1970     prototype => $setter ? '$;$' : '$',
1971     code => $get_code);
1972     } else {
1973     $method->{ExpandedURI q<dis2pm:methodCodeRef>}
1974     = perl_sub (name => '', code => $get_code,
1975     prototype => $setter ? '$;$' : '$');
1976     }
1977 wakaba 1.1 }
1978     } # package method
1979 wakaba 1.14
1980     ## -- Constants
1981 wakaba 1.5 for my $cg (values %{$pack->{ExpandedURI q<dis2pm:constGroup>}}) {
1982     next unless defined $cg->{Name};
1983     $result .= dispm_const_group (resource => $cg);
1984     } # package const group
1985     for my $cv (values %{$pack->{ExpandedURI q<dis2pm:const>}}) {
1986     next unless defined $cv->{Name};
1987 wakaba 1.11 $result .= dispm_const_value_sub (resource => $cv);
1988 wakaba 1.5 } # package const value
1989 wakaba 1.14
1990 wakaba 1.17 ## -- Error codes
1991     if ({
1992     ExpandedURI q<ManakaiDOM:ExceptionClass> => 1,
1993     ExpandedURI q<ManakaiDOM:WarningClass> => 1,
1994     }->{$pack->{ExpandedURI q<dis2pm:type>}}) {
1995     $result .= perl_sub
1996     name => '___error_def',
1997     prototype => '',
1998     code => perl_list {
1999     map {
2000     $_->{Name} => {
2001     ExpandedURI q<DOMCore:code>
2002     => perl_code_literal
2003     dispm_const_value (%opt, resource => $_),
2004     description => dispm_muf_description
2005     (%opt, resource => $_),
2006     ExpandedURI q<MDOMX:subtype> => {
2007     map {
2008     $_->{NameURI} => {
2009     description => dispm_muf_description
2010     (%opt, resource => $_),
2011     },
2012     } grep {defined $_->{Name}}
2013     values %{$_->{ExpandedURI q<dis2pm:xSubType>}||{}}
2014     },
2015     },
2016     } grep {defined $_->{Name}}
2017     values %{$pack->{ExpandedURI q<dis2pm:xConst>}||{}}
2018     };
2019     }
2020    
2021 wakaba 1.14 ## -- Operators
2022     my %ol;
2023 wakaba 1.17 my %mtd;
2024 wakaba 1.14 for (values %{$pack->{ExpandedURI q<dis2pm:overload>}||{}}) {
2025     next unless defined $_->{resource}->{Name};
2026     if ($_->{resource}->{ExpandedURI q<dis2pm:methodName+>} =~ /^\#/) {
2027     if ($_->{operator} =~ /^[A-Z]+$/) {
2028     my $code = $_->{resource}->{ExpandedURI q<dis2pm:methodCodeRef>};
2029     $code =~ s/\bsub /sub $_->{operator} /;
2030     $result .= $code;
2031 wakaba 1.17 $mtd{$_->{operator}} = 1;
2032 wakaba 1.14 } else {
2033     $ol{$_->{operator}} = perl_code_literal $_->{resource}
2034     ->{ExpandedURI q<dis2pm:methodCodeRef>};
2035     }
2036     } else {
2037     if ($_->{operator} =~ /^[A-Z]+$/) {
2038 wakaba 1.17 $mtd{$_->{operator}} = 1;
2039 wakaba 1.14 $result .= perl_statement
2040     perl_assign
2041     perl_var (type => '*',
2042     local_name => $_->{operator})
2043     => perl_var (type => '\&',
2044     local_name => $_->{resource}
2045     ->{ExpandedURI q<dis2pm:methodName>});
2046     } else {
2047     $ol{$_->{operator}}
2048     = $_->{resource}->{ExpandedURI q<dis2pm:methodName>};
2049     }
2050     }
2051     }
2052     if (keys %ol) {
2053     $ol{fallback} = 1;
2054     $result .= perl_statement 'use overload '.perl_list %ol;
2055     }
2056     for (values %{$pack->{ExpandedURI q<d:Operator>}||{}}) {
2057     next unless defined $_->{resource}->{Name};
2058     if ($_->{operator} eq ExpandedURI q<ManakaiDOM:MUErrorHandler>) {
2059     if ($_->{resource}->{ExpandedURI q<dis2pm:methodName+>} =~ /^\#/) {
2060     my $code = $_->{resource}->{ExpandedURI q<dis2pm:methodCodeRef>};
2061 wakaba 1.16 $code =~ s/\bsub /sub ___report_error /;
2062 wakaba 1.14 $result .= $code;
2063     } else {
2064     $result .= perl_statement
2065     perl_assign
2066     perl_var (type => '*',
2067 wakaba 1.16 local_name => '___report_error')
2068 wakaba 1.14 => perl_var (type => '\&',
2069     local_name => $_->{resource}
2070     ->{ExpandedURI q<dis2pm:methodName>});
2071     }
2072     } else {
2073     valid_err qq{Operator <$_->{operator}> is not supported},
2074     node => $_->{resource}->{src};
2075     }
2076     }
2077 wakaba 1.5 }
2078 wakaba 1.1 } # root object
2079 wakaba 1.6 }
2080    
2081 wakaba 1.16
2082     ## -- Variables
2083     for my $var (values %{$State->{Module}->{$State->{module}}
2084     ->{ExpandedURI q<dis2pm:variable>}}) {
2085     next unless defined $var->{Name};
2086     my $default = dispm_get_value
2087     (%opt, resource => $var,
2088     ExpandedURI q<dis2pm:ValueKeyName>
2089     => ExpandedURI q<d:DefaultValue>,
2090     ExpandedURI q<dis2pm:useDefaultValue> => 1,
2091     ExpandedURI q<dis2pm:valueType>
2092     => $var->{ExpandedURI q<d:actualType>});
2093    
2094     ## ISSUE: scope
2095    
2096     my $v = perl_var
2097     (type => $var->{ExpandedURI q<dis2pm:variableType>},
2098     local_name => $var->{ExpandedURI q<dis2pm:variableName>});
2099     if (defined $default and length $default) {
2100     $result .= perl_statement
2101     perl_assign $v => $default;
2102     } else {
2103     $result .= perl_statement $v;
2104     }
2105    
2106     if ($var->{ExpandedURI q<DISPerl:isExportOK>}) {
2107     $State->{ExpandedURI q<dis2pm:Package>}
2108     ->{$State->{Module}->{$State->{module}}
2109     ->{ExpandedURI q<dis2pm:packageName>}}
2110     ->{ExpandedURI q<dis2pm:variable>}->{$v} = 1;
2111     ## NOTE: Variable name uniqueness is assured in dis.pl.
2112     }
2113     }
2114    
2115     ## Constant exportion
2116     {
2117     my @xok;
2118     my $xr = '';
2119     my $cg = $State->{ExpandedURI q<dis2pm:Package>}
2120     ->{$State->{Module}->{$State->{module}}
2121     ->{ExpandedURI q<dis2pm:packageName>}}
2122     ->{ExpandedURI q<dis2pm:constGroup>};
2123     my %etag;
2124     for (keys %$cg) {
2125     $etag{$_} = $cg->{$_}->{member};
2126     }
2127     $xr .= perl_statement
2128     perl_assign
2129     perl_var (type => '%', local_name => 'EXPORT_TAG',
2130     scope => 'our')
2131     => '('.(perl_list %etag).')'
2132     if keys %etag;
2133    
2134     my $c = $State->{ExpandedURI q<dis2pm:Package>}
2135     ->{$State->{Module}->{$State->{module}}
2136     ->{ExpandedURI q<dis2pm:packageName>}}
2137     ->{ExpandedURI q<dis2pm:const>};
2138     if (keys %$c) {
2139     push @xok, keys %$c;
2140     $xr .= join '', map {perl_statement "sub $_ ()"} keys %$c;
2141     my $al = perl_literal {map {$_ =>
2142     $c->{$_}->{package}.'::'.$_} keys %$c};
2143     my $AL = '$al';
2144     my $ALD = '$AUTOLOAD';
2145     my $XL = '$Exporter::ExportLevel';
2146     my $SELF = '$self';
2147     my $ARGS = '@_';
2148     my $IT = '$_';
2149     my $REF = '\\';
2150 wakaba 1.17 my $NONAME = '\W';
2151 wakaba 1.16 $xr .= qq{
2152     sub AUTOLOAD {
2153     my $AL = our $ALD;
2154     $AL =~ s/.+:://;
2155     if ($al -> {$AL}) {
2156     no strict 'refs';
2157     *{$ALD} = $REF &{$al -> {$AL}};
2158     goto &{$ALD};
2159     } else {
2160     require Carp;
2161     Carp::croak (qq<Can't locate method "$ALD">);
2162     }
2163     }
2164     sub import {
2165     my $SELF = shift;
2166     if ($ARGS) {
2167     local $XL = $XL + 1;
2168     $SELF->SUPER::import ($ARGS);
2169     for (grep {not /$NONAME/} $ARGS) {
2170     eval qq{$IT};
2171     }
2172     }
2173     }
2174     };
2175     }
2176    
2177     for (keys %{$State->{ExpandedURI q<dis2pm:Package>}
2178     ->{$State->{Module}->{$State->{module}}
2179     ->{ExpandedURI q<dis2pm:packageName>}}
2180     ->{ExpandedURI q<dis2pm:variable>}}) {
2181     push @xok, $_;
2182     }
2183    
2184     if (@xok) {
2185     $xr .= perl_statement
2186     perl_assign
2187     perl_var (type => '@', local_name => 'EXPORT_OK',
2188     scope => 'our')
2189     => '('.(perl_list @xok).')';
2190     }
2191    
2192     if ($xr) {
2193     $result .= perl_change_package (full_name => $State->{Module}
2194     ->{$State->{module}}
2195     ->{ExpandedURI q<dis2pm:packageName>});
2196     $result .= $xr;
2197     $result .= perl_statement 'use Exporter';
2198     $result .= perl_statement 'push our @ISA, "Exporter"';
2199     }
2200     }
2201    
2202     ## Required modules
2203 wakaba 1.11 $result .= dispm_package_declarations;
2204     my $begin = '';
2205 wakaba 1.6 for (keys %{$State->{Module}->{$State->{module}}
2206     ->{ExpandedURI q<dis2pm:requiredModule>}||{}}) {
2207     next if $_ eq $State->{Module}->{$State->{module}}
2208     ->{ExpandedURI q<dis2pm:packageName>};
2209 wakaba 1.11 $begin .= perl_statement ('require ' . $_);
2210 wakaba 1.12 $State->{ExpandedURI q<dis2pm:referredPackage>}->{$_} = -1;
2211 wakaba 1.11 }
2212     $result = $begin . $result if $begin;
2213    
2214     my @ref;
2215     for (keys %{$State->{ExpandedURI q<dis2pm:referredPackage>}||{}}) {
2216     my $v = $State->{ExpandedURI q<dis2pm:referredPackage>}->{$_};
2217     if (ref $v or $v >= 0) {
2218     push @ref, $_;
2219     }
2220 wakaba 1.1 }
2221 wakaba 1.11 $result .= "for (" . join (", ", map {'$'.$_.'::'} @ref) . ") {}"
2222     if @ref;
2223 wakaba 1.1
2224 wakaba 1.11 $result = $header . $result . perl_statement 1;
2225 wakaba 1.1
2226     output_result $result;
2227    
2228 wakaba 1.17 =head1 BUGS
2229    
2230     Dynamic change for namespace binding, current "For", ... is poorly
2231     supported - it a code or element refers another code or element
2232     in the same or different source file, then their own bindings, not the former
2233     code or element's, should be used for resolution. The current
2234     implementation does not do so perfectly. So authors of
2235     "dis" files are encouraged not to bind the same namespace prefix
2236     to different namespace URIs and to prefer prefixed QName.
2237    
2238     =head1 SEE ALSO
2239    
2240     L<lib/manakai/dis.pl> - "dis" common utility.
2241    
2242     L<lib/manakai/DISCore.dis> - The definition for the "dis" format.
2243    
2244     L<lib/manakai/DISPerl.dis> - The definition for the "dis" Perl-specific
2245     vocabulary.
2246    
2247     =head1 LICENSE
2248    
2249     Copyright 2004-2005 Wakaba <w@suika.fam.cx>. All rights reserved.
2250    
2251     This program is free software; you can redistribute it and/or
2252     modify it under the same terms as Perl itself.
2253    
2254     =cut
2255    
2256     1; # $Date:$

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24