Module:Calculated table

From CrawlWiki
Revision as of 03:17, 1 July 2015 by Edsrzf (talk | contribs) (Module for generating tables based on formulas)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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
  return p._table(frame.args[1], frame.args[2], {style = frame.args.style}, 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 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 = j})
    end
    i = i + 2
  end
  local result = {"{| "}
  local style = opts.style
  if style then
    table.insert(result, style)
  end
  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
  for j, row in ipairs(calculations) do
    table.insert(result, "\n|-\n| ")
    table.insert(result, j)
    for i, col in ipairs(row) do
      table.insert(result, " || ")
      table.insert(result, col)
    end
  end
  table.insert(result, "\n|}")
  return table.concat(result)
end

return p