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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24