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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (hide annotations) (download)
Fri Dec 31 12:03:39 2004 UTC (19 years, 10 months ago) by wakaba
Branch: MAIN
Changes since 1.15: +216 -22 lines
File MIME type: text/plain
DISPerl:ScalarVariable: new type; domtest: New cdis support

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24