% luaset package
% version 1.0
% Licensed under LaTeX Project Public License v1.3c or later. The complete license text is available at http://www.latex-project.org/lppl.txt.
%Authors: Chetan Shirore and Dr. Ajit Kumar

\ProvidesPackage{luatruthtable}[1.0]
\RequirePackage{xkeyval}
\RequirePackage{amsmath}
\RequirePackage{luacode}
\begin{luacode*}
local function toBinary(x,y)
    y = y or math.max(1, select(2, math.frexp(x)))
    local res = {}
    for i = y, 1, -1 do
        res[i] = math.fmod(x, 2)
        x = math.floor((x - res[i]) / 2)
    end
    return res
end

local function _not(a)
  if a ==0 then return 1
    else return 0 end
end

local lognot = {}

local not_mt= {
  __mul = function(a,b)
      return _not(b)

  end
}

setmetatable(lognot, not_mt)
_G.lognot = lognot

local function _and(a, b)
  if a == 1 and b == 1 then return 1
    else return 0 end
end

local tmp1 = {}
local logand = {}

local and_mt= {
  __mul = function(a,b)
    if b==logand then
      tmp1[1]=a
      return tmp1
    elseif a == tmp1 then
      return _and(tmp1[1], b)
    end
  end
}

setmetatable(tmp1, and_mt)
setmetatable(logand, and_mt)
_G.logand = logand

local function _or(a, b)
  if a == 0 and b == 0 then return 0
    else return 1 end
end

local tmp2 = {}
local logor = {}

local or_mt= {
  __mul = function(a,b)
    if b==logor then
      tmp2[1]=a
      return tmp2
    elseif a == tmp2 then
      return _or(tmp2[1], b)
    end
  end
}

setmetatable(tmp2, or_mt)
setmetatable(logor, or_mt)
_G.logor = logor

local function _imp(a, b)
  if a == 1 and b == 0 then return 0
    else return 1 end
end

local tmp3 = {}
local imp = {}

local imp_mt= {
  __mul = function(a,b)
    if b==imp then
      tmp3[1]=a
      return tmp3
    elseif a == tmp3 then
      return _imp(tmp3[1], b)
    end
  end
}

setmetatable(tmp3, imp_mt)
setmetatable(imp, imp_mt)
_G.imp = imp

local function _iff(a, b)
  if a == b then return 1
    else return 0 end
end

local tmp4 = {}
local iff = {}

local iff_mt= {
  __mul = function(a,b)
    if b==iff then
      tmp4[1]=a
      return tmp4
    elseif a == tmp4 then
      return _iff(tmp4[1], b)
    end
  end
}

setmetatable(tmp4, iff_mt)
setmetatable(iff, iff_mt)
_G.iff = iff

local function _xor(a, b)
  if a ~= b then return 1
    else return 0 end
end

local tmp5 = {}
local logxor = {}

local xor_mt= {
  __mul = function(a,b)
    if b==logxor then
      tmp5[1]=a
      return tmp5
    elseif a == tmp5 then
      return _xor(tmp5[1], b)
    end
  end
}

setmetatable(tmp5, xor_mt)
setmetatable(logxor, xor_mt)
_G.logxor = logxor

local function _nand(a, b)
  if a ==1 and b == 1 then return 0
    else return 1 end
end

local tmp6 = {}
local lognand = {}

local nand_mt= {
  __mul = function(a,b)
    if b==lognand then
      tmp6[1]=a
      return tmp6
    elseif a == tmp6 then
      return _nand(tmp6[1], b)
    end
  end
}

setmetatable(tmp6, nand_mt)
setmetatable(lognand, nand_mt)
_G.lognand = lognand

local function _nor(a, b)
  if a ==0 and b == 0 then return 1
    else return 0 end
end

local tmp7 = {}
local lognor = {}

local nor_mt= {
  __mul = function(a,b)
    if b==lognor then
      tmp7[1]=a
      return tmp7
    elseif a == tmp7 then
      return _nor(tmp7[1], b)
    end
  end
}

setmetatable(tmp7, nor_mt)
setmetatable(lognor, nor_mt)
_G.lognor = lognor

local function _xnor(a, b)
  if a == b then return 1
    else return 0 end
end

local tmp8 = {}
local logxnor = {}

local xnor_mt= {
  __mul = function(a,b)
    if b==logxnor then
      tmp8[1]=a
      return tmp8
    elseif a == tmp8 then
      return _xnor(tmp8[1], b)
    end
  end
}

setmetatable(tmp8, xnor_mt)
setmetatable(logxnor, xnor_mt)
_G.logxnor = logxnor

function truthTable(str0,str,trtext,fltext)
local eval=""
local names={lognot=lognot,logand=logand,logor=logor, imp=imp, 
  iff=iff, logxor=logxor,lognand=lognand,lognor=lognor, logxnor=logxnor}
local vars={}
local expr={}
local countexp = 1
local countvars =1
local res=""
local sep=" & "
trtext = trtext or "$T$"
fltext = fltext or "$F$"
for variables in string.gmatch(str0, '([^,]+)') do
  vars[countvars] = variables
 countvars = countvars + 1
end

for subexp in string.gmatch(str, '([^,]+)') do
    expr[countexp] = subexp
    countexp = countexp + 1
end

local n =#vars
for i =1,2^n do
  itr = toBinary(i,n)

  for j=1, #itr do
    names[vars[j]] = itr[j]
end

    for k = 1, #expr do
      res= res ..sep.. load("return " .. expr[k],nil,"t",names)()
      end
if i~=2^n then
eval = eval .. table.concat(toBinary(i,n)," & ") .. res .."\\\\"
else
eval = eval .. table.concat(toBinary(i,n)," & ") .. res
end
 res=""
end

if trtext:gsub("%s+", "") =="0" or trtext:gsub("%s+", "") == "$0$"  
or fltext:gsub("%s+", "") =="1" or fltext:gsub("%s+", "") == "$1$" 
then
eval=eval
else
eval=eval:gsub(0,fltext):gsub(1,trtext)
end
return eval
end

\end{luacode*}

% ========= KEY DEFINITIONS =========
\define@key{luatruthtable}{trtext}{\def\luatrtbl@trtext{#1}}
\define@key{luatruthtable}{fltext}{\def\luatrtbl@fltext{#1}}

% ========= KEY DEFAULTS =========
\setkeys{luatruthtable}{trtext=$T$,fltext=$F$}%
% ========= Defining Command =========
\newcommand{\luaTruthTable}[3][]{%
  \setkeys{luatruthtable}{#1}
  \directlua{tex.sprint(truthTable(\luastringN{#2},\luastringN{#3},'\luatrtbl@trtext','\luatrtbl@fltext'))}} %

\endinput
