# 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}{%
\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/fraca
d = fracb/fracb
tex.sprint(math.floor(c*d))
end


anyname.tex

\documentclass[10pt,a4paper]{article}

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

\begin{document}

\newcommand{\surgefiw}{
\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}{%
\directlua{simpfracs("#1","#2")}%
}


To

\newcommand{\simpFracs}{%
\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. – Ulrike Fischer Jul 14 '20 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 '20 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 '20 at 16:29
• 2e^{-2}. correct. – Ben Jul 14 '20 at 16:32
• Lua uses math.exp(1) for e. – user220367 Jul 14 '20 at 16:44

## 1 Answer

After the initial discovery of having to convert

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


to

\newcommand{\simpFracs}{%
\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 == nil then
print("String is format 1!")
b = consta
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/fraca

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/fraca

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}{%
\directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}{%
\directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}{%
\directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}{
\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