File Coverage

blib/lib/Treex/PML/Schema/Copy.pm
Criterion Covered Total %
statement 89 113 78.7
branch 27 44 61.3
condition 12 25 48.0
subroutine 13 15 86.6
pod 3 3 100.0
total 144 200 72.0


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