diff options
Diffstat (limited to 'Tools/LuaMacro/macro/do.lua')
-rw-r--r-- | Tools/LuaMacro/macro/do.lua | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/Tools/LuaMacro/macro/do.lua b/Tools/LuaMacro/macro/do.lua new file mode 100644 index 0000000..45cf84c --- /dev/null +++ b/Tools/LuaMacro/macro/do.lua @@ -0,0 +1,75 @@ +--- An intelligent 'loop-unrolling' macro. +-- `do_` defines a named scoped macro `var` which is the loop iterator. +-- +-- For example, +-- +-- y = 0 +-- do_(i,1,10 +-- y = y + i +-- ) +-- assert(y == 55) +-- +-- `tuple` is an example of how the expansion of a macro can be +-- controlled by its context. Normally a tuple `A` expands to +-- `A_1,A_2,A_3` but inside `do_` it works element-wise: +-- +-- tuple(3) A,B +-- def_ do3(stmt) do_(k,1,3,stmt) +-- do3(A = B/2) +-- +-- This expands as +-- +-- A_1 = B_1/2 +-- A_2 = B_2/2 +-- A_3 = B_3/2 +-- +-- @module macro.do +local M = require 'macro' + +--- Expand a loop inline. +-- @p var the loop variable +-- @p start initial value of `var` +-- @p finish final value of `var` +-- @p stat the statement containing `var` +-- @macro do_ +M.define('do_(v,s,f,stat)',function(var,start,finish,statements) + -- macros with specified formal args have to make their own putter, + -- and convert the actual arguments to the type they expect. + local put = M.Putter() + var,start,finish = var:get_iden(),start:get_number(),finish:get_number() + M.push_macro_stack('do_',var) + -- 'do_' works by setting the variable macro for each value + for i = start, finish do + put:name 'set_':name(var):number(i):space() + put:tokens(statements) + end + put:name 'undef_':name(var) + put:name '_DROP_':string 'do_':space() + return put +end) + +--- an example of conditional expansion. +-- `tuple` takes a list of variable names, like a declaration list except that it +-- must end with a line end. +-- @macro tuple +M.define('tuple',function(get) + get:expecting '(' + local N = get:number() + get:expecting ')' + local names = get:names '\n' + for _,name in ipairs(names) do + M.define(name,function(get,put) + local loop_var = M.value_of_macro_stack 'do_' + if loop_var then + local loop_idx = tonumber(M.get_macro_value(loop_var)) + return put:name (name..'_'..loop_idx) + else + local out = {} + for i = 1,N do + out[i] = name..'_'..i + end + return put:names(out) + end + end) + end +end) |