Module:Calculated table
Documentation for this module may be created at Module:Calculated table/doc
local p = {} -- This is a simple Reverse Polish Notation evaluator. -- It's not infix because edsrzf is lazy and didn't want to write an infix -- parser. -- If you'd like to write one and replace this one, please feel free. local function evaluate(expr, env) local stack = {} local i = 1 while i <= #expr do local c = expr:sub(i, i) if c == '*' then local x = table.remove(stack) local y = table.remove(stack) table.insert(stack, x*y) elseif c == '/' then local x = table.remove(stack) local y = table.remove(stack) table.insert(stack, x/y) elseif c == '-' then local x = table.remove(stack) local y = table.remove(stack) table.insert(stack, x-y) elseif c == '+' then local x = table.remove(stack) local y = table.remove(stack) table.insert(stack, x+y) elseif tonumber(c) then local match = expr:match("^%d+", i) i = i + #match - 1 -- We'll add 1 more below table.insert(stack, tonumber(match)) elseif c:match("%a") then local match = expr:match("^%a+", i) i = i + #match - 1 -- We'll add 1 more below table.insert(stack, env[match]) end i = i + 1 end return table.remove(stack) end -- eval_func returns a function that evaluates the expression with a given environment. local function eval_func(expr) return function(env) return evaluate(expr, env) end end function p.table(frame) local i = 4 while i <= #frame.args do frame.args[i] = eval_func(frame.args[i]) i = i + 2 end local inputs = {} if frame.args.inputs then for str in frame.args.inputs:gmatch("[^,]+") do table.insert(inputs, str) end end return p._table(frame.args[1], frame.args[2], {style = frame.args.style, format = frame.args.format, inputs = inputs}, unpack(frame.args, 3)) end function p._table(base_heading, rows, opts, ...) local headings = {base_heading} local calculations = {} for j = 1, rows do calculations[j] = {} end local inputs = opts.inputs or {} local i = 1 while i < arg.n do table.insert(headings, arg[i]) local formula = arg[i+1] for j, row in ipairs(calculations) do row[(i+1)/2] = formula({x = inputs[j] or j-1}) end i = i + 2 end local result = {"{| "} local style = opts.style or [[cellpadding="4" cellspacing="0" border="1" align="center" style="text-align:center"]] table.insert(result, style) table.insert(result, "\n|-\n| ") for i, heading in ipairs(headings) do if i > 1 then table.insert(result, " || ") end table.insert(result, heading) end local format = function(s) return s end if type(opts.format) == "function" then format = opts.format elseif type(opts.format) == "string" then local formatstr = opts.format format = function(s) return formatstr:format(s) end end for j, row in ipairs(calculations) do table.insert(result, "\n|-\n| ") table.insert(result, inputs[j] or j-1) for i, col in ipairs(row) do table.insert(result, " || ") table.insert(result, format(col)) end end table.insert(result, "\n|}") return table.concat(result) end return p