# Passing a macro as a string in luatex

In lua I have a function that takes a string and an number called "simpFracs" (It's supposed to take a fraction and a number, multiply them, return a number)

I have a pretty disgusting macro (It's a macro that shows working steps for a math problem)

\def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}


Which, with, eg with #1=10 and #2=8 it'll expand into

\frac{1}{4}


For LuaLatex, I wanted to pass xval as a string. The macro looks like:

\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}


The simpFracs macro works fine on a string such as

\simpFracs{\frac{1}{4}}{\frac{4}{1}}


works fine, But when I add in a macro, I have no clue how to get this to work...

\simpFracs{\xval}{\\frac{4}{1}}


I've tried looking up macro expansion for a couple hours, But I have no clue how they expand in strings

A full working example: (I left this out because its disgusting)

-- in math.lua
-- I am aware this code is bad, but it works, its an assignment, I dont care if its hacky

function simpfrac(a,b)
sign = false;
if a < 0 then
sign = true
end
if b < 0 then
if sign == true then
sign = false
else
sign = true
end
end

a = math.abs(a)
b = math.abs(b)

local function gcd(a,b)
if b ~= 0 then
return gcd(b, a % b)
else
return math.abs(a)
end
end

t = gcd(a, b)
if b/t == 1 then
if sign == true then
tex.sprint(-math.floor(a/t))
else
tex.sprint(math.floor(a/t))
end

else
-- Floor removes the decimal points
if sign == true then
tex.sprint("-\\frac{", math.floor(a/t), "}{", math.floor(b/t), "}")
else
tex.sprint("\\frac{", math.floor(a/t), "}{", math.floor(b/t), "}")
end
end
end

function simpmult(a,b)
tex.sprint(a*b)
end

-- a = string (frac), b = string(frac)
function simpfracs(a,b)
-- Parse frac
-- frac{a} {b}
local fraca = {}
local fracb = {}
for w in string.gmatch(a, "{([^{}]*)}") do
table.insert(fraca,w)
end
for w in string.gmatch(b, "{([^{}]*)}") do
table.insert(fracb,w)
end
c = fraca[1]/fraca[2]
d = fracb[1]/fracb[2]
tex.sprint(math.floor(c*d))
end


anyname.tex

\documentclass[10pt,a4paper]{article}

\directlua{dofile("math.lua")}
\newcommand{\simpFrac}[2]{%
\directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}[2]{%
\directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}[2]{
\def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}
$x = \xval$ \\
$f(x) = #1xe^{-#2x}$ \\
% Want it to be this (But without the \\frac{1}{4} hard coded)
$y=\simpFracs{\\frac{1}{4}}{\\frac{#1}{1}}e^{\simpFracs{\\frac{1}{4}}{\\frac{-#2}{1}}}$ \\
% Dont know how to make this compile
%$y = \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}}$ \\
}

\surgefiw{10}{8}

\end{document}


UPDATE: Figured out how to fix the backslash issue, I just needed to change

\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("#1","#2")}%
}


To

\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}


But now the arguments being passed from the macro is: "\protect {\begingroup 1\endgroup \over 4}" and "\protect {\begingroup 10\endgroup \over 1}" rather than "\frac{1}{4}" and "\frac{10}{1}" and I have no clue how to go about fixing it...

• you should make a complete example that can be used for tests instead of showing some snippets. But beside this, it looks wrong to mix calculation and typesetting like this. Jul 14, 2020 at 15:42
• Added complete example. Some context as to why: I have to provide working for everything I put in a table for an assignment, I dont want a bunch of random errors in my working, I've already done this to produce 3 pages of working, It'd be a shame to change it midway through.
– Ben
Jul 14, 2020 at 16:25
• What's the output of \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}} supposed to be? 2e^{-2}? Please advise.
– Mico
Jul 14, 2020 at 16:29
• 2e^{-2}. correct.
– Ben
Jul 14, 2020 at 16:32
• Lua uses math.exp(1) for e.
– user220367
Jul 14, 2020 at 16:44

After the initial discovery of having to convert

\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("#1","#2")}%
}


to

\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}


I realized that it took one of two type of inputs, so instead of trying to understand latex, I just used lua to parse them.
The input could've been \frac{a}{b} or \protect {\begingroup a\endgroup \over b}
To keep the code readable, I split it up into functions, which means I also had to parse constants. Leaving me with the final lua code of:

function parsefrac(a)
print("A is", a)
-- First check is input is constant (Format 1)
local consta = {}
for w in string.gmatch(a, "%d+") do
table.insert(consta,w)
end
if consta[2] == nil then
print("String is format 1!")
b = consta[1]
return b;
end

-- frac{a}{b} -- (Format 2)
if a.sub(a,1,string.len("\\frac")) == "\\frac" then
-- Format 1
print("String is format 2!")
local fraca = {}

for w in string.gmatch(a, "{([^{}]*)}") do
table.insert(fraca,w)
end

b = fraca[1]/fraca[2]

return b

else
-- \protect {\begingroup a\endgroup \over b} -- (Format 3)
print("String is format 3!")
local fraca = {}
for w in string.gmatch(a, "%d+") do
table.insert(fraca,w)
end
b = fraca[1]/fraca[2]

return b
end
end

-- a = string (frac), b = string(frac)
function simpfracs(a,b)
-- Parse typesetting

c = parsefrac(a)
d = parsefrac(b)

tex.sprint(math.floor(c*d))
end


Which given the input

\documentclass[10pt,a4paper]{article}

\directlua{dofile("math.lua")}
\newcommand{\simpFrac}[2]{%
\directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}[2]{%
\directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}[2]{%
\directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}[2]{
\def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}
$x = \xval$ \\
$f(x) = #1xe^{-#2x}$ \\
$y = \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}}$ \\
}

\surgefiw{10}{8}

\end{document}



Will produce the desired results.
This isn't in the scope of the original question, but for completeness, I'm aware there's a logical error in 1/4 * 10 = 2, but that was fixed by changing

tex.sprint(math.floor(c*d))


to

    if c*d == math.floor(c*d) then
tex.sprint(math.floor(c*d))
else
simpfrac(c*d,1)
end


in the end of the simpfracs function