File Coverage

blib/lib/YATT/Lite/CGen.pm
Criterion Covered Total %
statement 100 111 90.0
branch 35 50 70.0
condition 13 26 50.0
subroutine 23 28 82.1
pod 0 15 0.0
total 171 230 74.3


line stmt bran cond sub pod time code
1             package YATT::Lite::CGen; sub MY () {__PACKAGE__}
2 9     9   22597 use strict;
  9         18  
  9         276  
3 9     9   46 use warnings qw(FATAL all NONFATAL misc);
  9         16  
  9         310  
4 9     9   53 use Carp;
  9         20  
  9         687  
5              
6 9     9   48 use constant DEBUG_REBUILD => $ENV{DEBUG_YATT_REBUILD};
  9         18  
  9         733  
7              
8 9     9   46 use base qw(YATT::Lite::VarMaker);
  9         21  
  9         1261  
9 9         131 use fields qw/curtmpl curwidget curtoks
10             altgen needs_escaping depth
11             cf_cgen_loader
12             cf_only_parse
13             cf_no_lineinfo cf_check_lineno
14             no_last_newline
15             cf_vfs cf_parser cf_sink scope
16             cf_lcmsg_sink
17 9     9   64 /;
  9         17  
18              
19 9     9   1230 use YATT::Lite::Core qw(Template Part);
  9         17  
  9         549  
20 9     9   52 use YATT::Lite::Constants;
  9         18  
  9         1927  
21 9     9   50 use YATT::Lite::Util qw(callerinfo numLines);
  9         16  
  9         13267  
22              
23             sub ensure_generated {
24 241     241 0 495 (my MY $self, my $spec, my Template $tmpl) = @_;
25 241 50       563 my ($type, $kind) = ref $spec ? @$spec : $spec;
26 241 50       660 $self->{cf_vfs}->error(q{sink is empty}) unless $self->{cf_sink};
27 241 100       770 return if defined $tmpl->{product}{$type};
28 163   100     915 local $self->{depth} = 1 + ($self->{depth} // 0);
29 163         499 my $pkg = $tmpl->{product}{$type} = $tmpl->{cf_entns};
30 163 50       428 if (not defined $tmpl->{product}{$type}) {
31 0         0 croak "package for product $type of $tmpl->{cf_path} is not defined!";
32             } else {
33 163         224 print STDERR "# generating $pkg for $type code of $tmpl->{cf_path}\n"
34             if DEBUG_REBUILD;
35             }
36             $self->{cf_parser}->parse_body($tmpl)
37             if not $kind or not $self->{cf_only_parse}
38 163 50 33     1093 or $self->{cf_only_parse}{$kind};
      33        
39 156         670 $self->setup_inheritance($tmpl);
40 156         760 my @res = $self->generate($tmpl, $kind);
41 137 50       626 if (my $sub = $self->{cf_sink}) {
42             $sub->({folder => $tmpl, package => $pkg, kind => 'body'
43             , depth => $self->{depth}}
44 137         1072 , @res);
45             }
46 136         3360 $pkg;
47             }
48              
49             sub generate {
50 156     156 0 387 (my MY $self, my Template $tmpl) = splice @_, 0, 2;
51             # XXX: localize した方がいいかも。 というか、 curtmpl との区別が紛らわしいか。
52 156 50       450 my $kind = shift if @_;
53 156         406 local $self->{curtmpl} = $tmpl;
54 156         345 local $self->{curline} = 1;
55             ($self->generate_preamble($self->{curtmpl})
56             , map {
57 228         381 my Part $part = $_;
58 228 50 33     939 if (not $kind or not $self->{cf_only_parse}
      33        
59             or $kind eq $part->{cf_kind}) {
60             my $sub = $self->can("generate_$part->{cf_kind}")
61             or die $self->generror("Can't generate part type: '%s'"
62 228 50       1175 , $part->{cf_kind});
63 228         1062 $sub->($self, $part, $part->{cf_name}, $tmpl->{cf_path});
64             } else {
65 0         0 ();
66             }
67 156         604 } @{$tmpl->{partlist}});
  156         395  
68             }
69              
70       0 0   sub setup_inheritance {}
71              
72             #========================================
73             sub altgen {
74 141     141 0 244 (my MY $self, my $ns) = @_;
75             # ns 一つに付き 高々 1回しか、can しないで済むように... と言っても、cgen 自体が複数個作られたら..
76 141 100       464 unless (exists $self->{altgen}{$ns}) {
77 98         139 $self->{altgen}{$ns} = do {
78 98 50       756 if (my $sub = $self->can("create_altgen_$ns")) {
79             sub {
80             # 毎回, new し直す。
81 0     0   0 $sub->($self)->generate_node(@_);
82 0         0 };
83             }
84             };
85             }
86 141         2605 $self->{altgen}{$ns};
87             }
88             sub create_altgen_js {
89 0     0 0 0 require YATT::Lite::CGen::JS;
90 0         0 my MY $self = shift;
91 0         0 new YATT::Lite::CGen::JS
92             ($self->cf_delegate(qw(vfs parser no_lineinfo check_lineno)));
93             }
94             #========================================
95             sub find_var {
96 424     424 0 687 (my MY $self, my $varName, my $check) = @_;
97 424 50       947 confess "Undefined varName for find_var!" unless defined $varName;
98 424         1666 for (my $scope = $self->{scope}; $scope; $scope = $scope->[1]) {
99 1377 100       5591 if (defined (my $var = $scope->[0]{$varName})) {
100 279 50 66     768 next if $check and not $check->($var);
101 279         1158 return $var;
102             }
103             }
104             }
105             sub find_callable_var {
106 141     141 0 266 (my MY $self, my $varName) = @_;
107 141     33   692 $self->find_var($varName, sub {shift->callable});
  33         183  
108             }
109             sub lookup_widget {
110 85     85 0 258 (my MY $self, my ($ns, @path)) = @_;
111             # ns 抜きと、有りで一回ずつ検索する
112             $self->{cf_vfs}->find_part_from($self->{curtmpl}, @path)
113 85 100       398 || $self->{cf_vfs}->find_part_from($self->{curtmpl}, $ns, @path);
114             }
115              
116             sub generror {
117 19     19 0 31 my MY $self = shift;
118 19         34 my Template $tmpl = $self->{curtmpl};
119 19         76 my ($pkg, $file, $line) = caller;
120 19         65 my %opts = ($self->_tmpl_file_line($self->{curline}), callerinfo());
121 19         71 $self->_error(\%opts, @_);
122             }
123             sub _error {
124 19     19   57 my MY $self = shift;
125 19         83 $self->{cf_vfs}->error(@_);
126             }
127             sub _tmpl_file_line {
128 19     19   32 (my MY $self, my $ln) = @_;
129 19         32 my Template $tmpl = $self->{curtmpl};
130             (tmpl_file => $tmpl->{cf_path} // $tmpl->{cf_name}
131 19 50 33     157 , defined $ln ? (tmpl_line => $ln) : ());
132             }
133              
134             sub add_curline {
135 78     78 0 140 (my MY $self, my $text) = @_;
136 78         242 $self->{curline} += numLines($text);
137 78         371 $text;
138             }
139              
140             sub sync_curline {
141 1145     1145 0 1707 (my MY $self, my $lineno) = @_;
142 1145 100       2577 return unless defined $lineno;
143 1054         1757 my $diff = $lineno - $self->{curline};
144 1054 50 33     2819 die "curline exceeds expected lineno! expect $lineno, curline=$self->{curline}\n" if $self->{cf_check_lineno} and $diff < 0;
145 1054         1449 $self->{curline} = $lineno;
146 1054 100       5076 $diff > 0 ? "\n" x $diff : ();
147             }
148             # の直後の改行を,
149             # ソース上のみの(出力しない)改行に変換する。
150             sub cut_next_nl {
151 448     448 0 648 my MY $self = shift;
152             # undef は返したくないので。
153             return wantarray ? () : ''
154 448 100 100     475 unless @{$self->{curtoks}} and $self->{curtoks}[0] =~ /^\r?\n$/;
  448 100       4166  
155             return wantarray ? () : ''
156 146 50       214 if @{$self->{curtoks}} == 1; # 最後の一個の改行は、残す。これは "}\n" のため
  146 100       676  
157 81         131 $self->{curline}++;
158 81         104 shift @{$self->{curtoks}};
  81         397  
159             }
160              
161             sub mkscope {
162 275     275 0 402 my MY $self = shift;
163 275 50       644 return unless @_;
164 275 100       854 my $scope = ref $_[-1] eq 'ARRAY' ? pop : [pop];
165 275         704 while (@_) {
166 757         2301 $scope = [pop, $scope];
167             }
168 275         949 $scope;
169             }
170              
171             sub terse_dump {
172 0     0 0   my MY $self = shift;
173 0           YATT::Lite::Util::terse_dump(@_);
174             }
175              
176             sub node_sync_curline {
177 0     0 0   (my MY $self, my $node) = @_;
178 0           $self->sync_curline($node->[NODE_LNO]);
179             }
180              
181             1;