Module:LogicUtils: Difference between revisions
Appearance
use mw.html instead of raw html strings |
No edit summary |
||
Line 25: | Line 25: | ||
return #names | return #names | ||
end | |||
local function eval(str, values) | |||
local stack = {} | |||
str:gsub("[^%s()]", function(c) | |||
if c == "&" or c == "|" or c == "^" then | |||
local v = table.remove(stack) | |||
if v == nil then error("Invalid expression: missing operand") end | |||
local v2 = table.remove(stack) | |||
if v2 == nil then error("Invalid expression: missing operand") end | |||
if c == "&" then | |||
table.insert(stack, v and v2) | |||
elseif c == "|" then | |||
table.insert(stack, v or v2) | |||
elseif c == "^" then | |||
table.insert(stack, v ~= v2) | |||
end | |||
elseif c == "!" then | |||
local v = table.remove(stack) | |||
if v == nil then error("Invalid expression: missing operand after '!'") end | |||
table.insert(stack, not v) | |||
else | |||
local index = string.find("abcdefghijklmnopqrstuvwxyz", c) | |||
if index then | |||
if values[index] == nil and not ignoreMissing then error("Value for variable '" .. c .. "' not provided") end | |||
table.insert(stack, values[index] or false) | |||
else | |||
error("Invalid character in expression: " .. c) | |||
end | |||
end | |||
end) | |||
return stack[1] | |||
end | |||
local function evalAll(str, num_vars, callback) | |||
local totalCombinations = 2 ^ num_vars | |||
local bit32 = require( 'bit32' ) | |||
for i = 0, totalCombinations - 1 do | |||
local values = {} | |||
for j = 1, num_vars do | |||
values[j] = bit32.band(i, bit32.lshift(1, j - 1)) ~= 0 | |||
end | |||
local result = eval(str, values) | |||
callback(values, result) | |||
end | |||
end | |||
local function renderCell(row, value) | |||
local style = "color:white; text-align:center;" | |||
if value == false then | |||
row:tag('td') | |||
:attr('style', 'background-color:#1f1e1e;'..style) | |||
:wikitext("0") | |||
elseif value == true then | |||
row:tag('td') | |||
:attr('style', 'background-color:#fd140f;'..style) | |||
:wikitext("1") | |||
else | |||
row:tag('td') | |||
:wikitext(value) | |||
end | |||
end | end | ||
Line 46: | Line 113: | ||
local row = tbl:tag('tr') | local row = tbl:tag('tr') | ||
for token in string.gmatch(args[i], "[^%s]+") do | for token in string.gmatch(args[i], "[^%s]+") do | ||
renderCell(row, token == "1" and true or token == "0" and false or token) | |||
end | end | ||
i = i + 1 | i = i + 1 | ||
end | end | ||
Line 70: | Line 123: | ||
end | end | ||
p.truth_table_auto = function(frame, args) | |||
local args = args or frame:getParent().args | |||
args.inputs = 2 | |||
args.outputs = 1 | |||
args.expr1 = "a b &" | |||
local tbl = mw.html.create('table') | |||
:addClass('wikitable') | |||
if args.caption ~= nil then | |||
tbl:tag('caption') | |||
:wikitext(args.caption) | |||
end | |||
local header = tbl:tag('tr') | |||
local nInputs = parse_io("Input", header, args.inputs) | |||
local nOutputs = parse_io("Output", header, args.outputs) | |||
for i = 1,nOutputs do | |||
local row = tbl:tag('tr') | |||
local expr = args["expr"..i] | |||
if expr == nil then | |||
error("Missing expression for output " .. i) | |||
end | |||
evalAll(expr, nInputs, function(values, result) | |||
for j = 1,nInputs do | |||
renderCell(row, values[j]) | |||
end | |||
renderCell(row, result) | |||
end) | |||
i = i + 1 | |||
end | |||
return tostring(tbl) | |||
end | |||
return p | return p |
Revision as of 12:02, 8 September 2025
Documentation for this module may be created at Module:LogicUtils/doc
local p = {}
function parse_io(kind, row, str)
local count = tonumber(str)
local names = {}
if count == nil then
-- str is a list of IO names
names = mw.text.split(str, ",")
else
-- str is a number
if count == 1 then
names[1] = kind
else
for i=1,count do
names[i] = string.format("%s %i", kind, i)
end
end
end
for i, v in ipairs(names) do
row:tag('th')
:wikitext(v)
end
return #names
end
local function eval(str, values)
local stack = {}
str:gsub("[^%s()]", function(c)
if c == "&" or c == "|" or c == "^" then
local v = table.remove(stack)
if v == nil then error("Invalid expression: missing operand") end
local v2 = table.remove(stack)
if v2 == nil then error("Invalid expression: missing operand") end
if c == "&" then
table.insert(stack, v and v2)
elseif c == "|" then
table.insert(stack, v or v2)
elseif c == "^" then
table.insert(stack, v ~= v2)
end
elseif c == "!" then
local v = table.remove(stack)
if v == nil then error("Invalid expression: missing operand after '!'") end
table.insert(stack, not v)
else
local index = string.find("abcdefghijklmnopqrstuvwxyz", c)
if index then
if values[index] == nil and not ignoreMissing then error("Value for variable '" .. c .. "' not provided") end
table.insert(stack, values[index] or false)
else
error("Invalid character in expression: " .. c)
end
end
end)
return stack[1]
end
local function evalAll(str, num_vars, callback)
local totalCombinations = 2 ^ num_vars
local bit32 = require( 'bit32' )
for i = 0, totalCombinations - 1 do
local values = {}
for j = 1, num_vars do
values[j] = bit32.band(i, bit32.lshift(1, j - 1)) ~= 0
end
local result = eval(str, values)
callback(values, result)
end
end
local function renderCell(row, value)
local style = "color:white; text-align:center;"
if value == false then
row:tag('td')
:attr('style', 'background-color:#1f1e1e;'..style)
:wikitext("0")
elseif value == true then
row:tag('td')
:attr('style', 'background-color:#fd140f;'..style)
:wikitext("1")
else
row:tag('td')
:wikitext(value)
end
end
p.truth_table = function(frame, args)
local args = args or frame:getParent().args
local tbl = mw.html.create('table')
:addClass('wikitable')
if args.caption ~= nil then
tbl:tag('caption')
:wikitext(args.caption)
end
local header = tbl:tag('tr')
local nInputs = parse_io("Input", header, args.inputs)
local nOutputs = parse_io("Output", header, args.outputs)
local i = 1
while args[i] ~= nil do
local row = tbl:tag('tr')
for token in string.gmatch(args[i], "[^%s]+") do
renderCell(row, token == "1" and true or token == "0" and false or token)
end
i = i + 1
end
return tostring(tbl)
end
p.truth_table_auto = function(frame, args)
local args = args or frame:getParent().args
args.inputs = 2
args.outputs = 1
args.expr1 = "a b &"
local tbl = mw.html.create('table')
:addClass('wikitable')
if args.caption ~= nil then
tbl:tag('caption')
:wikitext(args.caption)
end
local header = tbl:tag('tr')
local nInputs = parse_io("Input", header, args.inputs)
local nOutputs = parse_io("Output", header, args.outputs)
for i = 1,nOutputs do
local row = tbl:tag('tr')
local expr = args["expr"..i]
if expr == nil then
error("Missing expression for output " .. i)
end
evalAll(expr, nInputs, function(values, result)
for j = 1,nInputs do
renderCell(row, values[j])
end
renderCell(row, result)
end)
i = i + 1
end
return tostring(tbl)
end
return p