% Permission is granted to copy, distribute and/or modify this % software under the terms of the LaTeX Project Public License % (LPPL), version 1.3c or any later version. % % This software is provided 'as is', without warranty of any kind, % either expressed or implied, including, but not limited to, the % implied warranties of merchantability and fitness for a % particular purpose. \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luacas} [2023/05/26 v1.0.2 CAS written in Lua for LaTeX] \RequirePackage{iftex} \ifluatex \RequirePackage{luacode} \else {\PackageError{luacas} {Not running under LuaLaTeX} {This package requires LuaLaTeX. Try compiling this document with\MessageBreak 'lualatex' instead of 'latex'. This is a fatal error; I'm aborting now.}% }\stop \fi %Required Packages \RequirePackage{xparse} \RequirePackage{pgfkeys} \RequirePackage{verbatim} \RequirePackage{tikz} \RequirePackage{xcolor} \RequirePackage{mathtools} %These files contain Lua code for parsing luacas output; they also initialize the CAS itself \directlua{require('test.luacas-parser') require('test.luacas-helper') } \NewDocumentEnvironment{CAS}% {+b}% {\luaexec{CASparse([[#1]])}}% {} \newcommand{\get}% [2][true]% {\directlua{disp(#2, #1)}} \newcommand{\fetch}[1]{ \directlua{tex.print(tostring(#1))} } \NewDocumentCommand{\store}{m O{#1}}{ \expandafter\def\csname #2\endcsname{% \directlua{ input = #1 if not input[1] then tex.sprint{tostring(input)} else tex.sprint("{") for _,entry in ipairs(input) do tex.sprint(tostring(entry),",") end tex.sprint("}") end }% }% }% \NewDocumentCommand{\yoink}{m O{#1}}{% \expandafter\def\csname #2\endcsname{% \directlua{ tex.print(tostring(#1)) }% }% } %\newcommand{\eval}[1]{\luaexec{tex.print(parse('#1'):tolatex())}} %%%%%%%%%% %% Core %% %%%%%%%%%% %pretty print \NewDocumentCommand{\print}{s m}{% \IfBooleanTF{#1}{% \directlua{ local sym = #2 if sym then tex.print(sym:autosimplify():tolatex()) else tex.print('nil') end }% }{% \directlua{ local sym = #2 if sym then tex.print(sym:tolatex()) else tex.print('nil') end }% }% } %verbatim print \NewDocumentCommand{\vprint}{s m}{% \IfBooleanTF{#1}{% \directlua{ local sym = #2 tex.sprint([[\unexpanded{\begin{verbatim}]]..tostring(sym)..[[\end{verbatim}}]]) }% }{% \directlua{ local sym = #2 tex.sprint([[\unexpanded{\begin{verbatim}]]..tostring(sym:autosimplify())..[[\end{verbatim}}]]) }% }% } \NewDocumentCommand{\lprint}{m O{nil,nil}}{% \luaexec{ local tbl = #1 local low,upp = #2 local tmp =0 if tbl[0] == nil then tmp = 1 end upp = upp or \#tbl low = low or tmp for i=low,upp do tex.print(tbl[i]:tolatex()) if tbl[i+1] then tex.print(",") end end } } %prints the first level of an expression tree; for use within a tikzpicture environment \NewDocumentCommand{\printshrub}{s m}{% \IfBooleanTF{#1}{% \directlua{ local sym = #2 sym = sym:autosimplify() tex.print("\\node [label=90:",whatis(sym),"] {",nameof(sym),"}") tex.print(sym:gettheshrub()) tex.print(";") }% }{% \directlua{ local sym = #2 tex.print("\\node [label=90:",whatis(sym),"] {",nameof(sym),"}") tex.print(sym:gettheshrub()) tex.print(";") }% } } %prints the full expression tree; for use within a tikzpicture environment \NewDocumentCommand{\printtree}{s m}{% \IfBooleanTF{#1}{% \luaexec{ local sym = #2 sym = sym:autosimplify() tex.print("\\node {",nameof(sym),"}") tex.print(sym:getthetree()) tex.print(";") }% }{% \luaexec{ local sym = #2 tex.print("\\node {",nameof(sym),"}") tex.print(sym:getthetree()) tex.print(";") }% } } %parses an expression tree for use within the forest environment; result is stored in \forestresult \NewDocumentCommand{\parseforest}{s m}{% \IfBooleanTF{#1}{% \luaexec{ local sym = #2 sym = sym:autosimplify() tex.print("\\def\\forestresult{") tex.print("[") tex.print(nameof(sym)) tex.print(sym:gettheforest()) tex.print("]") tex.print("}") }% }{% \luaexec { local sym = #2 tex.print("\\def\\forestresult{") tex.print("[") tex.print(nameof(sym)) tex.print(sym:gettheforest()) tex.print("]") tex.print("}") }% } } \NewDocumentCommand{\parseshrub}{s m}{% \IfBooleanTF{#1}{% \luaexec{ local sym = #2 sym = sym:autosimplify() tex.print("\\def\\shrubresult{") tex.print("[") tex.print(nameof(sym)) tex.print(", tikz+={\\node[anchor=south] at (.north) {test};}") tex.print(sym:getthefancyshrub()) tex.print("]") tex.print("}") }% }{% \luaexec{ local sym = #2 tex.print("\\def\\shrubresult{") tex.print("[") tex.print(nameof(sym)) tex.print(", tikz+={\\node[anchor=south,font=\\ttfamily\\footnotesize,gray] at (.north) {",longwhatis(sym),"};}") tex.print(sym:getthefancyshrub()) tex.print("]") tex.print("}") }% } } \NewDocumentCommand{\whatis}{m}{% \luaexec{ tex.sprint("{\\ttfamily",longwhatis(#1),"}") }% } \NewDocumentCommand{\freeof}{s m m}{% \IfBooleanTF{#1}{% \luaexec{ local sym1 = #2 local sym2 = #3 if sym1:freeof(sym2) then tex.print(1) else tex.print(0) end } }{% \luaexec{ local sym1 = #2 local sym2 = #3 sym1 = sym1:autosimplify() sym2 = sym2:autosimplify() if sym1:freeof(sym2) then tex.print(1) else tex.print(0) end }% }% } \NewDocumentCommand{\isatomic}{s m}{% \IfBooleanTF{#1}{ \luaexec{ local sym = #2 if sym:isatomic() then tex.print(1) else tex.print(0) end } }{% \luaexec{ local sym = #2 sym = sym:autosimplify() if sym:isatomic() then tex.print(1) else tex.print(0) end }% }% } \NewDocumentCommand{\isconstant}{s m}{% \IfBooleanTF{#1}{% \luaexec{ local sym = #2 if sym:isconstant() then tex.print(1) else tex.print(0) end }% }{% \luaexec{% local sym = #2 sym = sym:autosimplify() if sym:isconstant() then tex.print(1) else tex.print(0) end }% }% }