Difference between revisions of "Module:Calculated table"

From CrawlWiki
Jump to: navigation, search
(Module for generating tables based on formulas)
 
(Start calculating from 0; allow specifying inputs)
 
(3 intermediate revisions by the same user not shown)
Line 53: Line 53:
 
     i = i + 2
 
     i = i + 2
 
   end
 
   end
   return p._table(frame.args[1], frame.args[2], {style = frame.args.style}, unpack(frame.args, 3))
+
  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
 
end
  
Line 62: Line 68:
 
     calculations[j] = {}
 
     calculations[j] = {}
 
   end
 
   end
 +
  local inputs = opts.inputs or {}
 
   local i = 1
 
   local i = 1
 
   while i < arg.n do
 
   while i < arg.n do
Line 67: Line 74:
 
     local formula = arg[i+1]
 
     local formula = arg[i+1]
 
     for j, row in ipairs(calculations) do
 
     for j, row in ipairs(calculations) do
       row[(i-1)/2] = formula({x = j})
+
       row[(i+1)/2] = formula({x = inputs[j] or j-1})
 
     end
 
     end
 
     i = i + 2
 
     i = i + 2
 
   end
 
   end
 
   local result = {"{| "}
 
   local result = {"{| "}
   local style = opts.style
+
   local style = opts.style or [[cellpadding="4" cellspacing="0" border="1" align="center" style="text-align:center"]]
   if style then
+
   table.insert(result, style)
    table.insert(result, style)
 
  end
 
 
   table.insert(result, "\n|-\n| ")
 
   table.insert(result, "\n|-\n| ")
 
   for i, heading in ipairs(headings) do
 
   for i, heading in ipairs(headings) do
Line 82: Line 87:
 
     end
 
     end
 
     table.insert(result, heading)
 
     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
 
   end
 
   for j, row in ipairs(calculations) do
 
   for j, row in ipairs(calculations) do
 
     table.insert(result, "\n|-\n| ")
 
     table.insert(result, "\n|-\n| ")
     table.insert(result, j)
+
     table.insert(result, inputs[j] or j-1)
 
     for i, col in ipairs(row) do
 
     for i, col in ipairs(row) do
 
       table.insert(result, " || ")
 
       table.insert(result, " || ")
       table.insert(result, col)
+
       table.insert(result, format(col))
 
     end
 
     end
 
   end
 
   end

Latest revision as of 04:07, 1 July 2015

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