File Coverage

blib/lib/Treex/PML/Schema/Copy.pm
Criterion Covered Total %
statement 25 113 22.1
branch 0 44 0.0
condition 0 25 0.0
subroutine 9 15 60.0
pod 3 3 100.0
total 37 200 18.5


line stmt bran cond sub pod time code
1             package Treex::PML::Schema::Copy;
2              
3 1     1   4 use strict;
  1         1  
  1         21  
4 1     1   3 use warnings;
  1         1  
  1         19  
5              
6 1     1   3 use vars qw($VERSION);
  1         0  
  1         31  
7             BEGIN {
8 1     1   11 $VERSION='2.21'; # version template
9             }
10 1     1   3 no warnings 'uninitialized';
  1         1  
  1         25  
11 1     1   3 use Carp;
  1         1  
  1         37  
12 1     1   4 use Treex::PML::Schema::Constants;
  1         0  
  1         77  
13 1     1   3 use List::Util qw(first);
  1         1  
  1         60  
14 1     1   3 use base qw(Treex::PML::Schema::XMLNode);
  1         1  
  1         745  
15              
16 0     0 1   sub get_decl_type { return(PML_COPY_DECL); }
17 0     0 1   sub get_decl_type_str { return('copy'); }
18              
19             sub simplify {
20 0     0 1   my ($copy,$opts)=@_;
21 0 0         return if $opts->{no_copy};
22 0           my $template_name = $copy->{template};
23 0           my $owner = _lookup_upwards($copy->{-parent},'template',$template_name);
24 0 0         unless ($owner) {
25 0           die "Could not find template $template_name\n";
26 0           return;
27             }
28 0           my $template = $owner->{template}{$template_name};
29             # print STDERR "Copying $copy->{template} as $copy->{prefix}\n";
30              
31 0 0         if (ref $template->{type}) {
32 0           my $parent = $copy->{-parent};
33 0   0       my $prefix = $copy->{prefix} || '';
34 0   0       $parent->{type}||={};
35 0           my (@new_types, @new_templates);
36 0           foreach my $t (values(%{$template->{type}})) {
  0            
37 0           my $new = $template->copy_decl($t);
38 0           _apply_prefix($copy,$template,$prefix,$new);
39 0           my $new2 = $parent->copy_decl($new);
40 0           push @new_types, $new2;
41             }
42 0           foreach my $t (values(%{$template->{template}})) {
  0            
43 0           my $new = $template->copy_decl($t);
44 0           _apply_prefix($copy,$template,$prefix,$new);
45 0           my $new2 = $parent->copy_decl($new);
46 0           push @new_templates, $new2;
47             }
48 0           for my $t (@new_types) {
49 0           my $name = $prefix.$t->{-name};
50             die "Type $name copied from $template_name already exists\n" if
51             exists $parent->{type}{$name}
52             or (exists $parent->{derive}{$name}
53             and $parent->{derive}{$name}{type} ne $name)
54 0 0 0       or exists $parent->{param}{$name};
      0        
      0        
55             # print STDERR "copying type $name into \n";
56 0           $t->{-name}=$name;
57 0           $parent->{type}{$name}=$t;
58             }
59 0           for my $t (@new_templates) {
60 0           my $name = $prefix.$t->{-name};
61             die "Template $name copied from $template_name already exists\n" if
62 0 0         exists $parent->{template}{$name};
63             # print STDERR "copying template $name\n";
64 0           $t->{-name}=$name;
65 0           $parent->{template}{$name}=$t;
66             }
67             }
68             }
69             # traverse declarations as long as there is one
70             # containing a hash key $what or one occurring in an array-ref $what
71             # with a Hash value containing the key $name
72             sub _lookup_upwards {
73 0     0     my ($parent, $what, $name)=@_;
74 0 0         if (ref($what) eq 'ARRAY') {
75 0           while ($parent) {
76             return $parent if
77 0 0   0     first { (ref($parent->{$_}) eq 'HASH') and exists($parent->{$_}{$name}) } @$what;
  0 0          
78 0           $parent = $parent->{-parent};
79             }
80             } else {
81 0           while ($parent) {
82 0 0 0       return $parent if (ref($parent->{$what}) eq 'HASH') and exists($parent->{$what}{$name});
83 0           $parent = $parent->{-parent};
84             }
85             }
86 0           return;
87             }
88              
89             sub _apply_prefix {
90 0     0     my ($copy,$template,$prefix,$type) = @_;
91 0 0         if (ref($type)) {
    0          
92 0 0         if (UNIVERSAL::isa($type,'HASH')) {
93 0 0 0       if (exists($type->{-name}) and $type->{-name} eq 'template') {
94             # hopefully a template
95 0 0         if ($type->{type}) {
96 0           _apply_prefix($copy,$template,$prefix,$_) for (values %{$type->{type}});
  0            
97             }
98 0           return;
99             }
100 0           my $ref = $type->{type};
101 0 0 0       if (defined($ref) and length($ref)) {
102 0           my $owner = _lookup_upwards($type->{-parent},['type','derive','param'],$ref);
103 0 0 0       if (defined $owner and $owner==$template) {
104             # the type is defined exactly on the level of the template
105 0 0         if (exists $copy->{let}{$ref}) {
106 0           my $let = $copy->{let}{$ref};
107 0 0         if ($let->{type}) {
108             $type->{type}=$let->{type}
109 0           } else {
110 0           delete $type->{type};
111 0           foreach my $d (qw(list alt structure container sequence cdata choice constant)) {
112 0 0         if (exists $type->{$d}) {
113 0           delete $type->{$d};
114 0           last;
115             }
116             }
117 0           delete $type->{-decl};
118 0           delete $type->{-resolved};
119 0           foreach my $d (qw(list alt structure container sequence cdata choice constant)) {
120 0 0         if (exists $let->{$d}) {
121 0           $type->{$d} = $type->copy_decl($let->{$d});
122 0           $type->{-decl}=$d;
123 0           last;
124             }
125             }
126             }
127             } else {
128 0           $type->{type} = $prefix.$ref; # do apply prefix
129             }
130             } else {
131 0           $type->{type} = $prefix.$ref; # do apply prefix
132             }
133             }
134             # traverse descendant type declarations
135 0           for my $d (qw(member attribute element)) {
136 0 0         if (ref($type->{$d})) {
137 0           _apply_prefix($copy,$template,$prefix,$_) for (values %{$type->{$d}});
  0            
138 0           return;
139             }
140             }
141 0           for my $d (qw(list alt structure container sequence)) {
142 0 0         if (ref($type->{$d})) {
143 0           _apply_prefix($copy,$template,$prefix,$type->{$d});
144 0           return;
145             }
146             }
147             }
148             } elsif (UNIVERSAL::isa($type,'ARRAY')) {
149 0           foreach my $d (@$type) {
150 0           _apply_prefix($copy,$template,$prefix,$d);
151             }
152             }
153             }
154              
155              
156             1;
157             __END__