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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24