Dear Hans,

It is nice to input the function as an argument.
It is suffice to convey one function at each all.

But the definition of the function 

  local function logicF3(p,q,r)
      return ((not p or not q) and r) or (p and (q or not r))
   -- return ((p == "0" or q == "0") and r == "1") or (p == "1" and (q == "1" or r == "0"))
  end


Is not working. The outputs are blank(for false) and “?”(for true)

Here is a working example.

Thank you for enhancing the code.

Best regards,

Dalyoung

\startluacode
function document.MakeHead(p,a)
if not a then
local t = p
p = string.rep("|mcw(1cm)",#p-1) .. "|mcw(2cm)|"
a = t
end
context.starttabulate { p }
context.FL()
for i=1,#a do
context.NC() context(a[i])
end
context.NC() context.NR()
context.LL()
end
function document.MakeFooter()
context.HL()
context.stoptabulate()
end

local tf = { true, false }

function document.truthTable(a,func)
document.MakeHead(a)
for i,s in ipairs(tf) do
for j,t in ipairs(tf) do
for k,u in ipairs(tf) do
context.NC()
context(s and "1" or "0")
context.NC()
context(t and "1" or "0")
context.NC()
if #a == 3 then
break
end
context(u and "1" or "0")
context.NC()
context(func(s,t,u))
context.NC()
context.AR()
end
if #a == 3 then
context(func(s,t))
context.NC()
context.AR()
end
end
end
document.MakeFooter()
end
\stopluacode

—- We define a logic function before we call the main function.
—- by changing the function, we get the result for two variables.

\startluacode
--statistics.starttiming()
local function logicF(p,q,r)
if (not q) and (p or r) then
return "1"
else
return "0"
end
—- return (not q) and (p or r)
end

document.truthTable({ "x", "y","z","f(x,y,x)"},logicF)
\stopluacode

\stoptext