tagged release 0.6.4
[parrot.git] / compilers / pct / src / POST / Compiler.pir
blob4986667e4083f298c57a79ddfa072774d1c795fa
1 =head1 NAME
3 POST::Compiler - Compiler for POST trees
5 =head1 DESCRIPTION
7 POST::Compiler defines a compiler that converts a POST tree into
8 PIR or an Eval PMC (bytecode).
10 =head1 METHODS
12 =over
14 =cut
16 .namespace [ 'POST::Compiler' ]
18 .sub '__onload' :load :init
19     .local pmc p6meta, cproto
20     p6meta = new 'P6metaclass'
21     cproto = p6meta.'new_class'('POST::Compiler', 'parent'=>'PCT::HLLCompiler', 'attr'=>'$!code')
22     cproto.'language'('POST')
23     $P1 = split ' ', 'pir evalpmc'
24     cproto.'stages'($P1)
26     $P0 = new 'String'
27     set_global '$?NAMESPACE', $P0
28     .return ()
29 .end
32 .sub 'to_pir' :method
33     .param pmc post
34     .param pmc adverbs         :slurpy :named
36     .local pmc newself
37     newself = new 'POST::Compiler'
39     ##  start with empty code
40     .local pmc code
41     code = new 'CodeString'
42     newself.'code'(code)
44     ##  if the root node isn't a Sub, wrap it
45     $I0 = isa post, 'POST::Sub'
46     if $I0 goto have_sub
47     $P0 = get_hll_global ['POST'], 'Sub'
48     post = $P0.'new'(post, 'name'=>'anon')
49   have_sub:
51     ##  now generate the pir
52     newself.'pir'(post)
54     ##  and return whatever code was generated
55     .return newself.'code'()
56 .end
59 =item code([str])
61 Get/set the code generated by this compiler.
63 =cut
65 .sub 'code' :method
66     .param pmc code            :optional
67     .param int has_code        :opt_flag
69     if has_code goto set_code
70     code = getattribute self, '$!code'
71     .return (code)
72   set_code:
73     setattribute self, '$!code', code
74     .return (code)
75 .end
78 =item pir_children(node)
80 Return generated PIR for C<node> and all of its children.
82 =cut
84 .sub 'pir_children' :method
85     .param pmc node
86     .local pmc code, iter
87     code = new 'CodeString'
88     iter = node.'iterator'()
89   iter_loop:
90     unless iter goto iter_end
91     .local pmc cpost
92     cpost = shift iter
93     $P0 = self.'pir'(cpost)
94     code .= $P0
95     goto iter_loop
96   iter_end:
97     .return (code)
98 .end
101 =item pir(Any node)
103 Return generated pir for any POST::Node.  Returns
104 the generated pir of C<node>'s children.
106 =cut
108 .sub 'pir' :method :multi(_,_)
109     .param pmc node
110     .return self.'pir_children'(node)
111 .end
114 =item pir(POST::Op node)
116 Return pir for an operation node.
118 =cut
120 .sub 'pir' :method :multi(_,['POST::Op'])
121     .param pmc node
123     ##  determine the type of operation
124     .local string pirop
125     pirop = node.'pirop'()
127     ##  determine if we're storing result
128     .local string result
129     result = node.'result'()
130     unless result goto have_result
131     concat result, ' = '
132   have_result:
134     ##  get list of arguments to operation
135     .local pmc arglist
136     arglist = node.'list'()
138     ##  get format and arguments based on pirop
139     .local string fmt, name, invocant
140     if pirop == 'call' goto pirop_call
141     if pirop == 'callmethod' goto pirop_callmethod
142     if pirop == 'return' goto pirop_return
143     if pirop == 'tailcall' goto pirop_tailcall
144     if pirop == 'inline' goto pirop_inline
146   pirop_opcode:
147     fmt = "    %n %,"
148     name = pirop
149     goto pirop_emit
151   pirop_call:
152     fmt = "    %r%n(%,)"
153     name = shift arglist
154     goto pirop_emit
156   pirop_callmethod:
157     fmt = "    %r%i.%n(%,)"
158     name = shift arglist
159     invocant = shift arglist
160     goto pirop_emit
162   pirop_return:
163     fmt = "    .return (%,)"
164     goto pirop_emit
166   pirop_tailcall:
167     name = shift arglist
168     fmt = '    .return %n(%,)'
169     goto pirop_emit
171   pirop_inline:
172     fmt = node.'inline'()
173     result = node.'result'()
174     goto pirop_emit
176   pirop_emit:
177     .local pmc code
178     code = new 'CodeString'
179     code.'emit'(fmt, arglist :flat, 'r'=>result, 'n'=>name, 'i'=>invocant, 't'=>result)
180     .return (code)
181 .end
184 =item pir(POST::Label node)
186 Generate a label.
188 =cut
190 .sub 'pir' :method :multi(_, ['POST::Label'])
191     .param pmc node
192     .local string code, value
193     value = node.'result'()
194     code = '  '
195     code .= value
196     code .= ":\n"
197     .return (code)
198 .end
201 =item pir(POST::Sub node)
203 Generate PIR for C<node>, storing the result into the compiler's
204 C<$!code> attribute and returning any code needed to look up
205 the sub.
207 =cut
209 .sub 'pir' :method :multi(_, ['POST::Sub'])
210     .param pmc node
212     .local pmc code
213     code = new 'CodeString'
215     .local string name, pirflags
216     name = node.'name'()
217     pirflags = node.'pirflags'()
219   pirflags_lexid:
220     $I0 = index pirflags, ':lexid('
221     if $I0 >= 0 goto pirflags_lexid_done
222     .local string lexid
223     lexid = code.'unique'()
224     node.'lexid'(lexid)
225     pirflags = concat pirflags, ' :lexid("'
226     pirflags .= lexid
227     pirflags .= '")'
228   pirflags_lexid_done:
230   pirflags_method:
231     $I0 = index pirflags, ':method'
232     if $I0 >= 0 goto pirflags_method_done
233     $S0 = node.'blocktype'()
234     if $S0 != 'method' goto pirflags_method_done
235     pirflags = concat pirflags, ' :method'
236   pirflags_method_done:
238     .local pmc outerpost, outername
239     outername = new 'Undef'
240     outerpost = node.'outer'()
241     if null outerpost goto pirflags_done
242     unless outerpost goto pirflags_done
243     ##  FIXME: RT#47956
244     ##  PIR doesn't compile properly if :outer points to a sub
245     ##  with :init/:load flags on it.
246     $I0 = index pirflags, ':init'
247     if $I0 >= 0 goto pirflags_done
248     $I0 = index pirflags, ':load'
249     if $I0 >= 0 goto pirflags_done
250     $S0 = outerpost.'pirflags'()
251     $I0 = index $S0, ':init'
252     if $I0 >= 0 goto pirflags_done
253     $I0 = index $S0, ':load'
254     if $I0 >= 0 goto pirflags_done
255     outername = outerpost.'lexid'()
256     $S0 = code.'escape'(outername)
257     pirflags = concat pirflags, ' :outer('
258     concat pirflags, $S0
259     concat pirflags, ')'
260   pirflags_done:
262     .local pmc outerns, ns, nskey
263     outerns = get_global '$?NAMESPACE'
264     nskey = outerns
265     ns = node.'namespace'()
266     unless ns goto have_ns
267     nskey = code.'key'(ns)
268     set_global '$?NAMESPACE', nskey
269   have_ns:
271   subpir_start:
272     $P0 = node.'compiler'()
273     unless $P0 goto subpir_post
274   subpir_compiler:
275     $P0 = node.'compiler_args'()
276     if $P0 goto have_compiler_args
277     $P0 = new 'Hash'
278   have_compiler_args:
279     $P0 = self.'hll_pir'(node, 'name'=>name, 'namespace'=>ns, 'pirflags'=>pirflags, $P0 :named :flat)
280     code .= $P0
281     goto subpir_done
283   subpir_post:
284     code.'emit'("\n.namespace %0", nskey)
285     $S0 = code.'escape'(name)
286     code.'emit'(".sub %0 %1", $S0, pirflags)
287     .local pmc paramlist
288     paramlist = node['paramlist']
289     if null paramlist goto paramlist_done
290     .local pmc iter
291     iter = new 'Iterator', paramlist
292   param_loop:
293     unless iter goto paramlist_done
294     $P0 = shift iter
295     if null $P0 goto param_loop
296     code .= $P0
297     goto param_loop
298   paramlist_done:
300     $P0 = self.'pir_children'(node)
301     code .= $P0
302     code.'emit'(".end\n\n")
304   subpir_done:
305     $P0 = self.'code'()
306     code .= $P0
307     self.'code'(code)
309     set_global '$?NAMESPACE', outerns
311     code = new 'CodeString'
312     .return (code)
313 .end
315 .sub 'hll_pir' :method
316     .param pmc node
317     .param pmc options         :slurpy :named
319     options['target'] = 'pir'
320     options['grammar'] = ''
321     .local pmc source, compiler, pir
322     source = node[0]
323     $S0 = node.'compiler'()
324     compiler = compreg $S0
325     $I0 = isa compiler, 'Sub'
326     if $I0 goto compiler_sub
327     .return compiler.'compile'(source, options :flat :named)
328   compiler_sub:
329     .return compiler(source, options :flat :named)
330 .end
332 =back
334 =head1 AUTHOR
336 Patrick Michaud <pmichaud@pobox.com> is the author and maintainer.
337 Please send patches and suggestions to the Parrot porters or
338 Perl 6 compilers mailing lists.
340 =head1 HISTORY
342 2007-11-21  Significant refactor as part of Parrot Compiler Toolkit
344 =head1 COPYRIGHT
346 Copyright (C) 2006-2008, The Perl Foundation.
348 =cut
350 # Local Variables:
351 #   mode: pir
352 #   fill-column: 100
353 # End:
354 # vim: expandtab shiftwidth=4 ft=pir: