Module: Klam::CompilationStages::ConvertSelfTailCallsToLoops
- Included in:
- Klam::Compiler
- Defined in:
- lib/klam/compilation_stages/convert_self_tail_calls_to_loops.rb
Overview
Convert Self Tail Calls To Loops
The Shen specification requires that self tail calls be optimized. This stage transforms defuns containing self tail calls into a loop/recur form akin to Clojure’s loop/recur. The code emitter knows how to handle these synthetic special forms.
For example, this code with tail calls:
(defun fact-iter (N Accum)
(if (= N 0)
Accum
(fact-iter (- N 1) (* N Accum))))
is converted to:
(defun fact-iter (N Accum)
([LOOP]
(if (= N 0)
Accum
([RECUR] (N Accum) ((- N 1) (* N Accum))))))
The variable names are carried along with their new binding expressions in the [RECUR] form so that they can be rebound before looping.
Note that this rebinding of variables causes a wrinkle with respect to closures created in the body. Those closures should close over the value at the point of closing rather than the ultimate values after rebinding. To solve this, another sythetic primitive, [FIX-VARS], is used to wrap these cases and the emitted Ruby code samples those variables.
This compilation stage must come after SimplifyBooleanOperations and ConvertFreezesToLambdas.
Instance Method Summary collapse
Instance Method Details
#convert_self_tail_calls_to_loops(sexp) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/klam/compilation_stages/convert_self_tail_calls_to_loops.rb', line 37 def convert_self_tail_calls_to_loops(sexp) # Self tail calls can only be found in functions defined by defun. # defun is only allowed at the top level, so there's no need to # walk the tree if this form is not a defun. if sexp.kind_of?(Array) && sexp[0] == :defun _, name, params, body = sexp if contains_self_tail_calls?(body, name) insert_loop_and_recur_into_defun(fix_vars(sexp, params)) else sexp end else sexp end end |