|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Positron::Template;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = 'v0.1.3'; # VERSION  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Positron::Template - a DOM based templating system  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 VERSION  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 version v0.1.3  | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Positron::Template;  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $template = Positron::Template->new();  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $dom    = create_dom_tree();  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $data   = { foo => 'bar', baz => [ 1, 2, 3 ] };  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $result = $template->process($dom, $data);   | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
396226
 | 
 use v5.10;  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
47
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
576
 | 
    | 
| 
25
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
72
 | 
 use strict;  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
396
 | 
    | 
| 
26
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
66
 | 
 use warnings;  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
336
 | 
    | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
28
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
70
 | 
 use Carp;  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1121
 | 
    | 
| 
29
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
7410
 | 
 use Positron::Environment;  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
341
 | 
    | 
| 
30
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
20527
 | 
 use Positron::Expression;  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
570
 | 
    | 
| 
31
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
81
 | 
 use Scalar::Util qw(blessed);  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48025
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
34
 | 
11
 | 
 
 | 
 
 | 
  
11
  
 | 
  
0
  
 | 
125
 | 
     my ($class, %options) = @_;  | 
| 
35
 | 
11
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
273
 | 
     my $self = {  | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         opener => '{',  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         closer => '}',  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         dom => $options{dom} // undef,  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         environment => Positron::Environment->new($options{env} // undef, { immutable => 1 }) // undef,  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         handler => $options{handler} || _handler_for($options{dom}) // undef,  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         include_paths => ['.'],  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
43
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
60
 | 
     return bless ($self, $class);  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Stop writing these until need is shown  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub dom {  | 
| 
48
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($self, $dom) = @_;  | 
| 
49
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if (@_ == 1) {  | 
| 
50
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return $self->{'dom'};  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
52
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->{'dom'} = $dom;  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub add_include_paths {  | 
| 
57
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
0
  
 | 
13
 | 
     my ($self, @paths) = @_;  | 
| 
58
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     push @{$self->{'include_paths'}}, @paths;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub process {  | 
| 
63
 | 
141
 | 
 
 | 
 
 | 
  
141
  
 | 
  
0
  
 | 
23757
 | 
     my ($self, $dom, $data) = @_;  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # TODO: what if only one is passed? -> $self attributes  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # What if a HashRef is passed? -> new Environment object  | 
| 
66
 | 
141
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
973
 | 
     if (ref($dom) eq 'HASH' or blessed($dom) and $dom->isa('Positron::Environment')) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
67
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $data = $dom;  | 
| 
68
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $dom = $self->{'dom'};  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
70
 | 
141
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
325
 | 
     if (not $data) {  | 
| 
71
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $data = $self->{'environment'};  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
73
 | 
141
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
381
 | 
     if (ref($data) eq 'HASH') {  | 
| 
74
 | 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
655
 | 
         $data = Positron::Environment->new($data);  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
77
 | 
141
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
366
 | 
     if (not ref($dom)) {  | 
| 
78
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
53
 | 
         return $self->_process_text($dom, $data);  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Real DOM -> List of nodes  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
82
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
192
 | 
     my @nodes = ();  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
84
 | 
118
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
368
 | 
     $self->{'handler'} //= _handler_for($dom);  | 
| 
85
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
323
 | 
     @nodes = $self->_process_element($dom, $data);  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # DESTROY Handler?  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Many people know that they will get a single node here.  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # May as well not force them to unpack a list.  | 
| 
90
 | 
114
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1279
 | 
     return (wantarray) ? @nodes : $nodes[0];  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_text {  | 
| 
94
 | 
146
 | 
 
 | 
 
 | 
  
146
  
 | 
 
 | 
251
 | 
     my ($self, $string, $environment, $with_quants) = @_;  | 
| 
95
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
267
 | 
     my $string_finder = $self->_make_finder('$');  | 
| 
96
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
428
 | 
     my $last_changing_quant = undef;  | 
| 
97
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
166
 | 
     my $did_change = undef;  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # First $ sigils; the quantifier chomps whitespace around it.  | 
| 
99
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1286
 | 
     $string =~ s{  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         (\s*)  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $string_finder  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         (\s*)  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }{  | 
| 
104
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
354
 | 
         my ($ws_before, $sigil, $quant, $expr, $ws_after) = ($1, $2, $3, $4, $5);  | 
| 
105
 | 
81
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
225
 | 
         my $replacement = Positron::Expression::evaluate($expr, $environment) // '';  | 
| 
106
 | 
81
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
250
 | 
         if ($quant eq '-') {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             $ws_before = '';  | 
| 
108
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
             $ws_after = '';  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif ($quant eq '*') {  | 
| 
110
 | 
3
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
15
 | 
             $ws_before &&= ' ';  | 
| 
111
 | 
3
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
15
 | 
             $ws_after &&= ' ';  | 
| 
112
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
             if ($replacement eq '') {  | 
| 
113
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
                 $ws_before = ' '; $ws_after = '';  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
116
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
108
 | 
         $last_changing_quant = $quant;  | 
| 
117
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
90
 | 
         $did_change = 1;  | 
| 
118
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
263
 | 
         "$ws_before$replacement$ws_after";  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }xmseg;  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Next comments; the quantifier chomps whitespace around it.  | 
| 
121
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
361
 | 
     my $comment_finder = $self->_make_finder('#');  | 
| 
122
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1007
 | 
     $string =~ s{  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         (\s*)  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $comment_finder  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         (\s*)  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }{  | 
| 
127
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
158
 | 
         my ($ws_before, $sigil, $quant, $comment, $ws_after) = ($1, $2, $3, $4, $5);  | 
| 
128
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
47
 | 
         if ($quant eq '-') {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
129
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
             $ws_before = '';  | 
| 
130
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
             $ws_after = '';  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif ($quant eq '*') {  | 
| 
132
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
             $ws_before = ' ';  | 
| 
133
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
             $ws_after = '';  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
135
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
         $last_changing_quant = $quant;  | 
| 
136
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
         $did_change = 1;  | 
| 
137
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
         "$ws_before$ws_after";  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }xmseg;  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Next voider; the quantifier chomps whitespace around it.  | 
| 
140
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
325
 | 
     my $voider_finder = $self->_make_finder('~');  | 
| 
141
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
937
 | 
     $string =~ s{  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         (\s*)  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $voider_finder  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         (\s*)  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }{  | 
| 
146
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
         my ($ws_before, $sigil, $quant, undef, $ws_after) = ($1, $2, $3, $4, $5);  | 
| 
147
 | 
10
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
46
 | 
         if ($quant eq '-') {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
             $ws_before = '';  | 
| 
149
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
             $ws_after = '';  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif ($quant eq '*') {  | 
| 
151
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
             $ws_before = ' ';  | 
| 
152
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
             $ws_after = ' ';  | 
| 
153
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
             if ("$ws_before$ws_after" =~ m{\A \s+ \z}xms) {  | 
| 
154
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
                 $ws_before = ' '; $ws_after = '';  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
157
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
         $last_changing_quant = $quant;  | 
| 
158
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
         $did_change = 1;  | 
| 
159
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
         "$ws_before$ws_after";  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }xmseg;  | 
| 
161
 | 
146
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1408
 | 
     return $with_quants? ($string, $did_change, $last_changing_quant) : $string;  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_element {  | 
| 
165
 | 
525
 | 
 
 | 
 
 | 
  
525
  
 | 
 
 | 
718
 | 
     my ($self, $node, $environment) = @_;  | 
| 
166
 | 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
723
 | 
     my $handler = $self->{'handler'};  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
168
 | 
525
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1103
 | 
     if (not ref($node)) {  | 
| 
169
 | 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
234
 | 
         return $self->_process_text($node, $environment);  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # check for assignments  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # create a modified environment if some are detected  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # proceed as normal  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Evaluate structure sigils  | 
| 
177
 | 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1548
 | 
     my ($sigil, $quant, $tail) = $self->_get_structure_sigil($node);  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Have sigil, evaluate  | 
| 
180
 | 
423
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
1309
 | 
     $sigil //= ''; # for 'eq'  | 
| 
181
 | 
423
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
3102
 | 
     if ($sigil eq '@') {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
         return $self->_process_loop($node, $environment, $sigil, $quant, $tail);  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($sigil ~~ ['?', '!']) {  | 
| 
184
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
         return $self->_process_condition($node, $environment, $sigil, $quant, $tail);  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($sigil eq '|') {  | 
| 
186
 | 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
180
 | 
         return $self->_process_switch($node, $environment, $sigil, $quant, $tail);  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($sigil eq '/') {  | 
| 
188
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
         return $self->_process_structure_comment($node, $environment, $sigil, $quant, $tail);  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($sigil ~~ ['.', ',']) {  | 
| 
190
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
         return $self->_process_include($node, $environment, $sigil, $quant, $tail);  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($sigil ~~ [':', ';']) {  | 
| 
192
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
125
 | 
         return $self->_process_wrap($node, $environment, $sigil, $quant, $tail);  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($sigil eq '^') {  | 
| 
194
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
         return $self->_process_function($node, $environment, $sigil, $quant, $tail);  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
196
 | 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
648
 | 
         my $new_node = $handler->shallow_clone($node);  | 
| 
197
 | 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
671
 | 
         $handler->push_contents( $new_node, map { $self->_process_element($_, $environment) } $handler->list_contents($node));  | 
| 
 
 | 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
423
 | 
    | 
| 
198
 | 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
471
 | 
         $self->_remove_structure_sigils($new_node);  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #$self->resolve_hash_attr($new_node, $environment);  | 
| 
200
 | 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
464
 | 
         $self->_resolve_text_attr($new_node, $environment);  | 
| 
201
 | 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
894
 | 
         return $new_node;  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # String ones  | 
| 
204
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $node;  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_loop {  | 
| 
208
 | 
31
 | 
 
 | 
 
 | 
  
31
  
 | 
 
 | 
67
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
209
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
 	my $handler = $self->{'handler'};  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # TODO: true() and coercion!  | 
| 
211
 | 
31
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
99
 | 
 	my $loop = Positron::Expression::evaluate($tail, $environment) || [];  | 
| 
212
 | 
31
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
86
 | 
 	if (not @$loop) {  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# keep if we should, else nothing  | 
| 
214
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
53
 | 
 		return ($quant eq '+') ? ($self->_clone_and_resolve($node, $environment)) : ();  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# else have loop  | 
| 
217
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
 	my @contents;  | 
| 
218
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
 	foreach my $row (@$loop) {  | 
| 
219
 | 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
226
 | 
 		my $env = Positron::Environment->new($row, {parent => $environment});  | 
| 
220
 | 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
172
 | 
 		my @row_contents = map { $self->_process_element( $_, $env) } $handler->list_contents($node);  | 
| 
 
 | 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
    | 
| 
221
 | 
46
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
213
 | 
 		push @contents, ($quant eq '*') ? ($self->_clone_and_resolve($node, $env, @row_contents)) : @row_contents;  | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
223
 | 
23
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
131
 | 
 	if ($quant ne '-' and $quant ne '*') { # remove this in any case  | 
| 
224
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
 		return ($self->_clone_and_resolve($node, $environment, @contents));  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
226
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 	return @contents;  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_condition {  | 
| 
230
 | 
23
 | 
 
 | 
 
 | 
  
23
  
 | 
 
 | 
45
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
231
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
 	my $handler = $self->{'handler'};  | 
| 
232
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
     my $truth = Positron::Expression::true(Positron::Expression::evaluate($tail, $environment));  | 
| 
233
 | 
23
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
57
 | 
 	if ($sigil eq '!') {$truth = not $truth;}  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
41
 | 
    | 
| 
234
 | 
23
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
118
 | 
 	my $keep = ($truth and $quant ne '-' or $quant eq '+');  | 
| 
235
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
 	my @contents = ();  | 
| 
236
 | 
23
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
78
 | 
 	if ($truth or $quant eq '*') {  | 
| 
237
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
 		@contents = map { $self->_process_element($_, $environment) } $handler->list_contents($node);  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
239
 | 
23
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
86
 | 
 	return ($keep) ? ($self->_clone_and_resolve($node, $environment, @contents)) : @contents;  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_switch {  | 
| 
243
 | 
75
 | 
 
 | 
 
 | 
  
75
  
 | 
 
 | 
135
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
244
 | 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
 	my $handler = $self->{'handler'};  | 
| 
245
 | 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
     my $truth;  | 
| 
246
 | 
75
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
161
 | 
     if ($tail =~ m{ \A : \s+ (.*) }xms) {  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # "switch/given": setter  | 
| 
248
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
         my $expr = $1;  | 
| 
249
 | 
15
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
47
 | 
         my $goal = Positron::Expression::evaluate($expr, $environment) // ''; # always defined  | 
| 
250
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
         $environment = Positron::Environment->new({'|' => $goal}, { parent => $environment, immutable => 0});  | 
| 
251
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
         $truth = 1; # counts as a true condition for quantifiers  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # "case/when": getter  | 
| 
254
 | 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
147
 | 
         my $goal = $environment->get('|');  | 
| 
255
 | 
60
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
113
 | 
         if (defined ($goal)) {  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # not consumed yet  | 
| 
257
 | 
52
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
120
 | 
             my $test = Positron::Expression::evaluate($tail, $environment) // '';  | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # "truth" as in a condition  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # To trigger the default, the $tail expression must be "empty", not the result!  | 
| 
260
 | 
52
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
334
 | 
             $truth = ($goal eq $test or $tail =~ m{ \A \s* \z }xms);  | 
| 
261
 | 
52
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
111
 | 
             if ($truth) {  | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # remember the match for defaults  | 
| 
263
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
                 $environment->set('|', undef); # Don't delete, because of parent  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # already consumed, or never saw a '|:'  | 
| 
267
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
             $truth = 0;  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Keep and contents (see condition)  | 
| 
271
 | 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
104
 | 
     my @contents = ();  | 
| 
272
 | 
75
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
333
 | 
     my $keep = ($truth and $quant ne '-' or $quant eq '+');  | 
| 
273
 | 
75
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
249
 | 
     if ($truth or $quant eq '*') {  | 
| 
274
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
         @contents = map { $self->_process_element($_, $environment) } $handler->list_contents($node);  | 
| 
 
 | 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
158
 | 
    | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
276
 | 
75
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
274
 | 
     return ($keep) ? ($self->_clone_and_resolve($node, $environment, @contents)) : @contents;  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_structure_comment {  | 
| 
280
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
7
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
281
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	my $handler = $self->{'handler'};  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # basically an always-false condition  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # we could reuse our $keep and @contents code here, but this is probably  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # more readable:  | 
| 
285
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     if ($quant eq '+') {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
286
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # keep node, not contents  | 
| 
287
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
         return $self->_clone_and_resolve($node, $environment);  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($quant eq '*') {  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # keep contents, not node  | 
| 
290
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
         return map { $self->_process_element($_, $environment) } $handler->list_contents($node);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
292
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         return; # nothing  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_include {  | 
| 
297
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
25
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
298
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
 	my $handler = $self->{'handler'};  | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
300
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     my @contents = ();  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
302
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     if ($sigil eq '.') {  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # from file  | 
| 
304
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
         my $filename = Positron::Expression::evaluate($tail, $environment);  | 
| 
305
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
         my $filepath = undef;  | 
| 
306
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         foreach my $include_path (@{$self->{'include_paths'}}) {  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
    | 
| 
307
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
736
 | 
             if (-r $include_path . $filename) {  | 
| 
308
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
                 $filepath = $include_path . $filename;  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
311
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
         if (not defined $filepath) {  | 
| 
312
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
             croak "Could not find $filename (from $tail) for inclusion";  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # automatically die if we can't read this  | 
| 
317
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
         @contents = $handler->parse_file($filepath);  | 
| 
318
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         @contents = map { $self->_process_element($_, $environment) } @contents;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # from env  | 
| 
321
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
         my $env_contents = Positron::Expression::evaluate($tail, $environment);  | 
| 
322
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
         if ($env_contents) {  | 
| 
323
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
             if (ref($env_contents) eq 'ARRAY') {  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # special case: can't allow ['a', 'text'], must be [['a', 'text']], sorry  | 
| 
325
 | 
6
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
48
 | 
                 if ($handler->isa('Positron::Handler::ArrayRef') and not ref($env_contents->[0])) {  | 
| 
326
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
                     @contents = ($env_contents);  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
328
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
                     @contents = @$env_contents;  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
331
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 @contents = ($env_contents);  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # warn?  | 
| 
335
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             @contents = ();  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
339
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     my $keep = ($quant eq '+');  | 
| 
340
 | 
10
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
62
 | 
     return ($keep) ? ($self->_clone_and_resolve($node, $environment, @contents)) : @contents;  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: Refactor. Either extract the parts that are common between _include and  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #       _wrap, or just push them both together in one function.  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_wrap {  | 
| 
346
 | 
50
 | 
 
 | 
 
 | 
  
50
  
 | 
 
 | 
94
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
347
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
 	my $handler = $self->{'handler'};  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
349
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
     my @contents = ();  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
351
 | 
50
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
113
 | 
     if ($tail =~ m{ \S }xms) {  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
353
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
         my @wrapping_contents;  | 
| 
354
 | 
26
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
         if ($sigil eq ':') {  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # filename, read that and include "us".  | 
| 
356
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
             my $filename = Positron::Expression::evaluate($tail, $environment);  | 
| 
357
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
             my $filepath = undef;  | 
| 
358
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
             foreach my $include_path (@{$self->{'include_paths'}}) {  | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
359
 | 
28
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
429
 | 
                 if (-r $include_path . $filename) {  | 
| 
360
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
                     $filepath = $include_path . $filename;  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
363
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
34
 | 
             if (not defined $filepath) {  | 
| 
364
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
                 croak "Could not find $filename (from $tail) for wrapping";  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # automatically die if we can't read this  | 
| 
367
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
             @wrapping_contents = $handler->parse_file($filepath);  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # from env  | 
| 
370
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
             my $env_contents = Positron::Expression::evaluate($tail, $environment);  | 
| 
371
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
29
 | 
             if ($env_contents) {  | 
| 
372
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
24
 | 
                 if (ref($env_contents) eq 'ARRAY') {  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # special case: can't allow ['a', 'text'], must be [['a', 'text']], sorry  | 
| 
374
 | 
12
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
77
 | 
                     if ($handler->isa('Positron::Handler::ArrayRef') and not ref($env_contents->[0])) {  | 
| 
375
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
                         @wrapping_contents = ($env_contents);  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     } else {  | 
| 
377
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         @wrapping_contents = @$env_contents;  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
380
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     @wrapping_contents = ($env_contents);  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # warn?  | 
| 
384
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 @wrapping_contents = ();  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # TODO: resolve later? We'd need to clone $node and remove structure sigils to defeat recursion  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Resolve now; also allows clone_and_resolve to clear sigils to defeat recursion  | 
| 
390
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
102
 | 
         @contents = map { $self->_process_element($_, $environment) } $handler->list_contents($node);  | 
| 
 
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
106
 | 
    | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # only quant-less versions pass the parent  | 
| 
392
 | 
24
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
72
 | 
         my @passed_nodes = $quant ? @contents : $self->_clone_and_resolve($node, $environment, @contents);  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
394
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
182
 | 
         $environment = Positron::Environment->new({':' => [ @passed_nodes ]}, { parent => $environment, immutable => 0});  | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
396
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
70
 | 
         @contents = @wrapping_contents;  | 
| 
397
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
         @contents = map { $self->_process_element($_, $environment) } @contents;  | 
| 
 
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
    | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # inclusion marker  | 
| 
401
 | 
24
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
65
 | 
         my $passed_nodes = $environment->get(':') || [];  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # On error, just kill all (warn, maybe?)  | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Remember: already resolved!  | 
| 
404
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
         @contents = @$passed_nodes;  | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # this works for both cases!  | 
| 
408
 | 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
     my $keep = ($quant eq '+');  | 
| 
409
 | 
48
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
254
 | 
     return ($keep) ? ($self->_clone_and_resolve($node, $environment, @contents)) : @contents;  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _process_function {  | 
| 
413
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
 
 | 
17
 | 
 	my ($self, $node, $environment, $sigil, $quant, $tail) = @_;  | 
| 
414
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 	my $handler = $self->{'handler'};  | 
| 
415
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
     my $function = Positron::Expression::evaluate($tail, $environment);  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # The "self" node can be part of the arguments (quant ''), receive the results of the function  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # (quant '+'), or be dropped altogether (quant '-').  | 
| 
419
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	my $keep = ($quant eq '+');  | 
| 
420
 | 
9
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
115
 | 
     my $pass_self = (not $keep and $quant ne '-');  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
422
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
 	my @contents = ();  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Need these in any case:  | 
| 
424
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
     @contents = map { $self->_process_element($_, $environment) } $handler->list_contents($node);  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
425
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     if ($pass_self) {  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # we could also need to pass "self".  | 
| 
427
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
         @contents = $self->_clone_and_resolve($node, $environment, @contents);  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
430
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
     @contents = $function->(@contents);  | 
| 
431
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
126
 | 
 	return ($keep) ? ($self->_clone_and_resolve($node, $environment, @contents)) : @contents;  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _make_finder {  | 
| 
436
 | 
1186
 | 
 
 | 
 
 | 
  
1186
  
 | 
 
 | 
57131
 | 
     my ($self, $sigils) = @_;  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # What to do on empty sigils? Need to find during development!  | 
| 
438
 | 
1186
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2308
 | 
     die "Empty sigil list!" unless $sigils;  | 
| 
439
 | 
1185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2154
 | 
     my ($opener, $closer) = ($self->{opener}, $self->{closer});  | 
| 
440
 | 
1185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2123
 | 
     my ($eopener, $ecloser) = ("\\$opener","\\$closer");  | 
| 
441
 | 
1185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6929
 | 
     my ($esigils) = join('', map { "\\$_" } split(qr{}, $sigils));  | 
| 
 
 | 
8228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14774
 | 
    | 
| 
442
 | 
1185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29175
 | 
     return qr{  | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $eopener  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ( [$esigils] )  | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ( [-+*]? )  | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ( [^$ecloser]* )  | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $ecloser  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }xms;  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
451
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Handlers for:  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # scalar string, no handler  | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # HTML::Element  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # XML::LibXML  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ArrayRef Handler  | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: an extensible mechanism  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _handler_for {  | 
| 
458
 | 
20
 | 
 
 | 
 
 | 
  
20
  
 | 
 
 | 
48
 | 
     my ($dom) = @_;  | 
| 
459
 | 
20
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
194
 | 
     return unless ref($dom); # Text at most, needs no handler  | 
| 
460
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
34
 | 
     if (ref($dom) eq 'ARRAY') {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
461
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11830
 | 
         require Positron::Handler::ArrayRef;  | 
| 
462
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
         return Positron::Handler::ArrayRef->new();  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (my $package = blessed($dom)) {  | 
| 
464
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         eval "require Positron::Handler::$package; 1;" or croak "Could not load handler for $package";  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_structure_sigil {  | 
| 
469
 | 
423
 | 
 
 | 
 
 | 
  
423
  
 | 
 
 | 
535
 | 
     my ($self, $node) = @_;  | 
| 
470
 | 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
532
 | 
     my $handler = $self->{'handler'};  | 
| 
471
 | 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
778
 | 
     my $structure_finder = $self->_make_finder('@?!/.:,;|^');  | 
| 
472
 | 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1685
 | 
     foreach my $attr ($handler->list_attributes($node)) {  | 
| 
473
 | 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
643
 | 
         my $value = $handler->get_attribute($node, $attr);  | 
| 
474
 | 
225
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2066
 | 
         if ($value =~ m{ $structure_finder }xms) {  | 
| 
475
 | 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1190
 | 
             return ($1, $2, $3);  | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
477
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
478
 | 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
597
 | 
     return; # Has none  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _remove_structure_sigils {  | 
| 
482
 | 
322
 | 
 
 | 
 
 | 
  
322
  
 | 
 
 | 
441
 | 
     my ($self, $node) = @_;  | 
| 
483
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
441
 | 
     my $handler = $self->{'handler'};  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # NOTE: we remove '=' here as well, even though it's not a structure sigil!  | 
| 
485
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
590
 | 
     my $structure_finder = $self->_make_finder('@?!/.:,;=|^');  | 
| 
486
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1073
 | 
     foreach my $attr ($handler->list_attributes($node)) {  | 
| 
487
 | 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
426
 | 
         my $value = $handler->get_attribute($node, $attr);  | 
| 
488
 | 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1083
 | 
         my $did_change = ($value =~ s{ $structure_finder }{}xmsg);  | 
| 
489
 | 
129
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
331
 | 
         if ($did_change) {  | 
| 
490
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # We removed something from this attribute -> delete it if empty  | 
| 
491
 | 
108
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
243
 | 
             if ($value eq '') {  | 
| 
492
 | 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
367
 | 
                 $handler->set_attribute($node, $attr, undef);  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
496
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
816
 | 
     return; # void?  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _clone_and_resolve {  | 
| 
500
 | 
107
 | 
 
 | 
 
 | 
  
107
  
 | 
 
 | 
212
 | 
     my ($self, $node, $environment, @contents) = @_;  | 
| 
501
 | 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
168
 | 
     my $handler = $self->{'handler'};  | 
| 
502
 | 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
292
 | 
     my $clone = $handler->shallow_clone($node);  | 
| 
503
 | 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
248
 | 
     $self->_remove_structure_sigils($clone);  | 
| 
504
 | 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
240
 | 
     $self->_resolve_text_attr($clone, $environment);  | 
| 
505
 | 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
298
 | 
     $handler->push_contents($clone, @contents);  | 
| 
506
 | 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
557
 | 
     return $clone;  | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _resolve_text_attr {  | 
| 
510
 | 
322
 | 
 
 | 
 
 | 
  
322
  
 | 
 
 | 
427
 | 
     my ($self, $node, $environment) = @_;  | 
| 
511
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
457
 | 
     my $handler = $self->{'handler'};  | 
| 
512
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
836
 | 
     foreach my $attr ($handler->list_attributes($node)) {  | 
| 
513
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
         my ($value, $did_change, $last_changing_quant) = $self->_process_text($handler->get_attribute($node, $attr), $environment, 1);  | 
| 
514
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
61
 | 
         if ($did_change) {  | 
| 
515
 | 
15
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
59
 | 
             if ($value eq '' and not $last_changing_quant eq '+') {  | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # We removed somethin from this attribute -> delete it if empty, unless the last sigil says otherwise  | 
| 
517
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
                 $value = undef;  | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
519
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
             $handler->set_attribute($node, $attr, $value);  | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
522
 | 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
563
 | 
     return;  | 
| 
523
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |