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 9     9   50 use strict;
  9         15  
  9         268  
4 9     9   30 use warnings;
  9         13  
  9         354  
5              
6 9     9   35 use vars qw($VERSION);
  9         13  
  9         433  
7             BEGIN {
8 9     9   189 $VERSION='2.29'; # version template
9             }
10 9     9   35 no warnings 'uninitialized';
  9         13  
  9         381  
11 9     9   38 use Carp;
  9         12  
  9         557  
12 9     9   87 use Treex::PML::Schema::Constants;
  9         27  
  9         902  
13 9     9   59 use List::Util qw(first);
  9         18  
  9         556  
14 9     9   37 use base qw(Treex::PML::Schema::XMLNode);
  9         13  
  9         9850  
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 4 my ($copy,$opts)=@_;
21 1 50       7 return if $opts->{no_copy};
22 1         5 my $template_name = $copy->{template};
23 1         9 my $owner = _lookup_upwards($copy->{-parent},'template',$template_name);
24 1 50       6 unless ($owner) {
25 0         0 die "Could not find template $template_name\n";
26 0         0 return;
27             }
28 1         3 my $template = $owner->{template}{$template_name};
29             # print STDERR "Copying $copy->{template} as $copy->{prefix}\n";
30              
31 1 50       6 if (ref $template->{type}) {
32 1         4 my $parent = $copy->{-parent};
33 1   50     5 my $prefix = $copy->{prefix} || '';
34 1   50     8 $parent->{type}||={};
35 1         4 my (@new_types, @new_templates);
36 1         3 foreach my $t (values(%{$template->{type}})) {
  1         4  
37 4         17 my $new = $template->copy_decl($t);
38 4         45 _apply_prefix($copy,$template,$prefix,$new);
39 4         17 my $new2 = $parent->copy_decl($new);
40 4         23 push @new_types, $new2;
41             }
42 1         4 foreach my $t (values(%{$template->{template}})) {
  1         6  
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         4 for my $t (@new_types) {
49 4         9 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     42 or exists $parent->{param}{$name};
      33        
      33        
55             # print STDERR "copying type $name into \n";
56 4         9 $t->{-name}=$name;
57 4         12 $parent->{type}{$name}=$t;
58             }
59 1         8 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   12 my ($parent, $what, $name)=@_;
74 3 100       14 if (ref($what) eq 'ARRAY') {
75 2         9 while ($parent) {
76             return $parent if
77 5 100   13   57 first { (ref($parent->{$_}) eq 'HASH') and exists($parent->{$_}{$name}) } @$what;
  13 100       58  
78 3         17 $parent = $parent->{-parent};
79             }
80             } else {
81 1         4 while ($parent) {
82 1 50 33     12 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   26 my ($copy,$template,$prefix,$type) = @_;
91 11 50       25 if (ref($type)) {
    0          
92 11 50       32 if (UNIVERSAL::isa($type,'HASH')) {
93 11 50 66     46 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         19 my $ref = $type->{type};
101 11 100 66     35 if (defined($ref) and length($ref)) {
102 2         14 my $owner = _lookup_upwards($type->{-parent},['type','derive','param'],$ref);
103 2 50 33     17 if (defined $owner and $owner==$template) {
104             # the type is defined exactly on the level of the template
105 2 100       11 if (exists $copy->{let}{$ref}) {
106 1         3 my $let = $copy->{let}{$ref};
107 1 50       4 if ($let->{type}) {
108             $type->{type}=$let->{type}
109 0         0 } else {
110 1         5 delete $type->{type};
111 1         3 foreach my $d (qw(list alt structure container sequence cdata choice constant)) {
112 8 50       20 if (exists $type->{$d}) {
113 0         0 delete $type->{$d};
114 0         0 last;
115             }
116             }
117 1         3 delete $type->{-decl};
118 1         3 delete $type->{-resolved};
119 1         4 foreach my $d (qw(list alt structure container sequence cdata choice constant)) {
120 6 100       15 if (exists $let->{$d}) {
121 1         7 $type->{$d} = $type->copy_decl($let->{$d});
122 1         7 $type->{-decl}=$d;
123 1         4 last;
124             }
125             }
126             }
127             } else {
128 1         5 $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         20 for my $d (qw(member attribute element)) {
136 29 100       61 if (ref($type->{$d})) {
137 3         6 _apply_prefix($copy,$template,$prefix,$_) for (values %{$type->{$d}});
  3         17  
138 3         7 return;
139             }
140             }
141 8         15 for my $d (qw(list alt structure container sequence)) {
142 36 100       76 if (ref($type->{$d})) {
143 3         14 _apply_prefix($copy,$template,$prefix,$type->{$d});
144 3         8 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__