Line # Revision Author
1 24518 jkeenan # Copyright (C) 2008, The Perl Foundation.
2 24466 coke # $Id$
3
4 =begin comments
5
6 lolcode::Grammar::Actions - ast transformations for lolcode
7
8 This file contains the methods that are used by the parse grammar
9 to build the PAST representation of an lolcode program.
10 Each method below corresponds to a rule in F<src/parser/grammar.pg>,
11 and is invoked at the point where C<{*}> appears in the rule,
12 with the current match object as the first argument. If the
13 line containing C<{*}> also has a C<#= key> comment, then the
14 value of the comment is passed as the second argument to the method.
15
16 =end comments
17
18 class lolcode::Grammar::Actions;
19
20 method TOP($/) {
21 25008 coke my $block := $( $<block> );
22 my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'), :isdecl(1));
23 $block.unshift($it);
24 make $block;
25 24466 coke }
26
27
28 24470 simon method statement ($/, $key) {
29 25988 tene if (($key eq 'expression')&&($<expression><tokens>[0]<identifier> ne 'VISIBLE')) {
30 25008 coke my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
31 24511 simon my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
32 $past.push( $it );
33 $past.push( $( $<expression> ) );
34 make $past;
35 26488 infinoid }
36 else {
37 24511 simon make $( $/{$key} ); # For now
38 }
39 24470 simon }
40
41 24472 simon
42 method declare($/) {
43 28887 tene our $?BLOCK;
44 our @?BLOCK;
45
46 my $name := ~$<variable><identifier>;
47
48 my $var := PAST::Var.new( :name( $name ),
49 :viviself('Undef'),
50 :node( $/ )
51 );
52
53 my $scope := 'lexical';
54 if $<scope>[0] {
55 if ~$<scope>[0] eq 'FARAWAY' {
56 $scope := 'package';
57 }
58 }
59
60 $var.scope(~$scope);
61 unless $?BLOCK.symbol($name) {
62 $?BLOCK.symbol($name, :scope($scope));
63 $var.isdecl(1);
64 }
65
66 24500 simon if ($<expression>) {
67 28887 tene $var.isdecl(1);
68 24472 simon # XXX Someone clever needs to refactor this into C<assign>
69 my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
70 28887 tene $past.push( $var );
71 24500 simon $past.push( $( $<expression>[0] ) );
72 24472 simon make $past;
73 26488 infinoid }
74 else {
75 28887 tene make $var;
76 24472 simon }
77 }
78 24466 coke
79 24472 simon method assign($/) {
80 24485 simon my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
81 $past.push( $( $<variable> ) );
82 24500 simon $past.push( $( $<expression> ) );
83 24485 simon make $past;
84 24472 simon }
85
86 29028 tene method function($/,$key) {
87 our $?BLOCK;
88 if $key eq 'params' {
89 our $?BLOCK_SIGNATURE;
90 my $arglist;
91 $arglist := PAST::Stmts.new();
92 # if there are any parameters, get the PAST for each of them and
93 # adjust the scope to parameter.
94 for $<parameters> {
95 my $param := PAST::Var.new(:name(~$_<identifier>), :scope('parameter'), :node($($_)));
96 $param.isdecl(1);
97 $arglist.push($param);
98 }
99 $?BLOCK_SIGNATURE := $arglist;
100 24485 simon }
101 29028 tene elsif $key eq 'block' {
102 my $block := $( $<block> );
103 $block.blocktype('declaration');
104 $?BLOCK.symbol(~$<variable><identifier>, :arity($block.arity()));
105 24485 simon
106 25988 tene
107 29028 tene my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'), :isdecl(1));
108 $block[1].unshift($it);
109 25008 coke
110 29028 tene $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'));
111 $block[1].push($it);
112 $block.name(~$<variable><identifier>);
113 make $block;
114 #my $past := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
115 #$($<variable>).isdecl(1);
116 #$past.push( $( $<variable> ) );
117 #$past.push( $block );
118 #make $past;
119 }
120 25008 coke
121 25988 tene
122 29028 tene
123 24485 simon }
124
125 24660 coke method ifthen($/) {
126 my $count := +$<expression> - 1;
127 my $expr := $( $<expression>[$count] );
128 my $then := $( $<block>[$count] );
129 $then.blocktype('immediate');
130 25117 pmichaud my $past := PAST::Op.new( $expr, $then,
131 24660 coke :pasttype('if'),
132 :node( $/ )
133 );
134 if ( $<else> ) {
135 my $else := $( $<else>[0] );
136 $else.blocktype('immediate');
137 $past.push( $else );
138 }
139 while ($count != 0) {
140 $count := $count - 1;
141 $expr := $( $<expression>[$count] );
142 $then := $( $<block>[$count] );
143 $then.blocktype('immediate');
144 25117 pmichaud $past := PAST::Op.new( $expr, $then, $past,
145 24660 coke :pasttype('if'),
146 :node( $/ )
147 );
148 }
149 25117 pmichaud $expr := $past.shift();
150 25008 coke my $it := PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
151 24727 coke my $bind := PAST::Op.new( :pasttype('bind'), :node( $/ ) );
152 $bind.push( $it );
153 $bind.push( $expr );
154 25117 pmichaud $past.unshift( $it );
155 24727 coke my $past := PAST::Stmts.new( $bind, $past, :node( $/ ) );
156 24660 coke make $past;
157 }
158
159 28887 tene method block($/,$key) {
160 our $?BLOCK;
161 our @?BLOCK;
162 if $key eq 'open' {
163 29028 tene our $?BLOCK_SIGNATURE;
164 28887 tene $?BLOCK := PAST::Block.new( PAST::Stmts.new(), :node($/) );
165 @?BLOCK.unshift($?BLOCK);
166 29028 tene my $iter := $?BLOCK_SIGNATURE.iterator();
167 $?BLOCK.arity(0);
168 for $iter {
169 $?BLOCK.arity($?BLOCK.arity() + 1);
170 $?BLOCK[0].push($_);
171 $?BLOCK.symbol($_.name(), :scope('lexical'));
172 }
173 24485 simon }
174 28887 tene elsif $key eq 'close' {
175 #my $past := PAST::Block.new( :blocktype('declaration'), :node( $/ ) );
176 my $past := @?BLOCK.shift();
177 $?BLOCK := @?BLOCK[0];
178 my $stmts := PAST::Stmts.new( :node( $/ ) );
179 for $<statement> {
180 $stmts.push( $( $_ ) );
181 }
182 $past.push($stmts);
183 make $past;
184 }
185 24485 simon }
186
187 24466 coke method value($/, $key) {
188 make $( $/{$key} );
189 }
190
191 25988 tene method bang($/) {
192 make PAST::Val.new( :value( ~$/ ), :returns('String'), :node($/) );
193 }
194
195 method expression($/) {
196 my $past := PAST::Op.new( :name('expr_parse'), :pasttype('call'), :node( $/ ) );
197 for $<tokens> {
198 29028 tene my $name := ~$_<identifier>;
199 25988 tene if($_<identifier>) {
200 29034 tene my $foo := lookup($name);
201 29028 tene our $?BLOCK;
202 our @?BLOCK;
203 if $?BLOCK.symbol($name) && $?BLOCK.symbol($name)<scope> {
204 $past.push(PAST::Var.new(:name($name), :scope($?BLOCK.symbol($name)<scope>)));
205 }
206 else {
207 my $inline := '%r = find_name "' ~ $_<identifier> ~ '"';
208 $past.push(PAST::Op.new( :inline($inline) ));
209 }
210 25988 tene }
211 elsif($_ eq "MKAY"){
212 my $inline := '%r = find_name "MKAY"';
213 $past.push(PAST::Op.new( :inline($inline) ));
214 }
215 else {
216 $past.push( $( $_ ) );
217 }
218 24511 simon }
219 25988 tene make $past;
220 24500 simon }
221 24466 coke
222 method integer($/) {
223 make PAST::Val.new( :value( ~$/ ), :returns('Integer'), :node($/) );
224 }
225
226 24726 coke method float($/) {
227 make PAST::Val.new( :value( ~$/ ), :returns('Float'), :node($/) );
228 }
229 24466 coke
230 24660 coke method boolean($/) {
231 if (~$/ eq 'FAIL' ) {
232 make PAST::Val.new( :value( 0 ), :returns('Boolean'), :node($/) );
233 26488 infinoid }
234 else {
235 24660 coke make PAST::Val.new( :value( 1 ), :returns('Boolean'), :node($/) );
236 }
237 }
238
239 24466 coke method quote($/) {
240 25125 coke make PAST::Val.new( :value( $($<yarn_literal>) ), :node($/) );
241 24466 coke }
242
243
244 24511 simon method variable ($/) {
245 25988 tene if ($<identifier> eq 'IT') {
246 25008 coke make PAST::Var.new( :name( 'IT' ), :scope('lexical'), :viviself('Undef'));
247 26488 infinoid }
248 else {
249 28887 tene our $?BLOCK;
250 our @?BLOCK;
251
252 my $var := PAST::Var.new( :name( $<identifier> ),
253 24527 simon :scope('lexical'),
254 :viviself('Undef'),
255 :node( $/ )
256 28887 tene );
257 if $?BLOCK.symbol($<identifier>) {
258 my $scope := '' ~ $?BLOCK.symbol($<identifier>)<scope>;
259 $var.scope(~$scope);
260 }
261 else {
262 our @?BLOCK;
263 my $exists := 0;
264 my $scope;
265 for @?BLOCK {
266 if $_ {
267 my $sym_table := $_.symbol(~$<identifier>);
268 if $sym_table {
269 $exists := 1;
270 $scope := '' ~ $sym_table<scope>;
271 }
272 }
273 }
274 if $exists == 0 {
275 $var.scope('package');
276 }
277 else {
278 $var.scope($scope);
279 }
280 }
281
282 make $var;
283 24527 simon }
284 24472 simon }
285
286
287 24466 coke # Local Variables:
288 # mode: cperl
289 # cperl-indent-level: 4
290 # fill-column: 100
291 # End:
292 # vim: expandtab shiftwidth=4:
293