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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24