#!/usr/bin/perl -w use strict; =head1 NAME cdis2pm - Generating Perl Module from a Compiled "dis" =head1 SYNOPSIS perl path/to/cdis2pm.pl input.cdis \ {--module-name=ModuleName | --module-uri=module-uri} \ [--for=for-uri] [options] > ModuleName.pm perl path/to/cdis2pm.pl --help =head1 DESCRIPTION The C script generates a Perl module from a compiled "dis" ("cdis") file. It is intended to be used to generate a manakai DOM Perl module files, although it might be useful for other purpose. This script is part of manakai. =cut use Message::Util::QName::Filter { d => q, dis2pm => q, DISCore => q, DISLang => q, DISPerl => q, disPerl => q, DOMCore => q, DOMEvents => q, DOMMain => q, DOMXML => q, DX => q, lang => q, Perl => q, license => q, ManakaiDOM => q, MDOMX => q, owl => q, rdf => q, rdfs => q, swcfg21 => q, TreeCore => q<>, }; =head1 OPTIONS =over 4 =item --enable-assertion / --noenable-assertion (default) Whether assertion codes should be outputed or not. =item --for=I (Optional) Specifies the "For" URI reference for which the outputed module is. If this parameter is ommitted, the default "For" URI reference for the module, if any, or the C is assumed. =item --help Shows the help message. =item --module-name=I The name of module to output. It is the local name part of the C C in the source "dis" file. Either C<--module-name> or C<--module-uri> is required. =item --module-uri=I A URI reference that identifies a module to output. Either C<--module-name> or C<--module-uri> is required. =item --output-module-version (default) / --nooutput-module-version Whether the C<$VERSION> special variable should be generated or not. =item --verbose / --noverbose (default) Whether a verbose message mode should be selected or not. =back =cut use Getopt::Long; use Pod::Usage; use Storable; my %Opt; GetOptions ( 'enable-assertion!' => \$Opt{outputAssertion}, 'for=s' => \$Opt{For}, 'help' => \$Opt{help}, 'module-name=s' => \$Opt{module_name}, 'module-uri=s' => \$Opt{module_uri}, 'output-module-version!' => \$Opt{outputModuleVersion}, 'verbose!' => $Opt{verbose}, ) or pod2usage (2); pod2usage ({-exitval => 0, -verbose => 1}) if $Opt{help}; $Opt{file_name} = shift; pod2usage ({-exitval => 2, -verbose => 0}) unless $Opt{file_name}; pod2usage (2) if not $Opt{module_uri} and not $Opt{module_name}; $Opt{outputModuleVersion} = 1 unless defined $Opt{outputModuleVersion}; BEGIN { require 'manakai/genlib.pl'; require 'manakai/dis.pl'; } our $State = retrieve ($Opt{file_name}) or die "$0: $Opt{file_name}: Cannot load"; eval q{ sub impl_msg ($;%) { warn shift () . "\n"; } } unless $Opt{verbose}; =head1 FUNCTIONS This section describes utility functions defined in this script for the sake of developer. =over 4 =item $result = perl_change_package (full_name => I) Changes the current Perl package in the output Perl code. C is also called in this function. =cut sub perl_change_package (%) { my %opt = @_; my $fn = $opt{full_name}; impl_err (qq<$fn: Bad package name>) unless $fn; unless ($fn eq $State->{ExpandedURI q}) { my $r = dispm_package_declarations (%opt); $State->{ExpandedURI q} = $fn; $State->{ExpandedURI q}->{$fn} = -1; return $r . perl_statement qq; } else { return ''; } } # perl_change_package =item $code = dispm_package_declarations (%opt) Generates a code fragment that declares what is required in the current package, including import statements for character classes. =cut sub dispm_package_declarations (%) { my %opt = @_; my $pack_name = $State->{ExpandedURI q}; my $pack = $State->{ExpandedURI q}->{$pack_name}; my $r = ''; my @xml_class; for (keys %{$pack->{ExpandedURI q}||{}}) { my $val = $pack->{ExpandedURI q}->{$_}; next if not ref $val and $val <= 0; if (/^InXML/) { push @xml_class, $_; $pack->{ExpandedURI q}->{$_} = -1; } else { valid_err (qq<"$_": Unknown character class>, node => ref $val ? $val : $opt{node}); } } if (@xml_class) { $State->{Module}->{$State->{module}} ->{ExpandedURI q} ->{'Char::Class::XML'} = 1; $r .= perl_statement 'Char::Class::XML->import ('. perl_list (@xml_class).')'; } $r; } # dispm_package_declarations =item $code = dispm_perl_throws (%opt) Generates a code to throw an exception. =cut sub dispm_perl_throws (%) { my %opt = @_; my $x = $opt{class_resource} || $State->{Type}->{$opt{class}}; my $r = 'report '; unless (defined $x->{Name}) { $opt{class} = dis_typeforuris_to_uri ($opt{class}, $opt{class_for}, %opt); $x = $State->{Type}->{$opt{class}}; } valid_err (qq is not defined>, node => $opt{node}) unless defined $x->{Name}; if ($x->{ExpandedURI q} and { ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$x->{ExpandedURI q}}) { $opt{type} = $opt{type_resource}->{Name} unless defined $opt{type}; valid_err qq{Exception code must be specified}, node => $opt{type_resource}->{src} || $opt{node} unless defined $opt{type}; $opt{subtype} = $opt{subtype_resource}->{NameURI} || $opt{subtype_resource}->{URI} unless defined $opt{subtype}; $opt{xparam}->{ExpandedURI q} = $opt{subtype} if defined $opt{subtype}; $r .= $x->{ExpandedURI q} . ' ' . perl_list -type => $opt{type}, -object => perl_code_literal ('$self'), %{$opt{xparam} || {}}; $State->{Module}->{$State->{module}} ->{ExpandedURI q} ->{$State->{Module}->{$x->{parentModule}} ->{ExpandedURI q}} = 1; } else { no warnings 'uninitialized'; valid_err (qq{Resource <$opt{class}> [<$x->{ExpandedURI q}>] }. q. q, node => $opt{node}); } return $r; } # dispm_perl_throw =item Lexical Variable $RegQNameChar The regular expression pattern for a QName character. =item Lexical Variable $RegBlockContent The regular expression pattern for a "block", i.e. a nestable section of "{" ... "}". =cut my $RegQNameChar = qr/[^\s<>"'\\\[\]\{\},=]/; use re 'eval'; my $RegBlockContent; $RegBlockContent = qr/(?>[^{}\\]*)(?>(?>[^{}\\]+|\\.|\{(??{$RegBlockContent})\})*)/s; =item $result = perl_code ($code, %opt) Converts preprocessing instructions in the <$code> and returns it. Note that this function is also defined in F but redefined here for the purpose of this script. =cut sub perl_code ($;%) { my ($s, %opt) = @_; valid_err q, node => $opt{node} unless defined $s; $s = $$s if ref $s eq '__code'; local $State->{Namespace} = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding}; $s =~ s[(?]+)>|\b(null|true|false)\b][ my ($q, $l) = ($1, $2); my $r; if (defined $q) { if ($q =~ /\}/) { valid_warn qq" has a "}" - it might be a typo>; } if ($q =~ /=$/) { valid_warn qq" ends with a "=" - >. q{should "=" be used place of "=>"?}; } if ($q =~ s/^(.+?):://) { my $et = dis_qname_to_uri ($1, %opt, use_default_namespace => ExpandedURI q); if ($et eq ExpandedURI q) { ## QName constant $r = perl_literal (dis_qname_to_uri ($q, use_default_namespace => 1, %opt)); } elsif ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$et}) { ## Method call my ($clsq, $mtdq) = split /\s*\.\s*/, $q, 2; my $clsu = dis_typeforqnames_to_uri ($clsq, use_default_namespace => 1, %opt); my $cls = $State->{Type}->{$clsu}; my $clsp = $cls->{ExpandedURI q}; if ($cls->{ExpandedURI q} and { ExpandedURI q => 1, ExpandedURI q => 1, }->{$cls->{ExpandedURI q}}) { valid_err q<"disPerl:ClassM" cannot be used for interface methods>, node => $opt{node} if $et eq ExpandedURI q; $clsp = ''; } else { valid_err qq must be defined>, node => $opt{node} unless defined $clsp; $State->{Module}->{$State->{module}} ->{ExpandedURI q} ->{$State->{Module}->{$cls->{parentModule}} ->{ExpandedURI q}} = 1; } if ($mtdq =~ /:/) { valid_err qq<$mtdq: Prefixed method name not supported>, node => $opt{node}; } else { my $mtd; for (values %{$cls->{ExpandedURI q}}) { if (defined $_->{Name} and $_->{Name} eq $mtdq) { $mtd = $_; last; } } valid_err qq. q, node => $mtd->{src} || $opt{node} if not defined $mtd or not defined $mtd->{ExpandedURI q}; $r = ' ' . ($clsp ? $clsp . { ExpandedURI q => '::', ExpandedURI q => '::', ExpandedURI q => '::', ExpandedURI q => '->', }->{$et} : '') . $mtd->{ExpandedURI q} . ' '; } } elsif ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$et}) { ## Perl package name my $uri = dis_typeforqnames_to_uri ($q, use_default_namespace => 1, %opt); if (defined $State->{Type}->{$uri}->{Name} and defined $State->{Type}->{$uri} ->{ExpandedURI q}) { $r = $State->{Type}->{$uri}->{ExpandedURI q}; if ({ ExpandedURI q => 1, ExpandedURI q => 1, }->{$et}) { $r = perl_literal $r; } } else { valid_err qq must be defined>, node => $opt{node}; } } elsif ($et eq ExpandedURI q) { ## CODE constant my ($nm); $q =~ s/^\s+//; if ($q =~ s/^((?>(?!::).)+)//s) { $nm = $1; $nm =~ tr/|/:/; } else { valid_err qq<"$q": Code name required>, node => $opt{node}; } $q =~ s/^::\s*//; my $param = dispm_parse_param (\$q, %opt, ExpandedURI q => 1, use_default_namespace => ''); my $uri = dis_typeforqnames_to_uri ($nm, use_default_namespace => 1, %opt); if (defined $State->{Type}->{$uri}->{Name} and dis_resource_ctype_match (ExpandedURI q, $State->{Type}->{$uri}, %opt)) { local $State->{ExpandedURI q} = $param; ## ISSUE: It might be required to check loop referring $r = dispm_get_code (%opt, resource => $State->{Type}->{$uri}, For => [keys %{$State->{Type}->{$uri} ->{For}}]->[0], 'For+' => [keys %{$State->{Type}->{$uri} ->{'For+'}||{}}], is_inline => 1, ExpandedURI q => $param, ExpandedURI q => ExpandedURI q); for (grep {/^\$/} keys %$param) { $r =~ s/\Q$_\E\b/$param->{$_}/g; } } else { valid_err qq must be defined>, node => $opt{node}; } } elsif ($et eq ExpandedURI q) { if ($q =~ /^((?>(?!\.)$RegQNameChar)*)\.($RegQNameChar+)$/o) { my ($cls, $constn) = ($1, $2); if (length $cls) { my $clsu = dis_typeforqnames_to_uri ($cls, %opt, use_default_namespace => 1, node => $_); $cls = $State->{Type}->{$clsu}; valid_err qq must be defined>, node => $_ unless defined $cls->{Name}; } else { $cls = $State->{ExpandedURI q}; valid_err q, node => $_ unless defined $cls->{Name}; } my $const = $cls->{ExpandedURI q}->{$constn}; valid_err qq. qq{"$cls->{Name}" (<$cls->{URI}>)}, node => $_ unless defined $const->{Name}; $r = dispm_const_value (resource => $const); } else { valid_err qq<"$q": Syntax error>, node => $opt{node}; } } else { valid_err qq<"$et": Unknown element type>, node => $opt{node}; } } else { valid_err qq<"<$q>": Element type must be specified>, node => $opt{node}; } } else { $r = {true => 1, false => 0, null => 'undef'}->{$l}; } $r; ]ge; if ($s =~ /\btry\b/) { $s = q.$s; } ## ISSUE: __FILE__ & __LINE__ will break if multiline substition happens. $s =~ s{ \b__($RegQNameChar+) (?:\{($RegBlockContent)\})? __\b }{ my ($name, $data) = ($1, $2); my $r; my $et = dis_qname_to_uri ($name, %opt, use_default_namespace => ExpandedURI q); if ($et eq ExpandedURI q) { ## Deep Method Call $r = '{'.perl_statement ('local $Error::Depth = $Error::Depth + 1'). perl_code ($data, %opt) . '}'; } elsif ($et eq ExpandedURI q) { ## Shallow Method Call $r = '{'.perl_statement ('local $Error::Depth = $Error::Depth - 1'). perl_code ($data, %opt) . '}'; } elsif ({ ExpandedURI q => 1, ExpandedURI q => 1, }->{$et}) { ## Raising an Exception or Warning if ($data =~ s/^ \s* ((?>(?! ::|\.)$RegQNameChar)+) \s* (?: \. \s* ((?>(?! ::|\.)$RegQNameChar)+) \s* (?: \. \s* ((?>(>! ::|\.)$RegQNameChar)+) \s* )? )? (?: ::\s* | $)//ox) { my ($q, $constq, $subtypeq) = ($1, $2, $3); s/\|/:/g for $q, $constq, $subtypeq; my ($cls, $const, $subtype) = dispm_xcref_to_resources ([$q, $constq, $subtypeq], %opt); ## Parameter my %xparam; while ($data =~ s/^\s*($RegQNameChar+)\s*//) { my $pnameuri = dis_qname_to_uri ($1, use_default_namespace => 1, %opt); if (defined $xparam{$pnameuri}) { valid_err qq is already specified>, node => $opt{node}; } if ($data =~ s/^=>\s*'([^']*)'\s*//) { ## String $xparam{$pnameuri} = $1; } elsif ($data =~ s/^=>\s*\{($RegBlockContent)\}\s*//) { ## Code $xparam{$pnameuri} = perl_code_literal ($1); } elsif ($data =~ /^,|$/) { ## Boolean $xparam{$pnameuri} = 1; } else { valid_err qq<<$pnameuri>: Parameter value is expected>, node => $opt{node}; } $data =~ s/^\,\s*// or last; } valid_err qq<"$data": Broken exception parameter specification>, node => $opt{node} if length $data; for ( ExpandedURI q, ExpandedURI q, ExpandedURI q, ExpandedURI q, ) { $xparam{$_} = $opt{$_} if defined $opt{$_}; } $r = dispm_perl_throws (%opt, class_resource => $cls, type_resource => $const, subtype_resource => $subtype, xparam => \%xparam); } else { valid_err qq, node => $opt{node}; } } elsif ($et eq ExpandedURI q) { my ($nm); $data =~ s/^\s+//; if ($data =~ s/^((?>(?!::).)+)//) { $nm = $1; } else { valid_err q, node => $opt{node}; } $data =~ s/^::\s*//; my $param = dispm_parse_param (\$data, %opt, use_default_namespace => '', ExpandedURI q => 1); my $uri = dis_typeforqnames_to_uri ($nm, use_default_namespace => 1, %opt); if (defined $State->{Type}->{$uri}->{Name} and dis_resource_ctype_match (ExpandedURI q, $State->{Type}->{$uri}, %opt)) { local $State->{ExpandedURI q} = $param; ## ISSUE: It might be required to detect a loop $r = dispm_get_code (%opt, resource => $State->{Type}->{$uri}, For => [keys %{$State->{Type}->{$uri} ->{For}}]->[0], 'For+' => [keys %{$State->{Type}->{$uri} ->{'For+'}||{}}], ExpandedURI q => $param, ExpandedURI q => ExpandedURI q); for (grep {/^\$/} keys %$param) { $r =~ s/\Q$_\E\b/ref $param->{$_} ? ${$param->{$_}} : $param->{$_}/ge; } valid_err qq is empty>, node => $opt{node} unless length $r; $r = "\n{\n$r\n}\n"; } else { valid_err qq must be defined>, node => $opt{node}; } } elsif ($et eq ExpandedURI q) { my $method = $opt{ExpandedURI q}; valid_err q cannot be used here>, node => $opt{node} unless defined $method->{Name}; PARAM: { for my $param (@{$method->{ExpandedURI q}||[]}) { if ($data eq $param->{ExpandedURI q}) { ## NOTE: property is not ## checked for this element. my $nm = dispm_get_code (%opt, resource => $State->{Type} ->{$param->{ExpandedURI q}}, ExpandedURI q => ExpandedURI q, ExpandedURI q => 1, ExpandedURI q => $param->{ExpandedURI q}); if (defined $nm) { $nm =~ s[\$INPUT\b][\$$param->{ExpandedURI q} ]g; $r = $nm; } else { $r = ''; } last PARAM; } } valid_err q, node => $opt{node}; } } elsif ($et eq ExpandedURI q) { if ($data =~ s/^\s*IS\s*\{($RegBlockContent)\}::\s*//o) { my $v = dis_qname_to_uri ($1, use_default_namespace => 1, %opt); if ($State->{ExpandedURI q}->{$v}) { $r = perl_code ($data, %opt); } } else { valid_err qq, node => $opt{node}; } } elsif ($et eq ExpandedURI q) { if ($data =~ s/^((?>(?!::).)*)::\s*//) { my @For = ($opt{For} || ExpandedURI q, @{$opt{'For+'} || []}); V: for (split /\s*\|\s*/, $1) { my $for = dis_qname_to_uri ($_, %opt, use_default_namespace => 1, node => $opt{node}); for (@For) { if (dis_uri_for_match ($for, $_, %opt)) { $r = perl_code ($data, %opt); last V; } } } } else { valid_err (qq block: "$data">, node => $opt{node}); } } elsif ($et eq ExpandedURI q) { my $atype; if ($data =~ s/^\s*($RegQNameChar+)\s*::\s*//) { $atype = dis_qname_to_uri ($1, %opt, use_default_namespace => 1); } else { valid_err (qq<"$data": Assertion type QName is required>, node => $opt{node}); } my $param = dispm_parse_param (\$data, %opt, use_default_namespace => '', ExpandedURI q => 1); my %xparam; my $cond; my $pre = ''; my $post = ''; if ($atype eq ExpandedURI q) { $pre = perl_statement perl_assign 'my $asActual' => '('.perl_code ($param->{actual}, %opt).')'; $cond = '$asActual > 0'; $xparam{ExpandedURI q} = 'a positive value'; $xparam{ExpandedURI q} = perl_code_literal q<$asActual>; } elsif ($atype eq ExpandedURI q) { $cond = '0'; $xparam{ExpandedURI q} = $param->{msg}; $xparam{ExpandedURI q} = '(invariant)'; } else { valid_err (qq is not supported>, node => $opt{node}); } if (defined $param->{pre}) { $pre = perl_code ($param->{pre}, %opt) . $pre; } if (defined $param->{post}) { $post .= perl_code ($param->{post}, %opt); } for ( ExpandedURI q, ExpandedURI q, ExpandedURI q, ExpandedURI q, ) { $xparam{$_} = $opt{$_} if defined $opt{$_}; } if ($Opt{outputAssertion}) { $r = $pre . perl_if $cond, undef, perl_statement dispm_perl_throws class => ExpandedURI q, class_for => ExpandedURI q, type => 'MDOM_DEBUG_BUG', subtype => ExpandedURI q, xparam => { ExpandedURI q => $atype, ExpandedURI q => perl_code_literal q<(sprintf 'at %s line %s%s%s', __FILE__, __LINE__, "\n\t", Carp::longmess ())>, %xparam, }; $r .= $post; $r = "{$r}"; } else { $r = ''; } } elsif ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$et}) { $r = qq<__${name}__>; valid_err (q. qq>, node => $opt{node}) if length $data; } else { valid_err qq not supported>, node => $opt{node}; } $r; }goex; ## Checks \p character classes while ($s =~ /\\p{([^{}]+)}/gs) { my $name = $1; $State->{ExpandedURI q} ->{$State->{ExpandedURI q}} ->{ExpandedURI q} ->{$name} ||= $opt{node} || 1; } $s; } =item {%param} = dispm_parse_param (\$paramspec, %opt) Parses parameter specification and returns it as a reference to hash. =cut sub dispm_parse_param ($%) { my ($src, %opt) = @_; my %param; while ($$src =~ s/^ ## Parameter name (\$? $RegQNameChar+)\s* (?: =>? \s* ## Parameter value ( ## Bare string $RegQNameChar+ | ## Quoted string '(?>[^'\\]*)' ## ISSUE: escape mechanism required? | ## Code \{$RegBlockContent\} ) \s*)? (?:,\s*|$)//ox) { my ($n, $v) = ($1, $2); if (defined $v) { if ($v =~ /^'/) { $v = substr ($v, 1, length ($v) - 2); } elsif ($v =~ /^\{/) { $v = perl_code_literal substr ($v, 1, length ($v) - 2); } else { # } } else { $v = 1; } if ($n =~ /^\$/) { $param{$n} = $v; } else { $param{dis_qname_to_uri ($n, %opt)} = $v; } } if ($opt{ExpandedURI q} and length $$src) { valid_err qq, node => $opt{node}; } \%param; } # dispm_parse_param =item $result = perl_code_source ($code, %opt) Attaches the source file information to a Perl code fragment. Note that the same name function is defined in F but redefined here for the purpose of this script. TODO: Non-debug purpose output should remove source information; otherwise it is too verbose. =cut sub perl_code_source ($%) { my ($s, %opt) = @_; my $npk = [qw/Name QName Label/]; my $f1 = sprintf q Node <%s> [Chunk #%d]>, $opt{file} || $State->{Module}->{$opt{resource}->{parentModule}}->{FileName}, $opt{path} || ($opt{resource}->{src} ? $opt{resource}->{src}->node_path (key => $npk) : $opt{node} ? $opt{node}->node_path (key => $npk) : 'x:unknown ()'), ++($State->{ExpandedURI q} ||= 0); my $f2 = sprintf q [Chunk #%d]>, $opt{file} || $State->{Module}->{$State->{module}}->{URI}, ++($State->{ExpandedURI q} ||= 0); $f1 =~ s/"/\"/g; $f2 =~ s/"/\"/g; sprintf qq<\n#line %d "%s"\n%s\n#line 1 "%s"\n>, $opt{line} || 1, $f1, $s, $f2; } # perl_code_source =item $code = dispm_get_code (resource => $res, %opt) Generates a Perl code fragment from resource(s). =cut sub dispm_get_code (%) { my %opt = @_; if (($opt{ExpandedURI q} and defined $opt{resource}->{Name}) or ($opt{resource}->{ExpandedURI q} and { ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$opt{resource}->{ExpandedURI q}}) or (dis_resource_ctype_match ([ExpandedURI q, ExpandedURI q], $opt{resource}, %opt, node => $opt{resource}->{src}))) { local $State->{Namespace} = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding} if defined $opt{resource}->{Name}; my $key = $opt{ExpandedURI q} || ExpandedURI q; my $n = dis_get_attr_node (%opt, parent => $opt{resource}->{src}, name => {uri => $key}, ContentType => ExpandedURI q) || dis_get_attr_node (%opt, parent => $opt{resource}->{src}, name => {uri => $key}, ContentType => ExpandedURI q); if ($n) { return disperl_to_perl (%opt, node => $n); } $n = dis_get_attr_node (%opt, parent => $opt{resource}->{src}, name => {uri => $key}, ContentType => ExpandedURI q); if ($n) { my $code = ''; for (@{dis_get_elements_nodes (%opt, parent => $n, name => 'require')}) { $code .= perl_statement 'require ' . $_->value; } my $v = $n->value; valid_err q, node => $n unless defined $v; $code .= perl_code ($v, %opt, node => $n); if ($opt{is_inline} and dis_resource_ctype_match ([ExpandedURI q], $opt{resource}, %opt, node => $opt{resource}->{src})) { $code =~ s/\n/\x20/g; return $code; } else { return perl_code_source ($code, %opt, node => $n); } } return undef; } else { impl_err ("Bad resource for dispm_get_code: ". $opt{resource}->{ExpandedURI q}, node => $opt{resource}->{src}); } } # dispm_get_code =item $code = dispm_get_value (%opt) Gets value property and returns it as a Perl code fragment. =cut sub dispm_get_value (%) { my %opt = @_; my $key = $opt{ExpandedURI q} || ExpandedURI q; my $vt = $opt{ExpandedURI q} || ExpandedURI q; local $State->{Namespace} = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding} if defined $opt{resource}->{Name}; local $opt{For} = [keys %{$opt{resource}->{For}}]->[0] if defined $opt{resource}->{Name}; local $opt{'For+'} = [keys %{$opt{resource}->{'For+'}||{}}] if defined $opt{resource}->{Name}; my $n = $opt{node} ? [$opt{node}] : dis_get_elements_nodes (%opt, parent => $opt{resource}->{src}, name => {uri => $key}); for my $n (@$n) { my $t = dis_get_attr_node (%opt, parent => $n, name => 'ContentType'); my $type; if ($t) { $type = dis_qname_to_uri ($t->value, %opt, node => $t); } elsif ($opt{resource}->{ExpandedURI q}) { $type = $opt{resource}->{ExpandedURI q}; } else { $type = ExpandedURI q; } valid_err (qq is not defined>, node => $t || $n) unless defined $State->{Type}->{$type}->{Name}; if (dis_uri_ctype_match (ExpandedURI q, $type, %opt)) { return perl_code ($n->value, %opt, node => $n); } elsif (dis_uri_ctype_match (ExpandedURI q, $type, %opt) or dis_uri_ctype_match (ExpandedURI q, $type, %opt)) { return perl_literal $n->value; } elsif (dis_uri_ctype_match (ExpandedURI q, $type, %opt) or dis_uri_ctype_match (ExpandedURI q, $type, %opt) or dis_uri_ctype_match (ExpandedURI q, $type, %opt) or dis_uri_ctype_match (ExpandedURI q, $type, %opt)) { return $n->value; } elsif (dis_uri_ctype_match (ExpandedURI q, $type, %opt)) { return ($n->value and ($n->value eq 'true' or $n->value eq '1')) ? 1 : 0; } elsif (dis_uri_ctype_match (ExpandedURI q, $type, %opt)) { return $n->value ? 1 : 0; } elsif (dis_uri_ctype_match (ExpandedURI q, $type, %opt)) { return perl_literal $n->value; } } ## No explicit value specified if ($opt{ExpandedURI q}) { if (dis_uri_ctype_match (ExpandedURI q, $vt, %opt)) { return q<"">; } elsif (dis_uri_ctype_match (ExpandedURI q, $vt, %opt) or dis_uri_ctype_match (ExpandedURI q, $vt, %opt) or dis_uri_ctype_match (ExpandedURI q, $vt, %opt) or dis_uri_ctype_match (ExpandedURI q, $vt, %opt) or dis_uri_ctype_match (ExpandedURI q, $vt, %opt)) { return q<0>; } elsif (dis_uri_ctype_match (ExpandedURI q, $vt, %opt)) { return q<[]>; } elsif (dis_uri_ctype_match (ExpandedURI q, $vt, %opt)) { return q<{}>; } } return undef; } # dispm_get_value =item $code = dispm_const_value (resource => $const, %opt) Returns a code fragment corresponding to the vaue of C<$const>. =cut sub dispm_const_value (%) { my %opt = @_; my $for = [keys %{$opt{resource}->{For}}]->[0]; local $opt{'For+'} = [keys %{$opt{resource}->{'For+'}||{}}]; my $value = dispm_get_value (%opt, ExpandedURI q => ExpandedURI q, ExpandedURI q => $opt{resource} ->{ExpandedURI q}, For => $for); valid_err q, node => $opt{resource}->{src} unless defined $value; return $value; } # dispm_const_value =item $code = dispm_const_value_sub (resource => $const, %opt) Returns a code fragment to declare and define a constant function corresponding to the definition of C<$const>. =cut sub dispm_const_value_sub (%) { my %opt = @_; my $value = dispm_const_value (%opt); my $name = $opt{resource}->{ExpandedURI q}; my $pc = $State->{ExpandedURI q} ->{$State->{Module}->{$State->{module}} ->{ExpandedURI q}} ->{ExpandedURI q} ||= {}; valid_err qq, node => $opt{resource}->{src} if defined $pc->{$name}->{resource}->{Name}; $pc->{$name} = { name => $name, resource => $opt{resource}, package => $State->{ExpandedURI q}, }; return perl_sub (name => $name, prototype => '', code => $value); } # dispm_const_value_sub =item $code = dispm_const_group (resource => $const_group, %opt) Returns a code fragment to define a constant value group. =cut sub dispm_const_group (%) { my %opt = @_; my $name = $opt{resource}->{ExpandedURI q}; for my $cg (values %{$opt{resource}->{ExpandedURI q}}) { if (defined $cg->{ExpandedURI q}) { valid_err (qq{"$name"."$cg->{ExpandedURI q}": }. qq{Nesting constant group not supported}, node => $cg->{src}); } } my $result = ''; my @cname; if (length $name) { if (defined $opt{ExpandedURI q}->{$name}) { valid_err qq, node => $opt{resource}->{src}; } $opt{ExpandedURI q}->{$name} = \@cname; } my $pc = $State->{ExpandedURI q} ->{$State->{Module}->{$State->{module}} ->{ExpandedURI q}} ->{ExpandedURI q} ||= {}; valid_err qq, node => $opt{resource}->{src} if defined $pc->{$name}->{resource}->{Name}; $pc->{$name} = { name => $name, resource => $opt{resource}, member => \@cname, }; for my $cv (values %{$opt{resource}->{ExpandedURI q}}) { next unless defined $cv->{ExpandedURI q}; #$result .= dispm_const_value_sub (%opt, resource => $cv); push @cname, $cv->{ExpandedURI q}; } return $result; } # dispm_const_group =item $desc = dispm_muf_description (%opt, resource => $res) Gets a template for a resource. =cut sub dispm_muf_description (%) { my %opt = @_; my $key = $opt{ExpandedURI q} || ExpandedURI q; local $State->{Namespace} = $State->{Module}->{$opt{resource}->{parentModule}}->{nsBinding}; local $opt{For} = [keys %{$opt{resource}->{For}}]->[0]; local $opt{'For+'} = [keys %{$opt{resource}->{'For+'}||{}}]; my $def = dis_get_attr_node (%opt, parent => $opt{resource}->{src}, name => {uri => $key}, ContentType => ExpandedURI q); if ($def) { my $template = $def->value; $template =~ s/]+)>/dis_qname_to_uri ($1, %opt, node => $opt{resource} ->{src})/ge; $template =~ s/\s+/ /g; $template =~ s/^ //; $template =~ s/ $//; return $template; } $key = $opt{ExpandedURI q} || ExpandedURI q; my $template = ''; for $def (@{dis_get_elements_nodes (%opt, parent => $opt{resource}->{src}, name => {uri => $key}, ContentType => ExpandedURI q, defaultContentType => ExpandedURI q)}) { $template .= disdoc2text ($def->value, %opt, node => $def); } $template =~ s/\s+/ /g; $template =~ s/^ //; $template =~ s/ $//; return $template; } # dispm_muf_description =item $code = disperl_to_perl (node => $node, %opt) Converts a C node to a Perl code fragment. =cut sub disperl_to_perl (%) { my %opt = @_; my $code = ''; for (@{$opt{node}->child_nodes}) { next unless $_->node_type eq '#element'; next unless dis_node_for_match ($_, $opt{For}, %opt); my $et = dis_element_type_to_uri ($_->local_name, %opt, node => $_); if ($et eq ExpandedURI q) { my $cn = $_->value; if ($cn =~ /^((?>(?!\.)$RegQNameChar)*)\.($RegQNameChar+)$/o) { my ($cls, $constn) = ($1, $2); if (length $cls) { my $clsu = dis_typeforqnames_to_uri ($cls, %opt, use_default_namespace => 1, node => $_); $cls = $State->{Type}->{$clsu}; valid_err qq must be defined>, node => $_ unless defined $cls->{Name}; } else { $cls = $State->{ExpandedURI q}; valid_err q, node => $_ unless defined $cls->{Name}; } my $const = $cls->{ExpandedURI q}->{$constn}; valid_err qq. qq{"$cls->{Name}" (<$cls->{URI}>)}, node => $_ unless defined $const->{Name}; $code .= perl_statement perl_assign perl_var (type => '$', local_name => 'r') => dispm_const_value (resource => $const); } else { valid_err q, node => $_; } } elsif ($et eq ExpandedURI q) { my $v = dispm_get_value (%opt, node => $_); $code .= perl_statement perl_assign perl_var (type => '$', local_name => 'r') => $v; } elsif ($et eq ExpandedURI q or $et eq ExpandedURI q or $et eq ExpandedURI q) { my $uri = dis_qname_to_uri ($_->value, %opt, node => $_, use_default_namespace => 1); $code .= perl_statement perl_assign perl_var (type => '$', local_name => 'r') => '$self->{'.(ExpandedURI q). '}->{'.(perl_literal $uri).'}'; if ($et eq ExpandedURI q) { $code .= perl_if 'defined $r', perl_code (q{$r = ($r)}, %opt, node => $_); } elsif ($et eq ExpandedURI q) { $code .= perl_if 'defined $r', perl_code (q{$r = ($r)}, %opt, node => $_); } } elsif ($et eq ExpandedURI q) { my $uri = dis_qname_to_uri ($_->value, %opt, node => $_, use_default_namespace => 1); my $chk = dis_get_attr_node (%opt, parent => $_, name => 'CheckReadOnly'); if ($chk and $chk->value) { my $for1 = $opt{For} || ExpandedURI q; unless (dis_uri_for_match (ExpandedURI q, $for1, node => $_)) { $for1 = ExpandedURI q; } $code .= perl_if q[$self->{].(perl_literal ExpandedURI q). q[}->{].(perl_literal ExpandedURI q). q[}], perl_statement dispm_perl_throws (%opt, class_for => $for1, class => ExpandedURI q, type => 'NO_MODIFICATION_ALLOWED_ERR', subtype => ExpandedURI q); } $code .= perl_statement perl_assign '$self->{'.(ExpandedURI q). '}->{'.(perl_literal $uri).'}' => perl_var (type => '$', local_name => 'given'); } elsif ($et eq ExpandedURI q) { my $memref = $_->value; my $mem = dispm_memref_to_resource ($memref, %opt, node => $_, return_method_returner => 1, use_default_type_resource => $State->{ExpandedURI q}, ## ISSUE: Reference in a resource that is ## referred from another resource might ## not be interpreted correctly. ); ## ISSUE: It might be required to detect a loop $code .= dispm_get_code (%opt, resource => $mem, For => [keys %{$mem->{For}}]->[0], 'For+' => [keys %{$mem->{'For+'}||{}}], ExpandedURI q => ExpandedURI q); } elsif ($et eq ExpandedURI q) { my ($cls, $type, $subtype) = dispm_xcref_to_resources ($_->value, %opt, node => $_); ## TODO: Parameter my %xparam; for ( ExpandedURI q, ExpandedURI q, ExpandedURI q, ExpandedURI q, ) { $xparam{$_} = $opt{$_} if defined $opt{$_}; } $code .= perl_statement dispm_perl_throws (%opt, class_resource => $cls, type_resource => $type, subtype_resource => $subtype, xparam => \%xparam); } elsif ($et eq ExpandedURI q) { my $cprop = dis_get_attr_node (%opt, parent => $_, name => {uri => ExpandedURI q}); my $propvalue; if ($cprop) { my $cpropuri = dis_qname_to_uri ($cprop->value, use_default_namespace => 1, %opt, node => $cprop); my $prop; if ($opt{ExpandedURI q}) { if (ref $opt{ExpandedURI q} eq 'HASH') { $prop = $opt{ExpandedURI q}; if (defined $prop->{$cpropuri}) { $propvalue = $prop->{$cpropuri}; } else { $propvalue = ''; } } else { $prop = dis_get_attr_node (%opt, parent => $opt{ExpandedURI q}, name => {uri => $cpropuri}); if ($prop) { $propvalue = $prop->value; } else { $propvalue = ''; } } } else { valid_err q, node => $_; } } else { valid_err q, node => $_; } my $selcase; for my $case (@{$_->child_nodes}) { next unless $case->node_type eq '#element'; next unless dis_node_for_match ($case, $opt{For}, %opt); my $et = dis_element_type_to_uri ($case->local_name, %opt, node => $case); if ($et eq ExpandedURI q) { my $val = dis_get_attr_node (%opt, parent => $case, name => 'Value', ContentType => ExpandedURI q, defaultContentType => ExpandedURI q); if ($val and $val->value eq $propvalue) { $selcase = $case; last; } elsif ($propvalue eq '' and (not $val or not $val->value)) { $selcase = $case; last; } } elsif ($et eq ExpandedURI q) { $selcase = $case; last; } elsif ({ ExpandedURI q => 1, }->{$et}) { # } else { valid_err qq not allowed here>, node => $case; } } if ($selcase) { my $lcode = perl_code ($selcase->value, %opt, node => $selcase); if ($opt{is_inline}) { $code .= $lcode; } else { $code .= perl_code_source ($lcode, %opt, node => $selcase); } } } elsif ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$et}) { # } else { valid_err qq not supported>, node => $opt{node}; } } my $val = $opt{node}->value; if (defined $val and length $val) { my $lcode = perl_code ($val, %opt); if ($opt{is_inline}) { $code .= $lcode; } else { $code .= perl_code_source ($lcode, %opt); } } return $code; } # disperl_to_perl =item $res = dispm_memref_to_resource ($memref, %opt) Converts a C (a reference to a class member, i.e. either method, attribute, attribute getter or attribute setter) to a resource. =cut sub dispm_memref_to_resource ($%) { my ($memref, %opt) = @_; my ($clsq, $memq) = split /\./, $memref, 2; unless (defined $memq) { valid_err qq<"$memref": Member name required>. node => $opt{node}; } elsif ($memq =~ /:/) { valid_err qq<"$memref": Prefixed member name not supported>, node => $opt{node}; } ## Class my $cls; my $clsuri; if ($clsq eq '') { if (defined $opt{use_default_type_resource}->{Name}) { $cls = $opt{use_default_type_resource}; $clsuri = $cls->{URI}; } elsif ($opt{use_default_type}) { $clsuri = $opt{use_default_type}; } else { $clsuri = dis_typeforqnames_to_uri ($clsq, use_default_namespace => 1, %opt); } } else { $clsuri = dis_typeforqnames_to_uri ($clsq, use_default_namespace => 1, %opt); } unless ($cls) { $cls = $State->{Type}->{$clsuri}; valid_err qq must be defined>, node => $opt{node} unless defined $cls->{Name}; } ## Method or attribute my $memname = $memq; my $mem; for (values %{$cls->{ExpandedURI q}||{}}) { if (defined $_->{Name} and $_->{Name} eq $memname) { $mem = $_; last; } } if ($mem) { if ($opt{return_method_returner}) { if (defined $mem->{ExpandedURI q}->{Name}) { $mem = $mem->{ExpandedURI q}; } elsif (defined $mem->{ExpandedURI q}->{Name}) { $mem = $mem->{ExpandedURI q}; } else { valid_err qq{Neither "return" nor "getter" is defined for }. qq{the class "$cls->{Name}" <$cls->{URI}>}, node => $opt{node}; } } } elsif ($memname =~ s/^([gs]et)(?=.)//) { my $gs = $1; $memname = lcfirst $memname; my $memp; for (values %{$cls->{ExpandedURI q}||{}}) { if (defined $_->{Name} and $_->{Name} eq $memname) { $memp = $_; last; } } if ($memp) { if ($gs eq 'set') { $mem = $memp->{ExpandedURI q}; unless (defined $mem->{Name}) { valid_err qq{Setter for "$memp->{Name}" <$memp->{URI}> is not defined}, node => $opt{node}; } } else { $mem = $memp->{ExpandedURI q}; unless (defined $mem->{Name}) { valid_err qq{Getter for "$memp->{Name}" <$memp->{URI}> is not defined}, node => $opt{node}; } } } } valid_err qq is not defined>, node => $opt{node} unless defined $mem->{Name}; return $mem; } # dispm_memref_to_resource =item ($clsres, $coderef, $subcoderef) = dispm_xcref_to_resources ($xcref, %opt) Converts a "DOMMain:XCodeRef" (exception or warning code reference) to its "resource" objects. =over 4 =item $clsres The resource object for the exception or warning class or interface identified by the XCodeRef. =item $coderef The resource object for the exception or warning code identified by the XCodeRef. =item $subcoderef The resource object for the exception or warning code idnetified by the XCodeRef, if any. If the XCodeRef identifies no subtype resource, an C is returned as C<$subcodref>. =back =cut sub dispm_xcref_to_resources ($%) { my ($xcref, %opt) = @_; my $q; my $constq; my $subtypeq; if (ref $xcref) { ($q, $constq, $subtypeq) = @$xcref; } else { ($q, $constq, $subtypeq) = split /\./, $xcref, 3; } my $clsuri; my $cls; my $consturi; my $const; my $subtypeuri; my $subtype; if (defined $constq and not defined $subtypeq) { $clsuri = dis_typeforqnames_to_uri ($q, use_default_namespace => 1, %opt); $cls = $State->{Type}->{$clsuri}; valid_err qq{Exception/warning class definition for }. qq{<$clsuri> is required}, node => $opt{node} unless defined $cls->{Name}; my ($consttq, $constfq) = split /\|\|/, $constq, 2; if (defined $constfq) { if ($consttq !~ /:/) { valid_err qq<"$constq": Unprefixed exception code QName must >. q, node => $opt{node}; } else { $consturi = dis_typeforqnames_to_uri ($consttq.'::'.$constfq, use_default_namespace => 1, %opt); } } else { if ($consttq !~ /:/) { $consturi = $consttq; CONSTCLS: { for (values %{$cls->{ExpandedURI q}}) { if (defined $_->{Name} and $_->{Name} eq $consturi) { $const = $_; last CONSTCLS; } } valid_err qq{Exception/warning code "$consturi" must be }. qq{defined in the exception/warning class }. qq{<$clsuri>}, node => $opt{node}; } } else { $consturi = dis_typeforqnames_to_uri ($consttq.'::'.$constfq, use_default_namespace => 1, %opt); } } unless ($const) { CONSTCLS: { for (values %{$cls->{ExpandedURI q}}) { if (defined $_->{Name} and $_->{URI} and $_->{URI} eq $consturi) { $const = $_; last CONSTCLS; } } valid_err qq{Exception/warning code <$consturi> must be }. qq{defined in the exception/warning class }. qq{<$clsuri>}, node => $opt{node}; } } } else { ## By code/subtype QName $subtypeq = $q unless defined $constq; $subtypeuri = dis_typeforqnames_to_uri ($subtypeq, use_default_namespace => 1, %opt); $subtype = $State->{Type}->{$subtypeuri}; valid_err qq{Exception/warning code/subtype <$subtypeuri> must }. qq{be defined}, node => $opt{node} unless defined $subtype->{Name} and defined $subtype->{ExpandedURI q}; if ($subtype->{ExpandedURI q} eq ExpandedURI q) { $const = $subtype->{ExpandedURI q}; $cls = $subtype->{ExpandedURI q}; } elsif ($subtype->{ExpandedURI q} eq ExpandedURI q) { $const = $subtype; $subtype = undef; $cls = $const->{ExpandedURI q}; } else { valid_err qq{Type of <$subtypeuri> must be either }. q{"ManakaiDOM:Const" or }. q{"ManakaiDOM:ExceptionOrWarningSubType"}, node => $opt{node}; } } return ($cls, $const, $subtype); } # dispm_xcref_to_resources =item $hash = dispm_collect_hash_prop_value ($resource, $propuri, %opt) Get property values from a resource and its superclasses (Cs - Cs are not checked). =cut our $DispmCollectHashPropValueDepth = 0; sub dispm_collect_hash_prop_value ($$%) { my ($res, $propu, %opt) = @_; my %r; local $DispmCollectHashPropValueDepth = $DispmCollectHashPropValueDepth + 1; return {} if $DispmCollectHashPropValueDepth == 10; for (@{$res->{ISA}||[]}) { %r = (%{dispm_collect_hash_prop_value ($State->{Type}->{$_}, $propu, %opt)}, %r); } %r = (%r, %{$res->{$propu}||{}}); \%r; } # dispm_collect_hash_prop_value =back =cut ## Outputed module and "For" my $mf = dis_get_module_uri (module_name => $Opt{module_name}, module_uri => $Opt{module_uri}, For => $Opt{For}); $State->{DefaultFor} = $mf->{For}; $State->{module} = $mf->{module}; our $result = ''; valid_err (qq{Perl module <$State->{module}> not defined for <$State->{DefaultFor}>}, node => $State->{Module}->{$State->{module}}->{src}) unless $State->{Module}->{$State->{module}} ->{ExpandedURI q}; $State->{ExpandedURI q} = 'main'; my $header = "#!/usr/bin/perl \n"; $header .= perl_comment q . "\n" . q<"> . $Opt{file_name} . q<" at > . rfc3339_date (time) . qq<.\n> . q; $header .= perl_comment qq{Module <$State->{module}>}; $header .= perl_comment qq{For <$State->{DefaultFor}>}; $header .= perl_statement q; $header .= perl_change_package (full_name => $State->{Module}->{$State->{module}} ->{ExpandedURI q}); $header .= perl_statement perl_assign perl_var (type => '$', local_name => 'VERSION', scope => 'our') => perl_literal version_date time if $Opt{outputModuleVersion}; ## -- Classes my %opt; for my $pack (values %{$State->{Module}->{$State->{module}} ->{ExpandedURI q}||{}}) { next unless defined $pack->{Name}; if ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$pack->{ExpandedURI q}}) { ## Package name and version $result .= perl_change_package (full_name => $pack->{ExpandedURI q}); $result .= perl_statement perl_assign perl_var (type => '$', local_name => 'VERSION', scope => 'our') => perl_literal version_date time; ## Inheritance ## TODO: IF "isa" should be expanded my $isa = $pack->{ExpandedURI q} || []; for (@$isa) { $State->{Module}->{$State->{module}} ->{ExpandedURI q}->{$_} ||= 1; } $State->{ExpandedURI q} ->{$pack->{ExpandedURI q}} = -1; for my $uri (@{$pack->{ISA}||[]}, @{$pack->{Implement}||[]}) { my $ipack = $State->{Type}->{$uri}; if (defined $ipack->{ExpandedURI q} and $ipack->{ExpandedURI q} ne $pack->{ExpandedURI q}) { push @$isa, $ipack->{ExpandedURI q}; if ($ipack->{ExpandedURI q} eq ExpandedURI q) { $State->{ExpandedURI q} ->{$ipack->{ExpandedURI q}} ||= 1; } } else { impl_msg ("Inheriting package name for <$uri> not defined", node => $pack->{src}) if $Opt{verbose}; } } $isa = array_uniq $isa; $result .= perl_inherit $isa; $State->{ExpandedURI q}->{$_} ||= $pack->{src} || 1 for @$isa; ## Role my $role = dispm_collect_hash_prop_value ($pack, ExpandedURI q, %opt); my $feature; for (values %$role) { my $roleres = $State->{Type}->{$_->{Role}}; my $compatres; $compatres = $State->{Type}->{$_->{compat}} if defined $_->{compat}; valid_err qq{Perl package name for interface <$_->{Role}> must be defined}, node => $roleres->{src} unless defined $roleres->{ExpandedURI q}; valid_err qq{Perl package name for class <$_->{compat}> must be defined}, node => $compatres->{src} if $compatres and not defined $compatres->{ExpandedURI q}; if ({ dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, (my $ev = dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt)) => 1, }->{$_->{Role}}) { unless ($feature) { $feature = {}; for (keys %{dispm_collect_hash_prop_value ($pack, ExpandedURI q, %opt)}) { my @f = ([$State->{Type}->{$_}, [], 1]); while (defined (my $f = shift @f)) { my $version = $f->[0]->{ExpandedURI q}; $version = '' unless defined $version; $f->[0]->{ExpandedURI q} = length $version ? $f->[0]->{ExpandedURI q} ? 1 : 0 : 0; for my $fname (keys %{$f->[0] ->{ExpandedURI q}}) { $feature->{$fname}->{$version} = 1 #= $f->[0]->{ExpandedURI q} ? 0 : 1 if $f->[2]; unless ($feature->{$fname}->{$version}) { $feature->{$_->[0]}->{$_->[1]} = 0 for @{$f->[1]}; } } push @f, map {[$State->{Type}->{$_}, ($f->[2] ? [@{$f->[1]}, map {[$_, $version]} keys %{$f->[0] ->{ExpandedURI q}}] : $f->[1]), $f->[2]]} @{$f->[0]->{ISA}||[]}; push @f, map {[$State->{Type}->{$_}, ($f->[2] ? [@{$f->[1]}, map {[$_, $version]} keys %{$f->[0] ->{ExpandedURI q}}] : $f->[1]), 0]} keys %{$f->[0]->{ExpandedURI q}||{}} if not $f->[0]->{ExpandedURI q}; } } } my %f = ( packageName => $pack->{ExpandedURI q}, feature => $feature, ); if ($_->{Role} eq $ev) { my @p = ($pack); my %pu; while (defined (my $p = shift @p)) { if ($p->{ExpandedURI q} eq ExpandedURI q) { $f{eventType}->{$p->{Name}} = 1; } $f{eventType}->{$_} = 1 for keys %{$p->{ExpandedURI q}||{}}; $pu{defined $p->{URI} ? $p->{URI} : ''} = 1; push @p, grep {!$pu{defined $_->{URI} ? $_->{URI} : ''}} map {$State->{Type}->{$_}} (@{$p->{ISA}||[]}, @{$p->{Implement}||[]}); } } $result .= perl_statement (($compatres ? perl_var (type => '$', package => $compatres ->{ExpandedURI q}, local_name => 'Class'). '{'.(perl_literal ($f{packageName})).'} = ' : ''). perl_var (type => '$', package => $roleres ->{ExpandedURI q}, local_name => 'Class'). '{'.(perl_literal ($f{packageName})).'} = '. perl_literal \%f); } elsif ({ dis_typeforuris_to_uri (ExpandedURI q, ExpandedURI q, %opt) => 1, }->{$_->{Role}}) { $result .= perl_statement 'push @org::w3c::dom::DOMImplementationSourceList, '. perl_literal ($pack->{ExpandedURI q}); } else { valid_err qq{Role <$_->{Role}> not supported}, $_->{node}; } } ## Members if ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$pack->{ExpandedURI q}}) { local $State->{ExpandedURI q} = $pack; local $opt{ExpandedURI q} = $pack->{ExpandedURI q}; ## -- Variables for my $var (values %{$pack->{ExpandedURI q}}) { next unless defined $var->{Name}; my $default = dispm_get_value (%opt, resource => $var, ExpandedURI q => ExpandedURI q, ExpandedURI q => 1, ExpandedURI q => $var->{ExpandedURI q}); my $v = perl_var (type => $var->{ExpandedURI q}, scope => (($var->{ExpandedURI q} =~ /::/ or (defined $default and index ($default, $var->{ExpandedURI q}) > -1)) ? undef : 'our'), local_name => $var->{ExpandedURI q}); if (defined $default and length $default) { if (not $var->{ExpandedURI q} =~ /::/ and index ($default, $var->{ExpandedURI q}) > -1) { $result .= perl_statement 'our '.$v; } $result .= perl_statement perl_assign $v => $default; } else { $result .= perl_statement $v; } } ## -- Subroutines for my $method (values %{$pack->{ExpandedURI q}}) { next unless defined $method->{Name}; if ($method->{ExpandedURI q} eq ExpandedURI q) { local $opt{ExpandedURI q} = $method->{ExpandedURI q}; local $opt{ExpandedURI q} = $method; my $proto = '$'; my @param = ('$self'); my $param_norm = ''; my $param_opt = 0; my $named_param = 0; my %param_replace; my $for = [keys %{$method->{For}}]->[0]; local $opt{'For+'} = [keys %{$method->{'For+'}||{}}]; for my $param (@{$method->{ExpandedURI q}||[]}) { my $atype = $param->{ExpandedURI q}; if ($param->{ExpandedURI q}) { $proto .= ';' unless $param_opt; $param_opt++; } my $is_np = dis_get_attr_node (%opt, parent => $param->{src}, name => {uri => ExpandedURI q}); if ($named_param) { if (not $is_np or not $is_np->value) { valid_err (q, node => $param->{src}); } } else { if ($is_np and $is_np->value) { $named_param = 1; $proto .= '%'; push @param, '%opt'; } } my $param_var; if (dis_uri_ctype_match (ExpandedURI q, $atype, %opt)) { if ($named_param) { valid_err (qq. q, node => $param->{src}); } $proto .= '@'; push @param, $param_var = '@'.$param->{ExpandedURI q}; } elsif (dis_uri_ctype_match (ExpandedURI q, $atype, %opt)) { if ($named_param) { valid_err (qq. q, node => $param->{src}); } $proto .= '%'; push @param, $param_var = '%'.$param->{ExpandedURI q}; } else { unless ($named_param) { $proto .= '$'; push @param, $param_var = '$'.$param->{ExpandedURI q}; } else { $param_var = '$opt{' . dis_camelCase_to_underscore_name ($param->{ExpandedURI q}) . '}'; } $param_replace{'$'.$param->{ExpandedURI q}} = $param_var; } my $nin = dis_get_attr_node (%opt, parent => $param->{ExpandedURI q}, name => {uri => ExpandedURI q}, ); if ($nin and $nin->value) { ## No input normalizing } else { my $nm = dispm_get_code (%opt, resource => $State->{Type}->{$atype}, ExpandedURI q => ExpandedURI q, For => $for, ExpandedURI q => 1, ExpandedURI q => $param->{ExpandedURI q}); if (defined $nm) { $nm =~ s/\$INPUT\b/$param_var/g; ## NOTE: "Perl:Array" or "Perl:Hash" is not supported. $param_norm .= $nm; } } } my $code = dispm_get_code (%opt, resource => $method->{ExpandedURI q}, For => $for, ExpandedURI q => ExpandedURI q); if (defined $code) { my $my = perl_statement ('my ('.join (", ", @param). ') = @_'); my $return = defined $method->{ExpandedURI q}->{Name} ? $method->{ExpandedURI q} : undef; for (keys %param_replace) { $code =~ s/\Q$_\E\b/$param_replace{$_}/g; } if ($return->{ExpandedURI q} ? 1 : 0) { my $default = dispm_get_value (%opt, resource => $return, ExpandedURI q => ExpandedURI q, ExpandedURI q => 1, ExpandedURI q => $return->{ExpandedURI q}); $code = $my . $param_norm . perl_statement (defined $default ? 'my $r = '.$default : 'my $r'). $code . "\n" . perl_statement ('$r'); } else { $code = $my . $code; } } else { ## Code not defined $code = perl_statement 'my $self = shift;'; $code .= perl_statement dispm_perl_throws class => ExpandedURI q, class_for => ExpandedURI q, type => 'NOT_SUPPORTED_ERR', subtype => ExpandedURI q, xparam => { ExpandedURI q => $pack->{ExpandedURI q}, ExpandedURI q => $method->{ExpandedURI q}, }; } if (length $method->{ExpandedURI q}) { $result .= perl_sub (name => $method->{ExpandedURI q}, code => $code, prototype => $proto); } else { $method->{ExpandedURI q} = perl_sub (name => '', code => $code, prototype => $proto); } } elsif ($method->{ExpandedURI q} eq ExpandedURI q) { local $opt{ExpandedURI q} = $method->{ExpandedURI q}; my $getter = $method->{ExpandedURI q}; valid_err qq{Getter for attribute "$method->{Name}" must be }. q{defined}, node => $method->{src} unless $getter; my $setter = defined $method->{ExpandedURI q}->{Name} ? $method->{ExpandedURI q} : undef; my $for = [keys %{$method->{For}}]->[0]; local $opt{'For+'} = [keys %{$method->{'For+'}||{}}]; local $opt{ExpandedURI q} = 'get'; my $get_code = dispm_get_code (%opt, resource => $getter, For => $for, ExpandedURI q => ExpandedURI q); if (defined $get_code) { my $default = dispm_get_value (%opt, resource => $getter, ExpandedURI q => ExpandedURI q, ExpandedURI q => 1, ExpandedURI q => $getter->{ExpandedURI q}); $get_code = perl_statement (defined $default ? 'my $r = '.$default : 'my $r'). $get_code. "\n" . perl_statement ('$r'); } else { ## Get code not defined $get_code = perl_statement dispm_perl_throws class => ExpandedURI q, class_for => ExpandedURI q, type => 'NOT_SUPPORTED_ERR', subtype => ExpandedURI q, xparam => { ExpandedURI q => $pack->{ExpandedURI q}, ExpandedURI q => $method->{ExpandedURI q}, ExpandedURI q => 'get', }; } if ($setter) { local $opt{ExpandedURI q} = 'set'; my $set_code = dispm_get_code (%opt, resource => $setter, For => $for, ExpandedURI q => ExpandedURI q); if (defined $set_code) { my $nm = dispm_get_code (%opt, resource => $State->{Type} ->{$setter->{ExpandedURI q}}, ExpandedURI q => ExpandedURI q, For => $for, ExpandedURI q => 1); if (defined $nm) { $nm =~ s/\$INPUT\b/\$given/g; } else { $nm = ''; } $set_code = $nm . $set_code. "\n"; } else { ## Set code not defined $set_code = perl_statement dispm_perl_throws class => ExpandedURI q, class_for => ExpandedURI q, type => 'NOT_SUPPORTED_ERR', subtype => ExpandedURI q, xparam => { ExpandedURI q => $pack->{ExpandedURI q}, ExpandedURI q => $method->{ExpandedURI q}, ExpandedURI q => 'set', }; } $get_code = perl_if '@_ == 2', perl_statement ('my ($self, $given) = @_'). $set_code, perl_statement ('my ($self) = @_'). $get_code; } else { $get_code = perl_statement ('my ($self) = @_'). $get_code; } if (length $method->{ExpandedURI q}) { $result .= perl_sub (name => $method->{ExpandedURI q}, prototype => $setter ? '$;$' : '$', code => $get_code); } else { $method->{ExpandedURI q} = perl_sub (name => '', code => $get_code, prototype => $setter ? '$;$' : '$'); } } } # package method ## -- Constants for my $cg (values %{$pack->{ExpandedURI q}}) { next unless defined $cg->{Name}; $result .= dispm_const_group (resource => $cg); } # package const group for my $cv (values %{$pack->{ExpandedURI q}}) { next unless defined $cv->{Name}; $result .= dispm_const_value_sub (resource => $cv); } # package const value ## -- Error codes if ({ ExpandedURI q => 1, ExpandedURI q => 1, ExpandedURI q => 1, }->{$pack->{ExpandedURI q}}) { $result .= perl_sub name => '___error_def', prototype => '', code => perl_list { map { $_->{Name} => { ExpandedURI q => perl_code_literal dispm_const_value (%opt, resource => $_), description => dispm_muf_description (%opt, resource => $_), ($_->{ExpandedURI q} ? (ExpandedURI q => $_->{ExpandedURI q}, ExpandedURI q => $_->{ExpandedURI q}) : ()), ExpandedURI q => { map { $_->{NameURI} => { description => dispm_muf_description (%opt, resource => $_), ($_->{ExpandedURI q} ? (ExpandedURI q => $_->{ExpandedURI q}, ExpandedURI q => $_->{ExpandedURI q}) : ()), }, } grep {defined $_->{Name}} values %{$_->{ExpandedURI q}||{}} }, }, } grep {defined $_->{Name}} values %{$pack->{ExpandedURI q}||{}} }; } ## -- Operators my %ol; my %mtd; for (values %{$pack->{ExpandedURI q}||{}}) { next unless defined $_->{resource}->{Name}; if ($_->{resource}->{ExpandedURI q} =~ /^\#/) { if ($_->{operator} =~ /^[A-Z]+$/) { my $code = $_->{resource}->{ExpandedURI q}; $code =~ s/\bsub /sub $_->{operator} /; $result .= $code; $mtd{$_->{operator}} = 1; } else { $ol{$_->{operator}} = perl_code_literal $_->{resource} ->{ExpandedURI q}; } } else { if ($_->{operator} =~ /^[A-Z]+$/) { $mtd{$_->{operator}} = 1; $result .= perl_statement perl_assign perl_var (type => '*', local_name => $_->{operator}) => perl_var (type => '\&', local_name => $_->{resource} ->{ExpandedURI q}); } else { $ol{$_->{operator}} = $_->{resource}->{ExpandedURI q}; } } } if (keys %ol) { $ol{fallback} = 1; $ol{bool} ||= perl_code_literal 'sub () {1}'; $result .= perl_statement 'use overload '.perl_list %ol; } my $op2perl = { ExpandedURI q => { method_name => '___report_error', }, ExpandedURI q => { method_name => 'as_string', }, ExpandedURI q => { method_name => 'new', }, ExpandedURI q => { method_name => 'clone', }, }; for (values %{$pack->{ExpandedURI q}||{}}) { next unless defined $_->{resource}->{Name}; if ($op2perl->{$_->{operator}}) { if ($_->{resource}->{ExpandedURI q} =~ /^\#/) { my $code = $_->{resource}->{ExpandedURI q}; $code =~ s/\bsub /sub $op2perl->{$_->{operator}}->{method_name} /; $result .= $code; } else { $result .= perl_statement perl_assign perl_var (type => '*', local_name => $op2perl->{$_->{operator}} ->{method_name}) => perl_var (type => '\&', local_name => $_->{resource} ->{ExpandedURI q}); } if ($_->{operator} eq ExpandedURI q) { $result .= perl_statement perl_assign perl_var (type => '*', local_name => 'stringify') => perl_var (type => '\&', local_name => $op2perl->{$_->{operator}} ->{method_name}); } } else { valid_err qq{Operator <$_->{operator}> is not supported}, node => $_->{resource}->{src}; } } } # Class } # root object } ## -- Variables for my $var (values %{$State->{Module}->{$State->{module}} ->{ExpandedURI q}}) { next unless defined $var->{Name}; my $default = dispm_get_value (%opt, resource => $var, ExpandedURI q => ExpandedURI q, ExpandedURI q => 1, ExpandedURI q => $var->{ExpandedURI q}); my $v = perl_var (type => $var->{ExpandedURI q}, scope => ($var->{ExpandedURI q} =~ /::/ ? undef : 'our'), local_name => $var->{ExpandedURI q}); if (defined $default and length $default) { $result .= perl_statement perl_assign $v => $default; } else { $result .= perl_statement $v; } if ($var->{ExpandedURI q}) { $State->{ExpandedURI q} ->{$State->{Module}->{$State->{module}} ->{ExpandedURI q}} ->{ExpandedURI q}->{$v} = 1; ## NOTE: Variable name uniqueness is assured in dis.pl. } } ## Constant exportion { my @xok; my $xr = ''; my $cg = $State->{ExpandedURI q} ->{$State->{Module}->{$State->{module}} ->{ExpandedURI q}} ->{ExpandedURI q}; my %etag; for (keys %$cg) { $etag{$_} = $cg->{$_}->{member}; } $xr .= perl_statement perl_assign perl_var (type => '%', local_name => 'EXPORT_TAG', scope => 'our') => '('.(perl_list %etag).')' if keys %etag; my $c = $State->{ExpandedURI q} ->{$State->{Module}->{$State->{module}} ->{ExpandedURI q}} ->{ExpandedURI q}; if (keys %$c) { push @xok, keys %$c; $xr .= join '', map {perl_statement "sub $_ ()"} keys %$c; my $al = perl_literal {map {$_ => $c->{$_}->{package}.'::'.$_} keys %$c}; my $AL = '$al'; my $ALD = '$AUTOLOAD'; my $XL = '$Exporter::ExportLevel'; my $SELF = '$self'; my $ARGS = '@_'; my $IT = '$_'; my $REF = '\\'; my $NONAME = '\W'; $xr .= qq{ sub AUTOLOAD { my $AL = our $ALD; $AL =~ s/.+:://; if ($al -> {$AL}) { no strict 'refs'; *{$ALD} = $REF &{$al -> {$AL}}; goto &{$ALD}; } else { require Carp; Carp::croak (qq); } } sub import { my $SELF = shift; if ($ARGS) { local $XL = $XL + 1; $SELF->SUPER::import ($ARGS); for (grep {not /$NONAME/} $ARGS) { eval qq{$IT}; } } } }; } for (keys %{$State->{ExpandedURI q} ->{$State->{Module}->{$State->{module}} ->{ExpandedURI q}} ->{ExpandedURI q}}) { push @xok, $_; } if (@xok) { $xr .= perl_statement perl_assign perl_var (type => '@', local_name => 'EXPORT_OK', scope => 'our') => '('.(perl_list @xok).')'; } if ($xr) { $result .= perl_change_package (full_name => $State->{Module} ->{$State->{module}} ->{ExpandedURI q}); $result .= $xr; $result .= perl_statement 'use Exporter'; $result .= perl_statement 'push our @ISA, "Exporter"'; } } ## Required modules $result .= dispm_package_declarations; my $begin = ''; for (keys %{$State->{Module}->{$State->{module}} ->{ExpandedURI q}||{}}) { next if $_ eq $State->{Module}->{$State->{module}} ->{ExpandedURI q}; $begin .= perl_statement ('require ' . $_); $State->{ExpandedURI q}->{$_} = -1; } $result = $begin . $result if $begin; ## Exception interfaces for my $p (keys %{$State->{ExpandedURI q}||{}}) { my $v = $State->{ExpandedURI q}->{$p}; if (ref $v or $v > 0) { $result .= perl_inherit ['Message::Util::Error'], $p; $State->{ExpandedURI q}->{$p} = -1; } } my @ref; for (keys %{$State->{ExpandedURI q}||{}}) { my $v = $State->{ExpandedURI q}->{$_}; if (ref $v or $v > 0) { push @ref, $_; } } $result .= "for (" . join (", ", map {'$'.$_.'::'} @ref) . ") {}" if @ref; $result = $header . $result . perl_statement 1; output_result $result; =head1 BUGS Dynamic change for namespace binding, current "For", ... is poorly supported - it a code or element refers another code or element in the same or different source file, then their own bindings, not the former code or element's, should be used for resolution. The current implementation does not do so perfectly. So authors of "dis" files are encouraged not to bind the same namespace prefix to different namespace URIs and to prefer prefixed QName. =head1 SEE ALSO L - "dis" common utility. L - The definition for the "dis" format. L - The definition for the "dis" Perl-specific vocabulary. =head1 LICENSE Copyright 2004-2005 Wakaba . All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # $Date: 2006/02/26 14:32:38 $