# Setting Environment while defining complex numbers in LuaTeX

My question is inspired from this question that I asked earlier. Here is the code.

\documentclass{article}
\usepackage{parskip,luacode}
\begin{luacode*}
M = {}         -- the module
complex = {} -- global complex numbers registry
local mt = {} --metatable for complex numbers
function new (r, i)
local cp = {}
cp = {r=r, i=i}
return setmetatable(cp,mt)
end
M.new = new        -- add 'new' to the module
function M.op (...)
local _ENV = complex
return ...
end
return new(c1.r + c2.r, c1.i + c2.i)
end
function M.tostring (c)
return string.format("(%g,%g)", c.r, c.i) --to avoid +-
end
mt.__tostring = M.tostring
\end{luacode*}
\newcommand\cpxNew[2]{%
\directlua{%
complex[\luastringN{#1}] = M.new(#2)
}%
}
\newcommand\cpxPrint[1]{%
\directlua{tex.sprint(tostring(complex[\luastringN{#1}]))}%
}

\newcommand\cpxOp[1]{%
\directlua{%
tex.print(tostring(M.op(#1)))
}%
}
\begin{document}
\cpxNew{a}{3,4}
\cpxPrint{a} \par
\cpxOp{complex.a + complex.a} \par
%\cpxOp{a+a}
\end{document}


It gets compiled. I get expected output too, except for the commented last command \cpxOp{a+a}. When I un-comment it, I get the error (arithmetic on nil value). I need such thing for setting metatables. I expect the answer (6,8). However, I am getting nil. The previous command \cpxOp{complex.a +complex.a} gives expected answer. What is the problem with the function M.op(...). I have set up local _ENV to complex and so I expect to get same answer as \cpxOp{complex.a + complex.a} for the command \cpxOp{a+a}. This does not happen. What may be the reason? Any help will be appreciated. Thanks.

• Changing _ENV doesn't have the effect you are looking for because Lua is not a macro language. If you had written return a instead of return ... in M.op, Lua would have used complex.a, but in your example the global a is looked up before M.op is even called. So the new _ENV isn't in effect at that point. – Marcel Krüger Apr 19 '20 at 19:11
• So how to evaluate ... in the environment complex? – user61681 Apr 20 '20 at 5:11
• The question isn't where ... is evaluated, it is in which scope a appears. So if you would want this, you would have to set local _ENV=complex in the \directlua block in \cpxOp – Marcel Krüger Apr 20 '20 at 16:35
• How to set local_ENV = complex in the \directlua block? – user61681 Apr 20 '20 at 17:00

Your macro \cpxNew is registering an element inside the complex table (in your case, complex.a or complex["a"]). If you call a, you get nil as it is an undefined element. A workaround is defining a new command so you have not to write complex

## EDIT

If you don't mind breaking things, you can equal complex and _G (global variable).

%!TEX program = lualatex
\documentclass{standalone}
\usepackage{luacode}
\begin{luacode*}
M = {}        -- the module
complex = _G -- global complex numbers registry
local mt = {} --metatable for complex numbers

function new (r, i)
local cp = {}
cp = {r=r, i=i}
return setmetatable(cp,mt)
end

M.new = new        -- add 'new' to the module

function M.op (...)
local _ENV = complex
return ...
end

function M.tostring (c)
return string.format("(%g,%g)", c.r, c.i) --to avoid +-
end
mt.__tostring = M.tostring
\end{luacode*}
\newcommand\cpxNew[2]{%
\directlua{%
complex[\luastringN{#1}] = M.new(#2)
}%
}
\newcommand\cpxPrint[1]{%
\directlua{tex.sprint(tostring(complex[\luastring{#1}]))}%
}

\newcommand\cpxOp[1]{%
\directlua{%
tex.print(tostring(M.op(#1)))
}%
}
%Workaround
\newcommand\cpxOpp[1]{%
\directlua{%
tex.print(tostring(M.op(complex[\luastring{#1}])))
}%
}
\begin{document}
\cpxNew{a}{3,4}
\cpxPrint{a}
\cpxOp{a+a}
\end{document}