line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package YATT::Lite::CGen::Perl; |
2
|
15
|
|
|
15
|
|
6543
|
use strict; |
|
15
|
|
|
|
|
41
|
|
|
15
|
|
|
|
|
622
|
|
3
|
15
|
|
|
15
|
|
78
|
use warnings qw(FATAL all NONFATAL misc); |
|
15
|
|
|
|
|
128
|
|
|
15
|
|
|
|
|
528
|
|
4
|
15
|
|
|
15
|
|
87
|
use mro 'c3'; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
172
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
require 5.010; # For named capture. |
7
|
|
|
|
|
|
|
|
8
|
15
|
|
|
15
|
|
655
|
use constant DEBUG_MRO => $ENV{DEBUG_YATT_MRO}; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
1135
|
|
9
|
|
|
|
|
|
|
|
10
|
15
|
|
|
15
|
|
94
|
use YATT::Lite::Core qw(Folder Template Part Widget Action); |
|
15
|
|
|
|
|
44
|
|
|
15
|
|
|
|
|
850
|
|
11
|
15
|
|
|
15
|
|
106
|
use YATT::Lite::Constants; |
|
15
|
|
|
|
|
35
|
|
|
15
|
|
|
|
|
2647
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# Naming convention: |
14
|
|
|
|
|
|
|
# generate_SRC -- Public Interface. |
15
|
|
|
|
|
|
|
# gen_DETAIL -- Internal higher/large tasks. |
16
|
|
|
|
|
|
|
# from_NODETYPE -- Node Type specific dispatch entry. |
17
|
|
|
|
|
|
|
# as_WHATHOW_FROM -- Miscellaneous dispatching (for var type and others) |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
{ |
20
|
|
|
|
|
|
|
#======================================== |
21
|
|
|
|
|
|
|
package YATT::Lite::CGen::Perl; sub MY () {__PACKAGE__} |
22
|
15
|
|
|
15
|
|
101
|
use base qw(YATT::Lite::CGen); |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
6078
|
|
23
|
15
|
|
|
15
|
|
114
|
use YATT::Lite::MFields; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
85
|
|
24
|
15
|
|
|
15
|
|
101
|
use YATT::Lite::Util qw(lexpand numLines globref terse_dump catch); |
|
15
|
|
|
|
|
36
|
|
|
15
|
|
|
|
|
807
|
|
25
|
15
|
|
|
15
|
|
101
|
use Carp; |
|
15
|
|
|
|
|
29
|
|
|
15
|
|
|
|
|
104995
|
|
26
|
|
|
|
|
|
|
#======================================== |
27
|
|
|
|
|
|
|
sub list_inheritance { |
28
|
440
|
|
|
440
|
0
|
924
|
(my MY $self, my Template $tmpl) = @_; |
29
|
|
|
|
|
|
|
# XXX: Duplicate detection should be handled higer layer. |
30
|
440
|
|
|
|
|
715
|
my %dup; |
31
|
|
|
|
|
|
|
map { |
32
|
440
|
|
|
|
|
1302
|
my Folder $f = $_; |
|
452
|
|
|
|
|
808
|
|
33
|
452
|
50
|
|
|
|
1280
|
unless (defined $f->{cf_entns}) { |
34
|
0
|
|
|
|
|
0
|
die "BUG: EntNS is empty for ".terse_dump($f->{cf_name})."!"; |
35
|
|
|
|
|
|
|
} |
36
|
452
|
50
|
|
|
|
1471
|
if ($dup{$f->{cf_entns}}++) { |
37
|
|
|
|
|
|
|
() |
38
|
0
|
|
|
|
|
0
|
} else { |
39
|
|
|
|
|
|
|
$f->{cf_entns} |
40
|
452
|
|
|
|
|
1703
|
} |
41
|
|
|
|
|
|
|
} $tmpl->list_base |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
sub setup_inheritance_for { |
44
|
220
|
|
|
220
|
0
|
620
|
(my MY $self, my $spec, my Template $tmpl) = @_; |
45
|
220
|
50
|
|
|
|
752
|
unless (defined $tmpl->{cf_entns}) { |
46
|
0
|
|
|
|
|
0
|
die "BUG: EntNS is empty for '$tmpl->{cf_name}'!"; |
47
|
|
|
|
|
|
|
} |
48
|
220
|
|
|
|
|
829
|
my $glob = globref($$tmpl{cf_entns}, 'ISA'); |
49
|
|
|
|
|
|
|
# XXX: base change should be reflected when reloaded, but... |
50
|
220
|
50
|
|
|
|
770
|
unless (defined $glob) { |
51
|
0
|
|
|
|
|
0
|
die "BUG: ISA glob for '$tmpl->{cf_name}' is empty!"; |
52
|
|
|
|
|
|
|
} |
53
|
220
|
|
|
|
|
1102
|
$self->ensure_generated_for_folders($spec, $tmpl->list_base); |
54
|
220
|
|
|
|
|
922
|
my @isa = $self->list_inheritance($tmpl); |
55
|
220
|
50
|
|
|
|
537
|
if (grep {not defined} @isa) { |
|
226
|
|
|
|
|
798
|
|
56
|
0
|
|
|
|
|
0
|
die "BUG: ISA for '$tmpl->{cf_name}' contains undef!"; |
57
|
|
|
|
|
|
|
} |
58
|
220
|
50
|
|
|
|
1598
|
if (my $err = catch { |
59
|
220
|
|
|
220
|
|
3874
|
*$glob = \@isa; |
60
|
|
|
|
|
|
|
}) { |
61
|
|
|
|
|
|
|
die $self->generror("Can't set ISA for '%s' as [%s]: %s" |
62
|
|
|
|
|
|
|
, $tmpl->{cf_name} |
63
|
0
|
|
|
|
|
0
|
, join(", ", @isa) |
64
|
|
|
|
|
|
|
, $err |
65
|
|
|
|
|
|
|
); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
sub generate_inheritance { |
69
|
220
|
|
|
220
|
0
|
593
|
(my MY $self, my Template $tmpl) = @_; |
70
|
220
|
|
|
|
|
597
|
my @isa = $self->list_inheritance($tmpl); |
71
|
220
|
|
|
|
|
793
|
my $mro = mro::get_mro($tmpl->{cf_entns}); |
72
|
220
|
|
|
|
|
387
|
print STDERR "($mro) [$tmpl->{cf_path}] $tmpl->{cf_entns}::ISA = @isa\n" |
73
|
|
|
|
|
|
|
if DEBUG_MRO; |
74
|
220
|
|
|
|
|
1046
|
sprintf q{use mro '%s'; our @ISA = qw(%s); }, $mro, join " ", @isa; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
#======================================== |
77
|
|
|
|
|
|
|
sub generate_preamble { |
78
|
220
|
|
|
220
|
0
|
539
|
(my MY $self, my Template $tmpl) = @_; |
79
|
220
|
|
33
|
|
|
645
|
$tmpl ||= $self->{curtmpl}; |
80
|
220
|
|
|
|
|
390
|
my @stats; |
81
|
220
|
50
|
|
|
|
758
|
unless ($self->{cf_no_lineinfo}) { |
82
|
220
|
|
|
|
|
723
|
my $line = qq{#line }. $self->{curline}; |
83
|
220
|
100
|
|
|
|
899
|
if (defined(my $fn = $tmpl->fake_filename)) { |
84
|
|
|
|
|
|
|
# cf_name is dummy filename. |
85
|
219
|
|
|
|
|
678
|
$line .= qq{ "$fn"}; |
86
|
|
|
|
|
|
|
} |
87
|
220
|
|
|
|
|
858
|
push @stats, $line .= "\n"; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
push @stats, sprintf q{package %s; use strict; use warnings; use 5.010; } |
90
|
220
|
|
|
|
|
1137
|
, $$tmpl{cf_entns}; |
91
|
220
|
|
|
|
|
966
|
push @stats, $self->generate_inheritance($tmpl); |
92
|
220
|
100
|
|
|
|
741
|
push @stats, "use utf8; " if $$tmpl{cf_utf8}; |
93
|
220
|
100
|
|
|
|
707
|
push @stats, q|no warnings qw(redefine); | if $$tmpl{cf_age}++; |
94
|
220
|
|
|
|
|
505
|
push @stats, sprintf q|sub filename {__FILE__}; |; |
95
|
|
|
|
|
|
|
@stats |
96
|
220
|
|
|
|
|
743
|
} |
97
|
|
|
|
|
|
|
sub generate_page { |
98
|
|
|
|
|
|
|
# XXX: 本物へ。 public フラグ? |
99
|
253
|
|
|
253
|
0
|
1037
|
shift->generate_widget(@_); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
sub generate_widget { |
102
|
346
|
|
|
346
|
0
|
1122
|
(my MY $self, my Widget $widget, my ($widget_name, $tmpl_path)) = @_; |
103
|
346
|
100
|
|
|
|
1026
|
if ($widget->{cf_suppressed}) { |
104
|
2
|
|
|
|
|
12
|
return "\n" x ($widget->{cf_endln} - $widget->{cf_startln}); |
105
|
|
|
|
|
|
|
} |
106
|
344
|
|
|
|
|
1430
|
break_cgen(); |
107
|
344
|
|
|
|
|
818
|
local $self->{curwidget} = $widget; |
108
|
|
|
|
|
|
|
# XXX: calling convention 周り, body の code 型 |
109
|
|
|
|
|
|
|
local $self->{scope} = $self->mkscope |
110
|
|
|
|
|
|
|
({}, $widget->{var_dict}, $widget->{arg_dict} ||= {} |
111
|
344
|
|
50
|
|
|
2376
|
, {this => $self->mkvar_at(undef, text => 'this') |
112
|
|
|
|
|
|
|
, 'CON' => $self->mkvar_at(undef, text => 'CON') |
113
|
|
|
|
|
|
|
, '_' => $self->mkvar_at(undef, text => '_')} |
114
|
|
|
|
|
|
|
); |
115
|
344
|
|
|
|
|
812
|
local $self->{curtoks} = [@{$widget->{tree}}]; |
|
344
|
|
|
|
|
1147
|
|
116
|
|
|
|
|
|
|
($self->sync_curline($widget->{cf_startln}) |
117
|
|
|
|
|
|
|
, "sub render_$$widget{cf_name} {" |
118
|
|
|
|
|
|
|
, $self->gen_preamble($widget) |
119
|
|
|
|
|
|
|
, $self->gen_getargs($widget, not $widget->{cf_implicit}) |
120
|
344
|
|
|
|
|
1438
|
, $self->as_print("}") |
121
|
|
|
|
|
|
|
); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
sub generate_action { |
124
|
3
|
|
|
3
|
0
|
8
|
(my MY $self, my Action $action) = @_; |
125
|
|
|
|
|
|
|
# XXX: 改行の調整が必要。 |
126
|
|
|
|
|
|
|
my @src = ($self->sync_curline($action->{cf_startln}) |
127
|
3
|
|
|
|
|
11
|
, "sub $$action{cf_name} {"); |
128
|
|
|
|
|
|
|
my $src = $self->{curtmpl}->source_substr |
129
|
3
|
|
|
|
|
15
|
($action->{cf_bodypos}, $action->{cf_bodylen}); |
130
|
|
|
|
|
|
|
|
131
|
3
|
100
|
66
|
|
|
11
|
if (lexpand($action->{arg_order}) |
132
|
|
|
|
|
|
|
or $src !~ m{^([\ \t\r\n]*)my\s*\([^;\)]+\)\s*=\s*\@_\s*;}) { |
133
|
|
|
|
|
|
|
# If an action has no arguments |
134
|
|
|
|
|
|
|
# and its source doesn't start with my (...) = @_;, |
135
|
|
|
|
|
|
|
# insert preamble and getargs. |
136
|
|
|
|
|
|
|
push @src, $self->gen_preamble($action) |
137
|
1
|
|
|
|
|
5
|
, $self->gen_getargs($action, not $action->{cf_implicit}); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
3
|
|
|
|
|
13
|
my $has_nl = $src =~ s/\r?\n\Z//; |
141
|
3
|
50
|
|
|
|
10
|
$self->{curline} = $action->{cf_bodyln} + numLines($src) |
142
|
|
|
|
|
|
|
+ ($has_nl ? 1 : 0); |
143
|
3
|
|
|
|
|
19
|
(@src, $src, "}"); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
#======================================== |
146
|
345
|
|
|
345
|
0
|
1538
|
sub gen_preamble {q{ my ($this, $CON) = splice @_, 0, 2;}} |
147
|
|
|
|
|
|
|
sub gen_getargs { |
148
|
377
|
|
|
377
|
0
|
903
|
(my MY $self, my Widget $widget, my $for_decl) = @_; |
149
|
377
|
|
|
|
|
634
|
my @res; |
150
|
377
|
|
|
|
|
1301
|
foreach my $argName (lexpand($widget->{arg_order})) { |
151
|
|
|
|
|
|
|
# デフォルト値と、型と。 |
152
|
588
|
|
|
|
|
1286
|
my $var = $widget->{arg_dict}{$argName}; |
153
|
588
|
100
|
|
|
|
2530
|
push @res, $for_decl ? $self->sync_curline($var->lineno) : () |
154
|
|
|
|
|
|
|
, sprintf q{ my %s = %s;}, $self->as_lvalue($var) |
155
|
|
|
|
|
|
|
, $self->as_getarg($var); |
156
|
|
|
|
|
|
|
# shift しない方が、debug 時に stack trace に引数値が見えて嬉しい。 |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
# 末尾の改行 |
159
|
377
|
100
|
33
|
|
|
1287
|
push @res, "\n" and $self->{curline}++ if $for_decl; |
160
|
|
|
|
|
|
|
(@res, $self->sync_curline($widget->{cf_bodyln}) |
161
|
377
|
|
|
|
|
1511
|
, $self->cut_next_nl); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
sub as_getarg { |
164
|
588
|
|
|
588
|
0
|
1294
|
(my MY $self, my $var) = @_; |
165
|
588
|
|
|
|
|
1701
|
my $actual = '$_['.$var->argno.']'; |
166
|
588
|
100
|
66
|
|
|
2003
|
return $actual unless defined (my $default = $var->default) |
167
|
|
|
|
|
|
|
and defined (my $mode = $var->dflag); |
168
|
28
|
|
|
|
|
80
|
my $varname = $self->as_lvalue($var); |
169
|
28
|
100
|
|
|
|
102
|
if ($mode eq "!") { |
170
|
4
|
|
|
|
|
15
|
return qq{defined $actual ? $actual : } |
171
|
4
|
|
|
|
|
12
|
. qq{die q|Argument '@{[$var->varname]}' is undef!|}; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
# XXX: do given/when は値を返さないから、ここでは使えない! void context 扱いになっちまう。 |
174
|
24
|
|
|
|
|
58
|
my ($cond) = do { |
175
|
24
|
100
|
|
|
|
96
|
if ($mode eq "|") { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
176
|
2
|
|
|
|
|
8
|
qq{$actual} |
177
|
|
|
|
|
|
|
} elsif ($mode eq "?") { |
178
|
20
|
|
|
|
|
74
|
qq{defined $actual && $actual ne ""} |
179
|
|
|
|
|
|
|
} elsif ($mode eq "/") { |
180
|
2
|
|
|
|
|
9
|
qq{defined $actual} |
181
|
|
|
|
|
|
|
} else { |
182
|
0
|
|
|
|
|
0
|
die "Unknown defaulting mode: $mode" |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
}; |
185
|
24
|
|
|
|
|
116
|
sprintf q{(%s ? %s : %s)}, $cond, $actual |
186
|
|
|
|
|
|
|
, $self->as_cast_to($var, $default); |
187
|
|
|
|
|
|
|
# XXX: html 型変数へ text 型変数の混じったデフォルト値を入れるときには、 as_text じゃだめ |
188
|
|
|
|
|
|
|
# as_text に、やはり escape flag を渡せるようにするのが筋か? |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
#======================================== |
191
|
|
|
|
|
|
|
our @DISPATCH; |
192
|
|
|
|
|
|
|
$DISPATCH[TYPE_LINEINFO] = \&from_lineinfo; |
193
|
|
|
|
|
|
|
$DISPATCH[TYPE_COMMENT] = \&from_comment; |
194
|
|
|
|
|
|
|
$DISPATCH[TYPE_LCMSG] = \&from_lcmsg; |
195
|
|
|
|
|
|
|
$DISPATCH[TYPE_ENTITY] = \&from_entity; |
196
|
|
|
|
|
|
|
$DISPATCH[TYPE_PI] = \&from_pi; |
197
|
|
|
|
|
|
|
$DISPATCH[TYPE_ELEMENT] = \&from_element; |
198
|
|
|
|
|
|
|
$DISPATCH[TYPE_ATT_NESTED] = \&from_elematt; |
199
|
|
|
|
|
|
|
sub as_print { |
200
|
403
|
|
|
403
|
0
|
1066
|
(my MY $self, my ($last, $localtoks)) = @_; |
201
|
403
|
50
|
|
|
|
1031
|
push @{$self->{curtoks}}, @$localtoks if $localtoks; |
|
0
|
|
|
|
|
0
|
|
202
|
403
|
|
|
|
|
984
|
local $self->{needs_escaping} = 1; |
203
|
403
|
|
|
|
|
1112
|
my (@result, @queue) = ''; |
204
|
|
|
|
|
|
|
# curline は queue 詰めの外側で操作する。 |
205
|
|
|
|
|
|
|
# $last は一回だけ出力するように、undef が必要。 |
206
|
|
|
|
|
|
|
my $flush = sub { |
207
|
1200
|
|
|
1200
|
|
2509
|
my ($has_nl, $task, $pad) = @_; |
208
|
1200
|
100
|
|
|
|
2847
|
push @result, $pad if defined $pad; |
209
|
1200
|
100
|
|
|
|
3862
|
push @result, q{print $CON (}.join(", ", @queue).");" if @queue; |
210
|
|
|
|
|
|
|
# もう token が残っていなくて、かつ $last が与えられていたら、 $last を足す。 |
211
|
1200
|
100
|
|
|
|
2950
|
push @result, $task->() if $task; |
212
|
1200
|
100
|
50
|
|
|
2908
|
$result[-1] .= $last and undef $last if $last and not @{$self->{curtoks}}; |
|
861
|
|
100
|
|
|
3543
|
|
213
|
|
|
|
|
|
|
# 明示 "\n" が来ていた場合は、 ";" と同時に改行する。 |
214
|
1200
|
100
|
|
|
|
2998
|
$result[-1] .= "\n" if $has_nl; |
215
|
1200
|
|
|
|
|
2746
|
undef @queue; |
216
|
403
|
|
|
|
|
2213
|
}; |
217
|
403
|
|
|
|
|
843
|
while (@{$self->{curtoks}}) { |
|
1854
|
|
|
|
|
4749
|
|
218
|
1472
|
|
|
|
|
2299
|
my $node = shift @{$self->{curtoks}}; |
|
1472
|
|
|
|
|
3011
|
|
219
|
1472
|
100
|
|
|
|
3523
|
unless (ref $node) { |
220
|
|
|
|
|
|
|
# text node の末尾が改行で終わっている場合、 明示的に "\n" を生成する |
221
|
901
|
|
|
|
|
3393
|
my $has_nl = $node =~ s/\r?\n\Z//s; |
222
|
901
|
100
|
|
|
|
3343
|
push @queue, qtext($node) if $node ne ''; # 削ったら空になるかも。 |
223
|
901
|
|
|
|
|
2856
|
$self->{curline} += numLines($node); |
224
|
901
|
100
|
|
|
|
2195
|
$self->{curline}++ if $has_nl; |
225
|
|
|
|
|
|
|
push @queue, q{"\n"} if $has_nl |
226
|
901
|
100
|
100
|
|
|
2253
|
and @{$self->{curtoks}} || not $self->{no_last_newline}; |
|
|
|
100
|
|
|
|
|
227
|
901
|
100
|
100
|
|
|
3695
|
$flush->($has_nl) if $has_nl || $node =~ /\n/; |
228
|
901
|
|
|
|
|
2040
|
next; |
229
|
|
|
|
|
|
|
} |
230
|
571
|
|
100
|
|
|
1751
|
my $pad = $self->sync_curline($node->[NODE_LNO]) // ''; |
231
|
571
|
50
|
|
|
|
1804
|
my $sub = $DISPATCH[$node->[0]] |
232
|
|
|
|
|
|
|
or die $self->generror("Unknown node type: %d", $node->[0]); |
233
|
571
|
|
|
|
|
1535
|
my $expr = $sub->($self, $node); |
234
|
550
|
50
|
|
|
|
1687
|
unless (defined $expr) { |
235
|
0
|
|
|
|
|
0
|
push @result, $self->cut_next_nl; |
236
|
0
|
|
|
|
|
0
|
next; |
237
|
|
|
|
|
|
|
} |
238
|
550
|
100
|
|
|
|
1311
|
if (ref $expr) { |
239
|
233
|
|
|
233
|
|
1428
|
$flush->(undef, sub { ("$$expr;", $self->cut_next_nl) }, $pad); |
|
233
|
|
|
|
|
945
|
|
240
|
|
|
|
|
|
|
} else { |
241
|
317
|
100
|
|
|
|
869
|
$flush->(undef, undef, $pad) if length $pad; |
242
|
317
|
|
|
|
|
645
|
push @queue, $expr; |
243
|
317
|
50
|
|
|
|
1170
|
$flush->() if $expr =~ /\n/; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
} |
246
|
382
|
|
|
|
|
1053
|
$flush->(); |
247
|
382
|
|
|
|
|
6228
|
join " ", @result; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
sub gen_as { |
250
|
78
|
|
|
78
|
0
|
273
|
(my MY $self, my ($type, $dispatch, $escape, $text_quote)) |
251
|
|
|
|
|
|
|
= splice @_, 0, 5; |
252
|
78
|
|
|
|
|
213
|
local $self->{needs_escaping} = $escape; |
253
|
78
|
|
|
|
|
137
|
my (@result); |
254
|
|
|
|
|
|
|
# Empty expr (ie <:yatt:arg>) should generate q|| as code. |
255
|
78
|
100
|
66
|
|
|
265
|
if (not @_ and $text_quote) { |
256
|
1
|
|
|
|
|
4
|
push @result, qtext(''); |
257
|
|
|
|
|
|
|
} |
258
|
78
|
|
|
|
|
233
|
while (@_) { |
259
|
135
|
|
|
|
|
262
|
my $node = shift; |
260
|
135
|
100
|
|
|
|
347
|
unless (ref $node) { |
261
|
103
|
100
|
|
|
|
305
|
push @result, ($text_quote ? qtext($node) : $node); |
262
|
103
|
|
|
|
|
365
|
$self->{curline} += numLines($node); |
263
|
103
|
|
|
|
|
308
|
next; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
# 許されるのは entity だけでは? でもないか。 element 引数の時は、capture したいはず。 |
266
|
32
|
50
|
|
|
|
119
|
my $sub = $dispatch->[$node->[0]] |
267
|
|
|
|
|
|
|
or die $self->generror("gen_as %s: Unknown node type: %d" |
268
|
|
|
|
|
|
|
, $type, $node->[0]); |
269
|
32
|
|
|
|
|
103
|
my $expr = $sub->($self, $node); |
270
|
32
|
50
|
|
|
|
95
|
next unless defined $expr; |
271
|
32
|
50
|
|
|
|
87
|
if (ref $expr) { |
272
|
0
|
|
|
|
|
0
|
die $self->generror("Syntax error, not allowed here: %s", $$expr); |
273
|
|
|
|
|
|
|
} |
274
|
32
|
|
|
|
|
103
|
push @result, $expr; |
275
|
|
|
|
|
|
|
} |
276
|
78
|
100
|
|
|
|
492
|
wantarray ? @result : join("", @result); |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
# as_list と対になる。 |
280
|
|
|
|
|
|
|
our @AS_TEXT; |
281
|
|
|
|
|
|
|
$AS_TEXT[TYPE_LCMSG] = \&from_lcmsg; |
282
|
|
|
|
|
|
|
$AS_TEXT[TYPE_ENTITY] = \&from_entity; |
283
|
|
|
|
|
|
|
$AS_TEXT[TYPE_PI] = \&text_from_pi; |
284
|
|
|
|
|
|
|
$AS_TEXT[TYPE_ELEMENT] = \&text_from_element; # XXX: ?? Used?? |
285
|
|
|
|
|
|
|
$AS_TEXT[TYPE_ATT_NESTED] = sub {undef}; # gen_as が scalar 受けゆえ |
286
|
|
|
|
|
|
|
# as_text は、escape 不要。なぜなら、 print 時に escape されるから。 |
287
|
|
|
|
|
|
|
# でも、 escape 有無を flag で渡せた方が、 html 型にも使えて便利では? |
288
|
|
|
|
|
|
|
# というか、 html 型には capture が必要か。 capture は buffering したいよね? |
289
|
|
|
|
|
|
|
sub as_text { |
290
|
14
|
|
|
14
|
0
|
61
|
join '.', shift->gen_as(text => \@AS_TEXT, 0, 1, @_); |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
our @AS_LIST; |
294
|
|
|
|
|
|
|
$AS_LIST[TYPE_ENTITY] = \&from_entity; |
295
|
|
|
|
|
|
|
$AS_LIST[TYPE_PI] = \&list_from_pi; |
296
|
|
|
|
|
|
|
$AS_LIST[TYPE_ELEMENT] = \&list_from_element; |
297
|
|
|
|
|
|
|
$AS_LIST[TYPE_ATT_NESTED] = sub {undef}; # XXX: 微妙 |
298
|
|
|
|
|
|
|
sub as_list { |
299
|
52
|
|
|
52
|
0
|
284
|
shift->gen_as(list => \@AS_LIST, 0, 0, @_); |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
#======================================== |
302
|
|
|
|
|
|
|
sub from_element { |
303
|
|
|
|
|
|
|
# XXX: macro (if, foreach, my, format) (error if は?) |
304
|
206
|
|
|
206
|
0
|
480
|
(my MY $self, my $node) = @_; |
305
|
206
|
|
|
|
|
422
|
my $path = $node->[NODE_PATH]; |
306
|
206
|
50
|
66
|
|
|
960
|
if (my $alt = $self->altgen($path->[0])) { |
|
|
100
|
100
|
|
|
|
|
307
|
0
|
|
|
|
|
0
|
qtext($alt->($node)); |
308
|
|
|
|
|
|
|
} elsif (@$path == 2 |
309
|
|
|
|
|
|
|
and my $macro = $self->can("macro_" . join "_", @$path) |
310
|
|
|
|
|
|
|
|| $self->can("macro_$path->[-1]")) { |
311
|
36
|
|
|
|
|
133
|
$macro->($self, $node); |
312
|
|
|
|
|
|
|
} else { |
313
|
|
|
|
|
|
|
# stack trace に現れるように, 敢えて展開。 |
314
|
170
|
|
|
|
|
377
|
$self->gen_call($node, @{$node->[NODE_PATH]}); |
|
170
|
|
|
|
|
718
|
|
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
sub text_from_element { |
318
|
2
|
|
|
2
|
0
|
7
|
(my MY $self, my $node) = @_; |
319
|
2
|
|
|
|
|
15
|
&YATT::Lite::Breakpoint::breakpoint(); |
320
|
2
|
|
|
|
|
18
|
my $call_ref = $self->from_element($node); |
321
|
2
|
|
|
|
|
13
|
sprintf q{YATT::Lite::Util::captured {my ($CON) = @_; %s}}, $$call_ref; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub gen_call { |
325
|
170
|
|
|
170
|
0
|
609
|
(my MY $self, my ($node, @path)) = @_; |
326
|
170
|
|
|
|
|
417
|
my $wname = join ":", @path; |
327
|
170
|
100
|
100
|
|
|
996
|
if (@path == 2 and my $var = $self->find_callable_var($path[-1])) { |
328
|
|
|
|
|
|
|
# code 引数の中の引数のデフォルト値の中に、改行が有ったら?? |
329
|
|
|
|
|
|
|
# XXX: body の引数宣言が無い場合に は、ちゃんと呼び出せるか? |
330
|
23
|
|
|
|
|
96
|
return $self->can("as_varcall_" . $var->type->[0]) |
331
|
|
|
|
|
|
|
->($self, $var, $node); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
147
|
100
|
|
|
|
942
|
my Widget $widget = $self->lookup_widget(@path) or do { |
335
|
2
|
|
|
|
|
9
|
my $err = $self->generror(q{No such widget <%s>}, $wname); |
336
|
2
|
|
|
|
|
98
|
die $err; |
337
|
|
|
|
|
|
|
}; |
338
|
|
|
|
|
|
|
|
339
|
145
|
|
|
|
|
693
|
$self->ensure_generated(perl => my Template $tmpl = $widget->{cf_folder}); |
340
|
145
|
|
|
|
|
444
|
my $use_this = $tmpl == $self->{curtmpl}; |
341
|
145
|
100
|
|
|
|
428
|
unless ($use_this) { |
342
|
29
|
|
|
|
|
185
|
$self->{curtmpl}->add_dependency($wname, $tmpl); |
343
|
|
|
|
|
|
|
} |
344
|
145
|
100
|
|
|
|
398
|
my $that = $use_this ? '$this' : $tmpl->{cf_entns}; |
345
|
|
|
|
|
|
|
\ sprintf(q{%s->render_%s($CON, %s)} |
346
|
|
|
|
|
|
|
, $that, $widget->{cf_name} |
347
|
145
|
|
|
|
|
669
|
, $self->gen_putargs($widget, $node) |
348
|
|
|
|
|
|
|
); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
sub gen_putargs { |
351
|
168
|
|
|
168
|
0
|
417
|
(my MY $self, my Widget $widget, my $node, my $delegate_vars) = @_; |
352
|
168
|
|
|
|
|
623
|
my ($path, $body, $primary, $head, $foot) = nx($node); |
353
|
|
|
|
|
|
|
return '' if not $delegate_vars and not $widget->{has_required_arg} |
354
|
168
|
100
|
100
|
|
|
1940
|
and not $primary and not $body; |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
355
|
77
|
|
|
|
|
236
|
my $wname = join ":", @$path; |
356
|
77
|
|
|
|
|
172
|
my ($posArgs, $actualNo, @argOrder); |
357
|
|
|
|
|
|
|
my $add_arg = sub { |
358
|
133
|
|
|
133
|
|
298
|
my ($name) = @_; |
359
|
133
|
100
|
|
|
|
418
|
my $formal = $widget->{arg_dict}{$name} or do { |
360
|
2
|
|
|
|
|
9
|
die $self->generror(q{Unknown arg '%s' in widget %s}, $name, $wname); |
361
|
|
|
|
|
|
|
}; |
362
|
131
|
50
|
|
|
|
443
|
if (defined $argOrder[my $argno = $formal->argno]) { |
363
|
0
|
|
|
|
|
0
|
die $self->generror(q{Duplicate arg '%s'}, $name); |
364
|
|
|
|
|
|
|
} else { |
365
|
131
|
|
|
|
|
275
|
$argOrder[$argno] = ++$actualNo; |
366
|
|
|
|
|
|
|
} |
367
|
131
|
|
|
|
|
239
|
$formal; |
368
|
77
|
|
|
|
|
450
|
}; |
369
|
|
|
|
|
|
|
# primary 引数 |
370
|
|
|
|
|
|
|
my @argExpr = map { |
371
|
77
|
|
|
|
|
214
|
$self->sync_curline($_->[NODE_LNO]), ", ", $self->add_curline(do { |
|
92
|
|
|
|
|
309
|
|
372
|
92
|
|
|
|
|
315
|
my $name = argName($_); |
373
|
92
|
100
|
|
|
|
256
|
unless (defined $name) { |
374
|
8
|
50
|
|
|
|
41
|
defined($name = $widget->{arg_order}[$posArgs++]) |
375
|
|
|
|
|
|
|
or die $self->generror("Too many args"); |
376
|
|
|
|
|
|
|
} |
377
|
92
|
|
|
|
|
220
|
my $formal = $add_arg->($name); |
378
|
90
|
100
|
|
|
|
234
|
unless (my $passThruVar = passThruVar($_)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
379
|
55
|
|
|
|
|
167
|
$self->as_cast_to($formal, argValue($_)); |
380
|
0
|
|
|
|
|
0
|
} elsif (my $actual = $self->find_var($passThruVar)) { |
381
|
30
|
100
|
100
|
|
|
166
|
if ($formal->already_escaped and not $actual->already_escaped) { |
382
|
|
|
|
|
|
|
# 受け手が escape 済みを期待しているのに、送り手がまだ escape されてないケース |
383
|
2
|
|
|
|
|
29
|
$self->as_escaped($actual); |
384
|
|
|
|
|
|
|
} else { |
385
|
28
|
|
|
|
|
73
|
$self->as_lvalue($actual); |
386
|
|
|
|
|
|
|
} |
387
|
0
|
50
|
|
|
|
0
|
} elsif (not defined argValue($_) and defined(my $v = $formal->flag)) { |
388
|
|
|
|
|
|
|
# フラグ立てとして扱って良い型の場合。 |
389
|
2
|
|
|
|
|
10
|
$v; |
390
|
|
|
|
|
|
|
} else { |
391
|
3
|
|
|
|
|
13
|
die $self->generror(q{valueless arg '%s'}, $passThruVar); |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
}); |
394
|
|
|
|
|
|
|
} @$primary; |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# element 引数 |
397
|
72
|
100
|
|
|
|
263
|
foreach my $arg (lexpand($head), $body ? $body : (), lexpand($foot)) { |
398
|
41
|
|
|
|
|
114
|
my ($name, $expr) = @$arg[NODE_PATH, NODE_VALUE]; |
399
|
41
|
100
|
|
|
|
141
|
my $formal = $add_arg->(ref $name ? $name->[-1] : $name); |
400
|
41
|
|
|
|
|
191
|
push @argExpr, ", ", $self->as_cast_to($formal, $expr); |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
# delegate の補間と、必須引数検査 |
404
|
70
|
|
|
|
|
143
|
foreach my $i (0 .. $#{$widget->{arg_order}}) { |
|
70
|
|
|
|
|
277
|
|
405
|
183
|
100
|
|
|
|
512
|
next if defined $argOrder[$i]; |
406
|
58
|
|
|
|
|
139
|
my $argName = $widget->{arg_order}[$i]; |
407
|
58
|
100
|
|
|
|
292
|
if (my $inherit = $delegate_vars->{$argName}) { |
|
|
100
|
|
|
|
|
|
408
|
7
|
|
|
|
|
17
|
push @argExpr, ', '. $self->as_lvalue($inherit); |
409
|
7
|
|
|
|
|
21
|
$argOrder[$inherit->argno] = ++$actualNo; |
410
|
|
|
|
|
|
|
} elsif ($widget->{arg_dict}{$argName}->is_required) { |
411
|
1
|
|
|
|
|
20
|
die $self->generror("Argument '%s' is missing", $argName); |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
sprintf q{(undef%s)[%s]} |
415
|
182
|
100
|
|
|
|
1311
|
, join("", @argExpr), join(", ", map {defined $_ ? $_ : 0} |
416
|
69
|
|
|
|
|
308
|
@argOrder[0 .. $#{$widget->{arg_order}}]); |
|
69
|
|
|
|
|
210
|
|
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
sub as_lvalue { |
419
|
878
|
|
|
878
|
0
|
1619
|
(my MY $self, my $var) = @_; |
420
|
878
|
|
|
|
|
2590
|
my $type = $var->type; |
421
|
878
|
100
|
|
|
|
4405
|
unless (defined $type) { |
|
|
50
|
|
|
|
|
|
422
|
0
|
|
|
|
|
0
|
die $self->generror("undefined var type"); |
423
|
0
|
|
|
|
|
0
|
} elsif (my $sub = $self->can("as_lvalue_" . $type->[0])) { |
424
|
28
|
|
|
|
|
76
|
$sub->($self, $var); |
425
|
|
|
|
|
|
|
} else { |
426
|
850
|
|
|
|
|
2468
|
'$'.$var->varname; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
sub as_lvalue_html { |
430
|
49
|
|
|
49
|
0
|
106
|
(my MY $self, my $var) = @_; |
431
|
49
|
|
|
|
|
134
|
'$html_'.$var->varname; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
sub as_varcall_code { |
434
|
20
|
|
|
20
|
0
|
61
|
(my MY $self, my ($codeVar, $node)) = @_; |
435
|
20
|
|
|
|
|
69
|
return \ sprintf q{$%1$s && $%1$s->(%2$s)}, $codeVar->varname |
436
|
|
|
|
|
|
|
, $self->gen_putargs($codeVar->widget, $node); |
437
|
|
|
|
|
|
|
# XXX: デフォルト body のように、引数宣言が無いケースも考慮せよ。 |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
sub as_varcall_delegate { |
440
|
3
|
|
|
3
|
0
|
11
|
(my MY $self, my ($var, $node)) = @_; |
441
|
3
|
|
|
|
|
12
|
my Widget $delegate = $var->widget; |
442
|
3
|
|
|
|
|
15
|
$self->ensure_generated(perl => my Template $tmpl = $delegate->{cf_folder}); |
443
|
3
|
50
|
|
|
|
19
|
my $that = $tmpl == $self->{curtmpl} ? '$this' : $tmpl->{cf_entns}; |
444
|
|
|
|
|
|
|
\ sprintf(q{%s->render_%s($CON, %s)} |
445
|
|
|
|
|
|
|
, $that, $delegate->{cf_name} |
446
|
3
|
|
|
|
|
14
|
, $self->gen_putargs($delegate, $node, $var->delegate_vars)); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
sub as_escaped { |
449
|
6
|
|
|
6
|
0
|
17
|
(my MY $self, my $var) = @_; |
450
|
6
|
50
|
|
|
|
27
|
if (my $sub = $self->can("as_escaped_" . $var->type->[0])) { |
451
|
0
|
|
|
|
|
0
|
$sub->($self, $var); |
452
|
|
|
|
|
|
|
} else { |
453
|
6
|
|
|
|
|
23
|
'YATT::Lite::Util::escape($'.$var->varname.')'; |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
#======================================== |
458
|
|
|
|
|
|
|
sub as_cast_to { |
459
|
139
|
|
|
139
|
0
|
321
|
(my MY $self, my $var, my $value) = @_; |
460
|
139
|
|
|
|
|
387
|
my $type = $var->type->[0]; |
461
|
139
|
50
|
|
|
|
777
|
my $sub = $self->can("as_cast_to_$type") |
462
|
|
|
|
|
|
|
or die $self->generror(q{Can't cast to type: %s}, $type); |
463
|
139
|
|
|
|
|
482
|
$sub->($self, $var, $value); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
sub as_cast_to_text { |
466
|
82
|
|
|
82
|
0
|
228
|
(my MY $self, my ($var, $value)) = @_; |
467
|
82
|
100
|
|
|
|
365
|
return qtext($value) unless ref $value; |
468
|
14
|
|
|
|
|
63
|
$self->as_text(@$value); |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
sub as_cast_to_attr { |
471
|
2
|
|
|
2
|
0
|
8
|
shift->as_cast_to_text(@_); |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
sub as_cast_to_html { |
474
|
16
|
|
|
16
|
0
|
40
|
(my MY $self, my ($var, $value)) = @_; |
475
|
16
|
100
|
|
|
|
51
|
unless (ref $value) { |
476
|
4
|
|
|
|
|
15
|
$self->{curline} += numLines($value); |
477
|
4
|
|
|
|
|
16
|
return qtext($value); |
478
|
|
|
|
|
|
|
} |
479
|
12
|
|
|
|
|
51
|
join '.', shift->gen_as(text => \@AS_TEXT, 1, 1, @$value); |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
sub as_cast_to_scalar { |
482
|
6
|
|
|
6
|
0
|
23
|
(my MY $self, my ($var, $value)) = @_; |
483
|
6
|
100
|
|
|
|
49
|
'scalar(do {'.(ref $value ? $self->as_list(@$value) : $value).'})'; |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
sub as_cast_to_bool { |
486
|
0
|
|
|
0
|
0
|
0
|
shift->as_cast_to_scalar(@_); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
sub as_cast_to_list { |
489
|
3
|
|
|
3
|
0
|
10
|
(my MY $self, my ($var, $value)) = @_; |
490
|
3
|
100
|
|
|
|
33
|
'['.(ref $value ? $self->as_list(@$value) : $value).']'; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
sub as_cast_to_code { |
493
|
32
|
|
|
32
|
0
|
79
|
(my MY $self, my ($var, $value)) = @_; |
494
|
32
|
|
|
|
|
136
|
local $self->{curtoks} = [@$value]; |
495
|
32
|
|
|
|
|
113
|
my Widget $virtual = $var->widget; |
496
|
|
|
|
|
|
|
local $self->{scope} = $self->mkscope |
497
|
32
|
|
100
|
|
|
255
|
({}, $virtual->{arg_dict} ||= {}, $self->{scope}); |
498
|
32
|
|
|
|
|
82
|
local $self->{no_last_newline} = 1; |
499
|
32
|
|
|
|
|
107
|
q|sub {|. join('', $self->gen_getargs($virtual) |
500
|
|
|
|
|
|
|
, $self->as_print("}")); |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
#---------------------------------------- |
503
|
|
|
|
|
|
|
sub argName { |
504
|
145
|
|
|
145
|
0
|
354
|
my ($arg, $skip) = @_; |
505
|
145
|
|
|
|
|
304
|
my $name = $$arg[NODE_PATH]; |
506
|
145
|
100
|
100
|
|
|
555
|
unless (wantarray and ref $name) { |
|
|
100
|
|
|
|
|
|
507
|
137
|
|
|
|
|
373
|
$name; |
508
|
0
|
|
|
|
|
0
|
} elsif (defined $skip) { |
509
|
2
|
|
|
|
|
6
|
@{$name}[$skip .. $#$name]; |
|
2
|
|
|
|
|
7
|
|
510
|
|
|
|
|
|
|
} else { |
511
|
6
|
|
|
|
|
22
|
@$name; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
} |
514
|
94
|
|
|
94
|
0
|
185
|
sub argValue { my $arg = shift; $$arg[NODE_VALUE] } |
|
94
|
|
|
|
|
410
|
|
515
|
|
|
|
|
|
|
sub passThruVar { |
516
|
98
|
|
|
98
|
0
|
181
|
my $arg = shift; |
517
|
98
|
100
|
|
|
|
439
|
if ($arg->[NODE_TYPE] == TYPE_ATT_NAMEONLY) { |
|
|
100
|
|
|
|
|
|
518
|
33
|
|
|
|
|
163
|
$$arg[NODE_PATH] |
519
|
|
|
|
|
|
|
} elsif ($arg->[NODE_TYPE] == TYPE_ATT_BARENAME) { |
520
|
8
|
|
|
|
|
47
|
$$arg[NODE_VALUE] |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
#======================================== |
524
|
|
|
|
|
|
|
sub from_pi { |
525
|
37
|
|
|
37
|
0
|
91
|
(my MY $self, my $node) = @_; |
526
|
|
|
|
|
|
|
# pi の ns 毎の役割を拡張可能に |
527
|
37
|
50
|
|
|
|
294
|
if (my $sub = $self->can("pi_of_" . $node->[NODE_PATH][0])) { |
528
|
0
|
|
|
|
|
0
|
return $sub->($self, $node); |
529
|
|
|
|
|
|
|
} |
530
|
37
|
|
|
|
|
131
|
$self->sync_curline($node->[NODE_LNO]); |
531
|
37
|
|
|
|
|
127
|
my @body = nx($node, 1); |
532
|
37
|
|
|
|
|
75
|
my ($fmt, $is_statement) = do { |
533
|
37
|
100
|
|
|
|
177
|
unless ($body[0] =~ s/^=+//) { |
|
|
100
|
|
|
|
|
|
534
|
25
|
|
|
|
|
57
|
(q{%s}, 1); |
535
|
0
|
|
|
|
|
0
|
} elsif (length $& >= 3) { |
536
|
6
|
|
|
|
|
19
|
q{do {%s}}; |
537
|
|
|
|
|
|
|
} else { |
538
|
6
|
|
|
|
|
24
|
q{YATT::Lite::Util::escape(do {%s})}; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
}; |
541
|
37
|
|
|
|
|
160
|
my $expr = join '', $self->as_list(@body); |
542
|
37
|
100
|
|
|
|
212
|
return \ "" unless $expr =~ /\S/; |
543
|
36
|
|
|
|
|
117
|
my $script = sprintf $fmt, $expr; |
544
|
36
|
100
|
|
|
|
128
|
$is_statement ? \ $script : $script; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
#======================================== |
547
|
|
|
|
0
|
0
|
|
sub from_lineinfo { } |
548
|
|
|
|
|
|
|
sub from_comment { |
549
|
2
|
|
|
2
|
0
|
5
|
(my MY $self, my $node) = @_; |
550
|
2
|
|
|
|
|
7
|
(undef, my ($nlines, $body)) = nx($node); # XXX: ok? |
551
|
2
|
|
|
|
|
5
|
$self->{curline} += $nlines; |
552
|
2
|
|
|
|
|
7
|
return \ ("\n" x $nlines); |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
sub from_lcmsg { |
555
|
3
|
|
|
3
|
0
|
8
|
(my MY $self, my $node) = @_; |
556
|
3
|
|
|
|
|
10
|
my ($path, $body) = nx($node); |
557
|
|
|
|
|
|
|
# $body is list of tokenlist. |
558
|
3
|
|
|
|
|
12
|
my $place = $self->{curtmpl}->fake_filename . ":" . $node->[NODE_LNO]; |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
# XXX: builtin xgettext |
561
|
3
|
100
|
66
|
|
|
17
|
if (@$body >= 2 or @$path >= 2) { |
562
|
|
|
|
|
|
|
# ngettext |
563
|
1
|
|
|
|
|
4
|
my ($uniq, $args, $numexpr) = ({}, []); |
564
|
|
|
|
|
|
|
my ($msgid, @plural) = map { |
565
|
1
|
|
|
|
|
3
|
scalar $self->gen_lcmsg($node, $_, $uniq, $args, \$numexpr); |
|
2
|
|
|
|
|
8
|
|
566
|
|
|
|
|
|
|
} @$body; |
567
|
1
|
50
|
|
|
|
5
|
if (my $sub = $self->{cf_lcmsg_sink}) { |
568
|
1
|
|
|
|
|
6
|
$sub->($place, $msgid, \@plural, $args); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
sprintf q{sprintf($CON->ngettext(%s, %s), %s)} |
571
|
1
|
|
|
|
|
10
|
, join(", ", map {qtext($_)} ($msgid, @plural)) |
|
2
|
|
|
|
|
7
|
|
572
|
|
|
|
|
|
|
, $numexpr, join(", ", @$args); |
573
|
|
|
|
|
|
|
} else { |
574
|
2
|
|
|
|
|
11
|
my ($msgid, @args) = $self->gen_lcmsg($node, $body->[0]); |
575
|
2
|
50
|
|
|
|
9
|
if (my $sub = $self->{cf_lcmsg_sink}) { |
576
|
2
|
|
|
|
|
7
|
$sub->($place, $msgid, undef, \@args); |
577
|
|
|
|
|
|
|
} |
578
|
2
|
|
|
|
|
17
|
sprintf q{sprintf($CON->gettext(%s), %s)} |
579
|
|
|
|
|
|
|
, qtext($msgid), join(", ", @args); |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
sub gen_lcmsg { |
583
|
4
|
|
|
4
|
0
|
10
|
(my MY $self, my ($node, $list, $uniq, $args, $ref_numeric)) = @_; |
584
|
4
|
|
|
|
|
7
|
my ($msgid, $vspec) = (""); |
585
|
4
|
100
|
33
|
|
|
54
|
if (@$list >= 2 and not ref $list->[0] and not ref $list->[-1] |
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
586
|
|
|
|
|
|
|
and $list->[0] =~ /^\n+$/ and $list->[-1] =~ /^\n+$/) { |
587
|
2
|
|
|
|
|
5
|
shift @$list; pop @$list; |
|
2
|
|
|
|
|
5
|
|
588
|
2
|
50
|
33
|
|
|
10
|
if (@$list and not ref $list->[0]) { |
589
|
2
|
|
|
|
|
7
|
$list->[0] =~ s/^\s+//; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
} |
592
|
4
|
|
|
|
|
13
|
foreach my $item (@$list) { |
593
|
12
|
50
|
|
|
|
64
|
unless (ref $item) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
594
|
|
|
|
|
|
|
# XXX: How about backslash? |
595
|
7
|
|
|
|
|
20
|
(my $cp = $item) =~ s/%/%%/g; |
596
|
7
|
|
|
|
|
16
|
$msgid .= $cp; |
597
|
0
|
|
|
|
|
0
|
} elsif ($item->[NODE_TYPE] != TYPE_ENTITY) { |
598
|
0
|
|
|
|
|
0
|
die "SYNERR"; |
599
|
0
|
50
|
|
|
|
0
|
} elsif (ref ($vspec = $item->[NODE_BODY]) ne 'ARRAY' |
600
|
|
|
|
|
|
|
|| $vspec->[0] ne 'var') { |
601
|
|
|
|
|
|
|
# || @$vspec != 2 |
602
|
0
|
|
|
|
|
0
|
die "SYNERR"; |
603
|
|
|
|
|
|
|
} else { |
604
|
5
|
|
|
|
|
11
|
my $name = $vspec->[1]; |
605
|
5
|
50
|
|
|
|
15
|
my $var = $self->find_var($name) |
606
|
|
|
|
|
|
|
or die $self->generror(q{No such variable '%s'}, $name); |
607
|
5
|
100
|
|
|
|
15
|
unless ($uniq->{$name}) { |
608
|
4
|
|
|
|
|
16
|
push @$args, $self->as_escaped($var); |
609
|
4
|
|
|
|
|
15
|
$uniq->{$name} = 1 + keys %$uniq; |
610
|
|
|
|
|
|
|
} |
611
|
5
|
100
|
|
|
|
14
|
my $argno = $ref_numeric ? $uniq->{$name} . '$' : ''; |
612
|
|
|
|
|
|
|
# XXX: type==value is alias of scalar. |
613
|
5
|
100
|
100
|
|
|
60
|
if ($ref_numeric and $var->type->[0] eq 'scalar') { |
614
|
1
|
|
|
|
|
3
|
$msgid .= "%${argno}d"; # XXX: format selection... but how? from entity? |
615
|
1
|
50
|
|
|
|
5
|
if ($$ref_numeric) { |
616
|
0
|
|
|
|
|
0
|
die "SYNERR"; |
617
|
|
|
|
|
|
|
} |
618
|
1
|
|
|
|
|
3
|
$$ref_numeric = $self->as_lvalue($var); |
619
|
|
|
|
|
|
|
} else { |
620
|
4
|
|
|
|
|
14
|
$msgid .= "%${argno}s"; |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
} |
624
|
4
|
|
|
|
|
9
|
$msgid =~ s/\r//g; |
625
|
|
|
|
|
|
|
# XXX: Unfortunately, this is not good for multiline message. |
626
|
4
|
100
|
|
|
|
19
|
wantarray ? ($msgid, lexpand($args)) : $msgid; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
sub from_elematt { |
630
|
0
|
|
|
0
|
0
|
0
|
(my MY $self, my $node) = @_; |
631
|
|
|
|
|
|
|
# <:yatt:elematt>.... は NOP へ。 |
632
|
0
|
|
|
|
|
0
|
return \ ""; |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
sub from_entity { |
635
|
355
|
|
|
355
|
0
|
794
|
(my MY $self, my $node) = @_; |
636
|
355
|
|
|
|
|
1054
|
(undef, my @pipe) = nx($node); |
637
|
|
|
|
|
|
|
# XXX: expand のように全体に作用するものも有るから、これも現在の式を渡す方式にすべき。 |
638
|
|
|
|
|
|
|
# 受け手が有るかどうかで式の生成方式も変わる?なら token リスト削りが良いか。 |
639
|
355
|
|
|
|
|
1372
|
$self->gen_entpath($self->{needs_escaping}, @pipe); |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# XXX: lxnest を caller が呼ぶ必要が有る...が、それって良いことなのか... |
643
|
|
|
|
|
|
|
sub gen_entpath { |
644
|
830
|
|
|
830
|
0
|
1813
|
(my MY $self, my ($escape_now)) = splice @_, 0, 2; |
645
|
830
|
50
|
|
|
|
1871
|
return '' unless @_; |
646
|
830
|
|
|
|
|
1770
|
local $self->{needs_escaping} = 0; |
647
|
830
|
100
|
100
|
|
|
5431
|
if (@_ == 1 and $_[0][0] eq 'call' |
|
|
|
100
|
|
|
|
|
648
|
|
|
|
|
|
|
and my $macro = $self->can("entmacro_$_[0][1]")) { |
649
|
108
|
|
|
|
|
302
|
return $macro->($self, $_[0]); |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
# XXX: path の先頭と以後は分けないと! as_head, as_rest? |
652
|
|
|
|
|
|
|
my @result = map { |
653
|
722
|
|
|
|
|
1434
|
my ($type, @rest) = @$_; |
|
760
|
|
|
|
|
1779
|
|
654
|
760
|
50
|
|
|
|
3158
|
unless (my $sub = $self->can("as_expr_$type")) { |
655
|
0
|
|
|
|
|
0
|
die $self->generror("unknown entity item %s", terse_dump($type)); |
656
|
|
|
|
|
|
|
} else { |
657
|
760
|
|
|
|
|
2063
|
$sub->($self, \$escape_now, @rest); |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
} @_; |
660
|
713
|
50
|
|
|
|
1888
|
return '' unless @result; |
661
|
713
|
100
|
|
|
|
1751
|
my $result = @result > 1 ? join("->", @result) : $result[0]; |
662
|
|
|
|
|
|
|
# XXX: これだと逆に、 html 型が困る。 |
663
|
713
|
100
|
100
|
|
|
2244
|
if (not $escape_now or ref $result) { |
664
|
526
|
|
|
|
|
1575
|
$result; |
665
|
|
|
|
|
|
|
} else { |
666
|
187
|
|
|
|
|
922
|
sprintf(q{YATT::Lite::Util::escape(%s)}, $result); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
sub gen_entlist { |
670
|
262
|
|
|
262
|
0
|
626
|
(my MY $self, my ($escape_now)) = splice @_, 0, 2; |
671
|
|
|
|
|
|
|
my @list = map { |
672
|
262
|
|
|
|
|
546
|
$self->gen_entpath($escape_now, lxnest($_)) |
|
439
|
|
|
|
|
1175
|
|
673
|
|
|
|
|
|
|
} @_; |
674
|
262
|
100
|
|
|
|
1282
|
wantarray ? @list : join ", ", @list; |
675
|
|
|
|
|
|
|
} |
676
|
|
|
|
|
|
|
sub as_expr_var { |
677
|
230
|
|
|
230
|
0
|
580
|
(my MY $self, my ($esc_later, $name)) = @_; |
678
|
230
|
100
|
|
|
|
751
|
my $var = $self->find_var($name) |
679
|
|
|
|
|
|
|
or die $self->generror(q{No such variable '%s'}, $name); |
680
|
222
|
100
|
|
|
|
763
|
if (my $sub = $self->can("as_expr_var_" . $var->type->[0])) { |
681
|
26
|
|
|
|
|
83
|
$sub->($self, $esc_later, $var, $name); |
682
|
|
|
|
|
|
|
} else { |
683
|
196
|
|
|
|
|
527
|
$self->as_lvalue($var); |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
sub as_expr_var_html { |
687
|
21
|
|
|
21
|
0
|
56
|
(my MY $self, my ($esc_later, $var, $name)) = @_; |
688
|
21
|
|
|
|
|
43
|
$$esc_later = 0; |
689
|
21
|
|
|
|
|
58
|
$self->as_lvalue_html($var); |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
sub as_expr_var_attr { |
692
|
5
|
|
|
5
|
0
|
11
|
(my MY $self, my ($esc_later, $var, $name)) = @_; |
693
|
|
|
|
|
|
|
# $$esc_later = 0; |
694
|
5
|
|
|
|
|
9
|
(undef, my $attname) = @{$var->type}; |
|
5
|
|
|
|
|
13
|
|
695
|
5
|
|
33
|
|
|
43
|
sprintf(q{YATT::Lite::Util::named_attr('%s', $%s)} |
696
|
|
|
|
|
|
|
, $attname // $name, $name); |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
sub as_expr_call { |
699
|
150
|
|
|
150
|
0
|
425
|
(my MY $self, my ($esc_later, $name)) = splice @_, 0, 3; |
700
|
|
|
|
|
|
|
# XXX: 受け側が print か、それとも一般の式か。 print なら \ すべき。 |
701
|
|
|
|
|
|
|
# entns があるか、find_code_var か。さもなければエラーよね。 |
702
|
150
|
100
|
|
|
|
575
|
if (my $var = $self->find_callable_var($name)) { |
703
|
|
|
|
|
|
|
# code 引数の中の引数のデフォルト値の中に、改行が有ったら?? |
704
|
|
|
|
|
|
|
# XXX: body の引数宣言が無い場合に は、ちゃんと呼び出せるか? |
705
|
11
|
|
|
|
|
51
|
return $self->as_expr_call_var($var, $name, @_); |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
139
|
|
|
|
|
509
|
my Template $tmpl = $self->{curtmpl}; |
709
|
139
|
100
|
|
|
|
2228
|
unless ($tmpl->{cf_entns}->can("entity_$name")) { |
710
|
|
|
|
|
|
|
die $self->generror(q!No such entity in namespace "%s": %s! |
711
|
1
|
|
|
|
|
4
|
, $tmpl->{cf_entns}, $name); |
712
|
|
|
|
|
|
|
} |
713
|
138
|
|
|
|
|
552
|
my $call = sprintf '$this->entity_%s(%s)', $name |
714
|
|
|
|
|
|
|
, scalar $self->gen_entlist(undef, @_); |
715
|
138
|
|
|
|
|
521
|
$call; |
716
|
|
|
|
|
|
|
} |
717
|
|
|
|
|
|
|
sub as_expr_call_var { |
718
|
11
|
|
|
11
|
0
|
33
|
(my MY $self, my ($var, $name, @args)) = @_; |
719
|
11
|
100
|
|
|
|
40
|
if (my $sub = $self->can("as_expr_call_var_" . $var->type->[0])) { |
720
|
1
|
|
|
|
|
10
|
$sub->($self, $var, $name, @args); |
721
|
|
|
|
|
|
|
} else { |
722
|
10
|
|
|
|
|
47
|
\ sprintf q{$%1$s && $%1$s->(%2$s)}, $name |
723
|
|
|
|
|
|
|
, scalar $self->gen_entlist(undef, @args); |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
sub as_expr_call_var_attr { |
727
|
1
|
|
|
1
|
0
|
5
|
(my MY $self, my ($var, $name, @args)) = @_; |
728
|
1
|
|
|
|
|
3
|
(undef, my $attname) = @{$var->type}; |
|
1
|
|
|
|
|
5
|
|
729
|
1
|
|
33
|
|
|
9
|
sprintf q|YATT::Lite::Util::named_attr('%s', %s)| |
730
|
|
|
|
|
|
|
, $attname // $name |
731
|
|
|
|
|
|
|
, join ", ", '$'.$name, $self->gen_entlist(undef, @args); |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
sub as_expr_invoke { |
734
|
5
|
|
|
5
|
0
|
18
|
(my MY $self, my ($esc_later, $name)) = splice @_, 0, 3; |
735
|
5
|
|
|
|
|
37
|
sprintf '%s(%s)', $name |
736
|
|
|
|
|
|
|
, scalar $self->gen_entlist(undef, @_); |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub as_expr_expr { |
740
|
21
|
|
|
21
|
0
|
53
|
(my MY $self, my ($esc_later, $expr)) = @_; |
741
|
21
|
|
|
|
|
69
|
$expr; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
sub as_expr_array { |
744
|
5
|
|
|
5
|
0
|
12
|
(my MY $self, my ($esc_later)) = splice @_, 0, 2; |
745
|
5
|
|
|
|
|
22
|
'['.$self->gen_entlist(undef, @_).']'; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
sub as_expr_hash { |
748
|
0
|
|
|
0
|
0
|
0
|
(my MY $self, my ($esc_later)) = splice @_, 0, 2; |
749
|
0
|
|
|
|
|
0
|
'{'.$self->gen_entlist(undef, @_).'}'; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
sub as_expr_aref { |
752
|
21
|
|
|
21
|
0
|
54
|
(my MY $self, my ($esc_later, $node)) = @_; |
753
|
21
|
|
|
|
|
61
|
'['.$self->gen_entpath(undef, lxnest($node)).']'; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
sub as_expr_href { |
756
|
10
|
|
|
10
|
0
|
31
|
(my MY $self, my ($esc_later, $node)) = @_; |
757
|
10
|
|
|
|
|
41
|
'{'.$self->gen_entpath(undef, lxnest($node)).'}'; |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
sub as_expr_prop { |
760
|
2
|
|
|
2
|
0
|
5
|
(my MY $self, my ($esc_later, $name)) = @_; |
761
|
2
|
50
|
|
|
|
18
|
if ($name =~ /^\w+$/) { |
762
|
2
|
|
|
|
|
10
|
"{$name}" |
763
|
|
|
|
|
|
|
} else { |
764
|
0
|
|
|
|
|
0
|
'{'.qtext($name).'}'; |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
} |
767
|
|
|
|
|
|
|
sub as_expr_text { |
768
|
316
|
|
|
316
|
0
|
615
|
(my MY $self, my ($esc_later, $expr)) = @_; |
769
|
316
|
|
|
|
|
762
|
qqvalue($expr); |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
#======================================== |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
sub make_arg_spec { |
775
|
30
|
|
|
30
|
0
|
95
|
my ($pack, $dict, $order) = splice @_, 0, 3; |
776
|
30
|
|
|
|
|
72
|
foreach my $name (@_) { |
777
|
75
|
|
|
|
|
174
|
$dict->{$name} = @$order; |
778
|
75
|
|
|
|
|
168
|
push @$order, $name; |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
} |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
sub feed_arg_spec { |
783
|
23
|
|
|
23
|
0
|
70
|
(my MY $trans, my ($args, $arg_dict, $arg_order)) = splice @_, 0, 4; |
784
|
23
|
|
|
|
|
50
|
my ($found, $nth); |
785
|
23
|
|
|
|
|
71
|
foreach my $arg (lexpand($args)) { |
786
|
27
|
|
|
|
|
84
|
my ($name, @ext) = argName($arg); # XXX: は? |
787
|
27
|
100
|
|
|
|
80
|
unless (defined $name) { |
788
|
7
|
50
|
|
|
|
35
|
$name = $arg_order->[$nth++] |
789
|
|
|
|
|
|
|
or die $trans->generror($arg, "Too many args"); |
790
|
|
|
|
|
|
|
} |
791
|
27
|
50
|
|
|
|
84
|
defined (my $argno = $arg_dict->{$name}) |
792
|
|
|
|
|
|
|
or die $trans->generror($arg, "Unknown arg '%s'", $name); |
793
|
|
|
|
|
|
|
|
794
|
27
|
|
|
|
|
51
|
$_[$argno] = $arg; |
795
|
27
|
|
|
|
|
57
|
$found++; |
796
|
|
|
|
|
|
|
} |
797
|
23
|
|
|
|
|
73
|
$found; |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
{ |
801
|
|
|
|
|
|
|
MY->make_arg_spec(\ my %args, \ my @args, qw(if unless)); |
802
|
|
|
|
|
|
|
sub macro_if { |
803
|
9
|
|
|
9
|
0
|
19
|
(my MY $self, my $node) = @_; |
804
|
9
|
|
|
|
|
40
|
my ($path, $body, $primary, $head, $foot) = nx($node); |
805
|
9
|
|
|
|
|
26
|
my @arms = do { |
806
|
9
|
50
|
|
|
|
45
|
$self->feed_arg_spec($primary, \%args, \@args |
807
|
|
|
|
|
|
|
, my ($if, $unless)) |
808
|
|
|
|
|
|
|
or die $self->generror("Not enough arguments!"); |
809
|
9
|
|
|
|
|
23
|
my ($kw, $cond) = do { |
810
|
9
|
50
|
|
|
|
25
|
if ($if) { (if => $if) } |
|
9
|
0
|
|
|
|
48
|
|
811
|
0
|
|
|
|
|
0
|
elsif ($unless) { (unless => $unless) } |
812
|
0
|
|
|
|
|
0
|
else { die "??" } |
813
|
|
|
|
|
|
|
}; |
814
|
9
|
|
|
|
|
40
|
["$kw (%s) ", $cond->[NODE_VALUE], lexpand($body->[NODE_VALUE])]; |
815
|
|
|
|
|
|
|
}; |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
# いかん、 cond を生成するなら、body も生成しておかないと、行番号が困る。 |
818
|
|
|
|
|
|
|
|
819
|
9
|
|
|
|
|
31
|
foreach my $arg (lexpand($foot)) { |
820
|
6
|
50
|
|
|
|
21
|
if ($arg->[NODE_PATH][-1] eq 'else') { |
821
|
6
|
|
|
|
|
25
|
$self->feed_arg_spec($arg->[NODE_ATTLIST], \%args, \@args |
822
|
|
|
|
|
|
|
, my ($if, $unless)); |
823
|
6
|
|
|
|
|
13
|
my ($fmt, $guard) = do { |
824
|
6
|
100
|
|
|
|
22
|
if ($if) { (q{elsif (%s) }, $if->[NODE_VALUE]) } |
|
2
|
50
|
|
|
|
6
|
|
825
|
0
|
|
|
|
|
0
|
elsif ($unless) { (q{elsif (not %s) }, $unless->[NODE_VALUE]) } |
826
|
4
|
|
|
|
|
12
|
else { (q{else }, undef) } |
827
|
|
|
|
|
|
|
}; |
828
|
6
|
|
|
|
|
20
|
push @arms, [$fmt, $guard, lexpand($arg->[NODE_VALUE])] |
829
|
|
|
|
|
|
|
} else { |
830
|
0
|
|
|
|
|
0
|
push @{$arms[-1]}, lexpand($arg->[NODE_VALUE]); |
|
0
|
|
|
|
|
0
|
|
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
} |
833
|
9
|
|
|
|
|
41
|
local $self->{scope} = $self->mkscope({}, $self->{scope}); |
834
|
|
|
|
|
|
|
my @expr = map { |
835
|
9
|
|
|
|
|
26
|
my ($fmt, $guard, @body) = @$_; |
|
15
|
|
|
|
|
47
|
|
836
|
15
|
|
|
|
|
43
|
local $self->{curtoks} = [@body]; |
837
|
15
|
100
|
|
|
|
67
|
(defined $guard |
838
|
|
|
|
|
|
|
? sprintf($fmt, join "", $self->as_list(lexpand($guard))) : $fmt) |
839
|
|
|
|
|
|
|
.'{'.$self->cut_next_nl.$self->as_print('}'); |
840
|
|
|
|
|
|
|
} @arms; |
841
|
9
|
|
|
|
|
33
|
\ join "", @expr, $self->cut_next_nl; |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
{ |
846
|
|
|
|
|
|
|
sub macro_my { |
847
|
16
|
|
|
16
|
0
|
36
|
(my MY $self, my $node) = @_; |
848
|
16
|
|
|
|
|
60
|
my ($path, $body, $primary, $head, $foot) = nx($node); |
849
|
|
|
|
|
|
|
|
850
|
16
|
100
|
66
|
|
|
84
|
my $has_body = $body && @$body ? 1 : 0; |
851
|
|
|
|
|
|
|
my $adder = sub { |
852
|
26
|
|
|
26
|
|
60
|
my ($default_type, $arg, $valNode, $skip) = @_; |
853
|
26
|
|
|
|
|
79
|
my ($name, $typename) = argName($arg, $skip); |
854
|
26
|
100
|
|
|
|
97
|
if (my $oldvar = $self->find_var($name)) { |
855
|
1
|
|
50
|
|
|
7
|
die $self->generror("Conflicting variable '%s'" |
856
|
|
|
|
|
|
|
." (previously defined at line %s)" |
857
|
|
|
|
|
|
|
, $name, $oldvar->lineno // '(unknown)'); |
858
|
|
|
|
|
|
|
} |
859
|
25
|
|
66
|
|
|
110
|
$typename ||= $default_type; |
860
|
25
|
100
|
|
|
|
184
|
if (my $sub = $self->can("_macro_my_$typename")) { |
861
|
3
|
|
|
|
|
12
|
$sub->($self, $node, $name, $valNode); |
862
|
|
|
|
|
|
|
} else { |
863
|
22
|
50
|
|
|
|
87
|
my $var = $self->{scope}[0]{$name} |
864
|
|
|
|
|
|
|
= $self->mkvar_at(undef, $typename, $name) |
865
|
|
|
|
|
|
|
or die $self->generror("Unknown type '%s' for variable '%s'" |
866
|
|
|
|
|
|
|
, $typename, $name); |
867
|
|
|
|
|
|
|
# typename == source の時が問題だ。 |
868
|
22
|
|
|
|
|
72
|
my $expr = 'my '.$self->as_lvalue($var); |
869
|
22
|
|
|
|
|
62
|
my $value = argValue($valNode); |
870
|
22
|
100
|
|
|
|
97
|
$expr .= $value ? (' = '.$self->as_cast_to($var, $value)) : ';'; |
871
|
|
|
|
|
|
|
} |
872
|
16
|
|
|
|
|
102
|
}; |
873
|
16
|
|
|
|
|
33
|
my @assign; |
874
|
16
|
|
|
|
|
46
|
foreach my $arg (@{$primary}[0 .. $#$primary-$has_body]) { |
|
16
|
|
|
|
|
45
|
|
875
|
17
|
|
|
|
|
46
|
push @assign, $adder->(text => $arg, $arg); |
876
|
|
|
|
|
|
|
} |
877
|
15
|
100
|
|
|
|
56
|
if ($has_body) { |
878
|
6
|
|
|
|
|
16
|
my $arg = $primary->[-1]; |
879
|
|
|
|
|
|
|
# XXX: ここは統合できるはず。ただし、NESTED の時に name が無いことを確認すべき。 |
880
|
6
|
100
|
|
|
|
18
|
if ($$arg[NODE_TYPE] == TYPE_ATT_NESTED) { |
881
|
1
|
|
|
|
|
6
|
foreach my $each (nx($arg, 1)) { |
882
|
2
|
|
|
|
|
6
|
push @assign, $adder->(html => $each, $body); |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
} else { |
885
|
5
|
|
|
|
|
19
|
push @assign, $adder->(html => $arg, $body); |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
} |
888
|
15
|
|
|
|
|
37
|
foreach my $arg (map {lexpand($_)} $head, $foot) { |
|
30
|
|
|
|
|
79
|
|
889
|
2
|
|
|
|
|
7
|
push @assign, $adder->(text => $arg, $arg, 1); # Skip leading :yatt: |
890
|
|
|
|
|
|
|
} |
891
|
15
|
|
|
|
|
159
|
\ join "; ", @assign; |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
sub _macro_my_code { |
894
|
2
|
|
|
2
|
|
7
|
(my MY $self, my ($node, $name, $valNode)) = @_; |
895
|
2
|
|
|
|
|
9
|
my $var = $self->{scope}[0]{$name} = $self->mkvar_at(undef, code => $name); |
896
|
2
|
|
|
|
|
6
|
local $self->{curtoks} = [lexpand(argValue($valNode))]; |
897
|
2
|
|
|
|
|
9
|
'my '.$self->as_lvalue($var).' = '.q|sub {| . $self->as_print('}'); |
898
|
|
|
|
|
|
|
} |
899
|
|
|
|
|
|
|
sub _macro_my_source { |
900
|
1
|
|
|
1
|
|
5
|
(my MY $self, my ($node, $name, $valNode)) = @_; |
901
|
1
|
|
|
|
|
6
|
my $var = $self->{scope}[0]{$name} = $self->mkvar_at(undef, text => $name); |
902
|
|
|
|
|
|
|
'my '.$self->as_lvalue($var).' = ' |
903
|
2
|
|
|
|
|
8
|
.join(q|."\n".|, map {qtext($_)} |
904
|
1
|
|
|
|
|
6
|
split /\n/, $self->{curtmpl}->node_body_source($node)); |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
sub macro_block { |
908
|
3
|
|
|
3
|
0
|
6
|
(my MY $self, my $node) = @_; |
909
|
3
|
|
|
|
|
11
|
my ($path, $body, $primary, $head, $foot) = nx($node); |
910
|
3
|
|
|
|
|
7
|
$self->macro_scoped_block_of_tokens(+{}, @{argValue($body)}); |
|
3
|
|
|
|
|
10
|
|
911
|
|
|
|
|
|
|
} |
912
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
sub macro_scoped_block_of_tokens { |
914
|
3
|
|
|
3
|
0
|
13
|
(my MY $self, my ($scope, @tokens)) = @_; |
915
|
3
|
|
|
|
|
10
|
local $self->{scope} = $self->mkscope($scope, $self->{scope}); |
916
|
3
|
|
|
|
|
8
|
local $self->{curtoks} = \@tokens; |
917
|
3
|
|
|
|
|
10
|
\ ('{'.$self->as_print('}')); |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
} |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
{ |
922
|
|
|
|
|
|
|
MY->make_arg_spec(\ my %args, \ my @args, qw(list my nth)); |
923
|
|
|
|
|
|
|
sub macro_foreach { |
924
|
8
|
|
|
8
|
0
|
25
|
(my MY $self, my ($node, $opts)) = @_; |
925
|
8
|
|
|
|
|
38
|
my ($path, $body, $primary, $head, $foot) = nx($node); |
926
|
8
|
50
|
|
|
|
56
|
$self->feed_arg_spec($primary, \%args, \@args |
927
|
|
|
|
|
|
|
, my ($list, $my, $nth)) |
928
|
|
|
|
|
|
|
or die $self->generror("Not enough arguments!"); |
929
|
|
|
|
|
|
|
|
930
|
8
|
|
|
|
|
31
|
my ($prologue, $continue, $epilogue) = ('', '', ''); |
931
|
|
|
|
|
|
|
|
932
|
8
|
50
|
|
|
|
25
|
unless (defined $list) { |
933
|
0
|
|
|
|
|
0
|
die $self->generror("no list= is given"); |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
|
936
|
8
|
|
|
|
|
16
|
my %local; |
937
|
8
|
|
|
|
|
15
|
my $loopvar = do { |
938
|
8
|
100
|
|
|
|
20
|
if ($my) { |
939
|
7
|
|
|
|
|
23
|
my ($x, @type) = lexpand($my->[NODE_PATH]); |
940
|
7
|
|
|
|
|
16
|
my $varname = $my->[NODE_VALUE]; |
941
|
7
|
|
50
|
|
|
59
|
$local{$varname} = $self->mkvar_at(undef, $type[0] || '' => $varname); |
942
|
7
|
|
|
|
|
22
|
'my $' . $varname; |
943
|
|
|
|
|
|
|
} else { |
944
|
|
|
|
|
|
|
# _ は? entity 自体に処理させるか… |
945
|
1
|
|
|
|
|
2
|
'' |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
}; |
948
|
|
|
|
|
|
|
|
949
|
8
|
|
|
|
|
17
|
my ($nth_var, @nth_type) = do { |
950
|
8
|
100
|
66
|
|
|
39
|
if ($nth and my $vn = $nth->[NODE_VALUE]) { |
951
|
1
|
|
|
|
|
5
|
my ($x, @t) = lexpand($nth->[NODE_PATH]); |
952
|
1
|
50
|
|
|
|
7
|
if ($vn =~ /^(\w+)$/) { |
953
|
1
|
|
|
|
|
5
|
($vn, @t); |
954
|
|
|
|
|
|
|
} else { |
955
|
0
|
|
|
|
|
0
|
die $self->generror("Invalid nth var: %s", $nth); |
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
}; |
959
|
8
|
100
|
|
|
|
28
|
if ($nth_var) { |
960
|
1
|
|
50
|
|
|
8
|
$local{$nth_var} = $self->mkvar_at(undef, $nth_type[0] || '' => $nth_var); |
961
|
|
|
|
|
|
|
|
962
|
1
|
|
|
|
|
4
|
$prologue .= sprintf q{ my $%s = 1;}, $nth_var; |
963
|
1
|
|
|
|
|
4
|
$continue .= sprintf q{ $%s++;}, $nth_var; |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
|
966
|
8
|
|
|
|
|
21
|
my $fmt = q|{%4$s; foreach %1$s (%2$s) %3$s continue {%5$s} %6$s}|; |
967
|
8
|
|
|
|
|
16
|
my $listexpr = do { |
968
|
8
|
50
|
|
|
|
32
|
unless (my $passThruVarName = passThruVar($list)) { |
|
|
100
|
|
|
|
|
|
969
|
2
|
|
|
|
|
10
|
$self->as_list(lexpand($list->[NODE_VALUE])); |
970
|
0
|
|
|
|
|
0
|
} elsif (my $found_var = $self->find_var($passThruVarName)) { |
971
|
6
|
100
|
|
|
|
41
|
unless ($found_var->is_type('list')) { |
972
|
1
|
|
|
|
|
18
|
die $self->generror(q{%s - %s should be list type.} |
973
|
|
|
|
|
|
|
, join(":", @$path), $passThruVarName); |
974
|
|
|
|
|
|
|
} |
975
|
5
|
|
|
|
|
15
|
'@'.$self->as_lvalue($found_var); |
976
|
|
|
|
|
|
|
} else { |
977
|
0
|
|
|
|
|
0
|
die $self->generror("Unknown list="); |
978
|
|
|
|
|
|
|
} |
979
|
|
|
|
|
|
|
}; |
980
|
|
|
|
|
|
|
|
981
|
7
|
|
|
|
|
13
|
local $self->{curtoks} = [@{argValue($body)}]; |
|
7
|
|
|
|
|
22
|
|
982
|
7
|
|
|
|
|
34
|
local $self->{scope} = $self->mkscope(\%local, $self->{scope}); |
983
|
7
|
|
|
|
|
28
|
my $statements = '{'.$self->as_print('}'); |
984
|
|
|
|
|
|
|
|
985
|
7
|
50
|
33
|
|
|
40
|
if ($opts and $opts->{fragment}) { |
986
|
0
|
|
|
|
|
0
|
($fmt, $loopvar, $listexpr, $statements |
987
|
|
|
|
|
|
|
, $prologue, $continue, $epilogue); |
988
|
|
|
|
|
|
|
} else { |
989
|
7
|
|
|
|
|
63
|
\ sprintf $fmt, $loopvar, $listexpr, $statements |
990
|
|
|
|
|
|
|
, $prologue, $continue, $epilogue; |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
} |
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
sub entx { |
996
|
108
|
|
|
108
|
0
|
253
|
my ($node) = @_; |
997
|
108
|
|
|
|
|
216
|
@{$node}[2..$#$node]; |
|
108
|
|
|
|
|
416
|
|
998
|
|
|
|
|
|
|
} |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
sub entmacro_if { |
1001
|
99
|
|
|
99
|
0
|
213
|
(my MY $self, my $node) = @_; |
1002
|
99
|
|
|
|
|
259
|
my ($cond, $then, $else) = $self->gen_entlist(undef, entx($node)); |
1003
|
|
|
|
|
|
|
sprintf q|do {(%s) ? (%s) : (%s)}| |
1004
|
99
|
50
|
50
|
|
|
306
|
, map {ref $_ ? $$_ : $_} $cond, $then, $else || q{''}; |
|
297
|
|
|
|
|
1041
|
|
1005
|
|
|
|
|
|
|
} |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
sub entmacro_ifeq { |
1008
|
0
|
|
|
0
|
0
|
0
|
(my MY $self, my $node) = @_; |
1009
|
0
|
|
|
|
|
0
|
my ($val, $what, $then, $else) = $self->gen_entlist(undef, entx($node)); |
1010
|
|
|
|
|
|
|
sprintf q|do {((%s // '') eq (%s // '')) ? (%s) : (%s)}| |
1011
|
0
|
0
|
0
|
|
|
0
|
, map {ref $_ ? $$_ : $_} $val, $what, $then, $else || q{''}; |
|
0
|
|
|
|
|
0
|
|
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
sub entmacro_value_checked { |
1015
|
0
|
|
|
0
|
0
|
0
|
(my MY $self, my $node) = @_; |
1016
|
0
|
|
|
|
|
0
|
my (@list) = $self->gen_entlist(undef, entx($node)); |
1017
|
0
|
0
|
|
|
|
0
|
unless (@list == 2) { |
1018
|
0
|
|
|
|
|
0
|
die $self->generror("Invalid number of args: value_checked(VALUE, HASH)"); |
1019
|
|
|
|
|
|
|
} |
1020
|
|
|
|
|
|
|
sprintf q|YATT::Lite::Util::value_checked(%s)| |
1021
|
0
|
0
|
|
|
|
0
|
, join ", ", map {ref $_ ? $$_ : $_} @list; |
|
0
|
|
|
|
|
0
|
|
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
sub entmacro_value_selected { |
1025
|
0
|
|
|
0
|
0
|
0
|
(my MY $self, my $node) = @_; |
1026
|
0
|
|
|
|
|
0
|
my (@list) = $self->gen_entlist(undef, entx($node)); |
1027
|
0
|
0
|
|
|
|
0
|
unless (@list == 2) { |
1028
|
0
|
|
|
|
|
0
|
die $self->generror("Invalid number of args: value_selected(VALUE, HASH)"); |
1029
|
|
|
|
|
|
|
} |
1030
|
|
|
|
|
|
|
sprintf q|YATT::Lite::Util::value_selected(%s)| |
1031
|
0
|
0
|
|
|
|
0
|
, join ", ", map {ref $_ ? $$_ : $_} @list; |
|
0
|
|
|
|
|
0
|
|
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
sub entmacro_lexpand { |
1035
|
5
|
|
|
5
|
0
|
14
|
(my MY $self, my $node) = @_; |
1036
|
5
|
|
|
|
|
28
|
q|@{|.$self->gen_entpath(undef, map {lxnest($_)} entx($node)).q|}|; |
|
5
|
|
|
|
|
17
|
|
1037
|
|
|
|
|
|
|
} |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
sub entmacro_render { |
1040
|
4
|
|
|
4
|
0
|
12
|
(my MY $self, my $node) = @_; |
1041
|
4
|
|
|
|
|
20
|
my ($wname, @expr) = $self->gen_entlist(undef, entx($node)); |
1042
|
4
|
|
|
|
|
31
|
\ sprintf q{YATT::Lite::Util::safe_render($this, $CON, %s, %s)} |
1043
|
|
|
|
|
|
|
, $wname, join(", ", @expr); |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
sub entmacro_dispatch_all { |
1047
|
0
|
|
|
0
|
0
|
|
(my MY $self, my $node) = @_; |
1048
|
0
|
|
|
|
|
|
my ($prefix, $nargs, @list) = $self->gen_entlist(undef, entx($node)); |
1049
|
0
|
|
|
|
|
|
\ sprintf q{YATT::Lite::Util::dispatch_all($this, $CON, %s, %s, %s)} |
1050
|
|
|
|
|
|
|
, $prefix, $nargs, join(", ", @list); |
1051
|
|
|
|
|
|
|
} |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
sub entmacro_dispatch_one { |
1054
|
0
|
|
|
0
|
0
|
|
(my MY $self, my $node) = @_; |
1055
|
0
|
|
|
|
|
|
my ($prefix, $nargs, @list) = $self->gen_entlist(undef, entx($node)); |
1056
|
0
|
|
|
|
|
|
\ sprintf q{YATT::Lite::Util::dispatch_one($this, $CON, %s, %s, %s)} |
1057
|
|
|
|
|
|
|
, $prefix, $nargs, join(", ", @list); |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
|
1060
|
15
|
|
|
15
|
|
210
|
use YATT::Lite::Breakpoint qw(break_load_cgen break_cgen); |
|
15
|
|
|
|
|
43
|
|
|
15
|
|
|
|
|
1626
|
|
1061
|
|
|
|
|
|
|
break_load_cgen(); |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
1; |