summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pgf/libraries/luamath
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/libraries/luamath')
-rw-r--r--Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgflibraryluamath.code.tex499
-rw-r--r--Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.functions.lua313
-rw-r--r--Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.parser.lua647
3 files changed, 1459 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgflibraryluamath.code.tex b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgflibraryluamath.code.tex
new file mode 100644
index 00000000000..b06695a87fa
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgflibraryluamath.code.tex
@@ -0,0 +1,499 @@
+% Copyright 2011 by Christophe Jorssen and Mark Wibrow
+%
+% This file may be distributed and/or modified
+%
+% 1. under the LaTeX Project Public License and/or
+% 2. under the GNU Public License.
+%
+% See the file doc/generic/pgf/licenses/LICENSE for more details.
+%
+% $Id: pgflibraryluamath.code.tex,v 1.11 2012/03/06 16:06:09 cjorssen Exp $
+%
+% !!! Warning: this library does not work with fpu!!!
+
+% *******************************************************************
+% Some luatex stuff. Should be put elsewhere (e.g. in
+% pgfutil-luatex-engine).
+
+% We assume luatex version > 0.39:
+% - \directlua <general text> will work
+% - \directlua is the only luatex primitive that we can assume
+% accessible without being prefixed by the format via
+% tex.enableprimitives.
+% Ideas taken from the ifluatex package (Heiko Oberdiek)
+\let\pgfutil@ifluatex\iffalse
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname directlua\endcsname\relax
+\else
+ \expandafter\let\csname pgfutil@ifluatex\expandafter\endcsname
+ \csname iftrue\endcsname
+\fi
+
+\pgfutil@ifluatex
+ \let\pgfutil@directlua\directlua
+ \pgfutil@directlua{%
+ tex.enableprimitives('pgfutil@',{'luaescapestring'})}
+\else
+ \def\pgfutil@directlua#1{}
+ \def\pgfutil@luaescapestring#1{}
+\fi
+
+% End of luatex stuff
+% *******************************************************************
+
+% Loading part: based on fpu library
+
+\newif\ifpgfluamathcomputationactive
+\newif\ifpgfluamathparseractive
+
+\def\pgfluamath@makecomputationactive{%
+ \ifpgfluamathcomputationactive
+ \else
+ \pgfluamath@checkuninstallcmd%
+ \pgfluamath@install%
+ \pgfluamathcomputationactivetrue
+ \fi}
+
+\def\pgfluamath@makecomputationinactive{%
+ \ifpgfluamathcomputationactive
+ \pgfluamath@uninstall%
+ \pgfluamathcomputationactivefalse
+ \fi}
+
+\def\pgfluamath@makeparseractive{%
+ \ifpgfluamathparseractive
+ \else
+ \let\pgfluamath@pgfmathparse\pgfmathparse
+ \let\pgfmathparse\pgfluamathparse
+ \pgfluamathparseractivetrue
+ \fi}
+
+\def\pgfluamath@makeparserinactive{%
+ \ifpgfluamathparseractive
+ \let\pgfmathparse\pgfluamath@pgfmathparse
+ \pgfluamathparseractivefalse
+ \fi}
+
+\pgfqkeys{/pgf}{%
+ % Enable lua-side computation of \pgfmathresult
+ % (will be deactivated after the current TeX group)
+ luamath/.is choice,
+ luamath/only computation/.code={%
+ \pgfutil@ifluatex
+ \pgfluamath@makecomputationactive
+ \pgfluamath@makeparserinactive
+ \else
+ \pgfmath@error{Sorry, you need the luaTeX engine to use the
+ luamath library}%
+ \fi},
+ luamath/parser and computation/.code={%
+ \pgfutil@ifluatex
+ \pgfluamath@makecomputationactive
+ \pgfluamath@makeparseractive
+ \else
+ \pgfmath@error{Sorry, you need the luaTeX engine to use the
+ luamath library}%
+ \fi},
+ luamath/off/.code={%
+ \pgfluamath@makecomputationinactive
+ \pgfluamath@makeparserinactive},
+ luamath/.default=only computation}
+
+\def\pgfluamath@uninstall@appendcmd#1{%
+ \expandafter\gdef\expandafter\pgfluamath@uninstall\expandafter{%
+ \pgfluamath@uninstall #1}}
+
+% If the uninstall command is already assembled, it will skip the
+% uninstall assemblation.
+\def\pgfluamath@checkuninstallcmd{%
+ \pgfutil@ifundefined{pgfluamath@uninstall}{%
+ \pgfutil@directlua{%
+ pgfluamathfunctions = require("pgfluamath.functions")
+ pgfluamathparser = require("pgfluamath.parser")}
+ \global\let\pgfluamath@uninstall=\pgfutil@empty
+ }{%
+ % We already HAVE an uninstall command (prepared globally).
+ % So: don't waste time assembling one!
+ \def\pgfluamath@uninstall@appendcmd##1{}%
+ \def\pgfluamath@prepareuninstallcmd##1{}%
+ }%
+}
+
+% This assembles an uninstall command globally ON FIRST USAGE.
+% See \pgfmathfloat@plots@checkuninstallcmd
+\def\pgfluamath@prepareuninstallcmd#1{%
+ \expandafter\global\expandafter\let
+ \csname pgfluamath@backup@\string#1\endcsname=#1%
+ \expandafter\gdef\expandafter\pgfluamath@uninstall\expandafter{%
+ \pgfluamath@uninstall
+ \expandafter\let\expandafter#1\csname pgfluamath@backup@\string#1\endcsname}%
+}
+
+\def\pgfluamath@install@function#1=#2{%
+ \pgfluamath@prepareuninstallcmd{#1}%
+ \let#1=#2%
+}
+
+\def\pgfluamath@install{%
+ \pgfluamath@install@function\pgfmathadd@=\pgfluamathadd@%
+ \pgfluamath@install@function\pgfmathsubtract@=\pgfluamathsubtract@%
+ \pgfluamath@install@function\pgfmathneg@=\pgfluamathneg@%
+ \pgfluamath@install@function\pgfmathmultiply@=\pgfluamathmultiply@%
+ \pgfluamath@install@function\pgfmathdivide@=\pgfluamathdivide@%
+ % \pgfluamath@install@function\pgfmathdiv@=\pgfluamathdiv@%
+ \pgfluamath@install@function\pgfmathfactorial@=\pgfluamathfactorial@%
+ \pgfluamath@install@function\pgfmathsqrt@=\pgfluamathsqrt@%
+ % \pgfluamath@install@function\pgfmathpow@=\pgfluamathpow@%
+ \pgfluamath@install@function\pgfmathe@=\pgfluamathe@%
+ \pgfluamath@install@function\pgfmathexp@=\pgfluamathexp@%
+ \pgfluamath@install@function\pgfmathln@=\pgfluamathln@%
+ \pgfluamath@install@function\pgfmathlogten@=\pgfluamathlogten@%
+ % \pgfluamath@install@function\pgfmathlogtwo@=\pgfluamathlogtwo@%
+ \pgfluamath@install@function\pgfmathabs@=\pgfluamathabs@%
+ \pgfluamath@install@function\pgfmathmod@=\pgfluamathmod@%
+ \pgfluamath@install@function\pgfmathMod@=\pgfluamathMod@%
+ \pgfluamath@install@function\pgfmathround@=\pgfluamathround@%
+ \pgfluamath@install@function\pgfmathfloor@=\pgfluamathfloor@%
+ \pgfluamath@install@function\pgfmathceil@=\pgfluamathceil@%
+ % \pgfluamath@install@function\pgfmathint@=\pgfluamathint@%
+ % \pgfluamath@install@function\pgfmathfrac@=\pgfluamathfrac@%
+ % \pgfluamath@install@function\pgfmathreal@=\pgfluamathreal@%
+ \pgfluamath@install@function\pgfmathgcd@=\pgfluamathgcd@%
+ \pgfluamath@install@function\pgfmathisprime@=\pgfluamathisprime@%
+ \pgfluamath@install@function\pgfmathpi@=\pgfluamathpi@%
+ \pgfluamath@install@function\pgfmathrad@=\pgfluamathrad@%
+ \pgfluamath@install@function\pgfmathdeg@=\pgfluamathdeg@%
+ \pgfluamath@install@function\pgfmathsin@=\pgfluamathsin@%
+ \pgfluamath@install@function\pgfmathcos@=\pgfluamathcos@%
+ \pgfluamath@install@function\pgfmathtan@=\pgfluamathtan@%
+ \pgfluamath@install@function\pgfmathsec@=\pgfluamathsec@%
+ \pgfluamath@install@function\pgfmathcosec@=\pgfluamathcosec@%
+ \pgfluamath@install@function\pgfmathcot@=\pgfluamathcot@%
+ \pgfluamath@install@function\pgfmathasin@=\pgfluamathasin@%
+ \pgfluamath@install@function\pgfmathacos@=\pgfluamathacos@%
+ \pgfluamath@install@function\pgfmathatan@=\pgfluamathatan@%
+ \pgfluamath@install@function\pgfmathatantwo@=\pgfluamathatantwo@%
+ \pgfluamath@install@function\pgfmathmax@=\pgfluamathmax@%
+ \pgfluamath@install@function\pgfmathmin@=\pgfluamathmin@%
+ % \pgfluamath@install@function\pgfmath@pi=\pgfluamathpi@%
+ % \pgfluamath@install@function\pgfmathpi=\pgfluamathpi@%
+ % \pgfluamath@install@function\pgfmathe@=\pgfluamathe@%
+ % \pgfluamath@install@function\pgfmathe=\pgfluamathe@%
+ % \pgfluamath@install@function\pgfmathlessthan@=\pgfluamathlessthan@%
+ % \pgfluamath@install@function\pgfmathless@=\pgfluamathlessthan@%
+ % \pgfluamath@install@function\pgfmathgreaterthan@=\pgfluamathgreaterthan@%
+ % \pgfluamath@install@function\pgfmathgreater@=\pgfluamathgreaterthan@%
+ % \pgfluamath@install@function\pgfmathpow@=\pgfluamathpow@
+ \pgfluamath@install@function\pgfmathrand@=\pgfluamathrand@
+ \pgfluamath@install@function\pgfmathrand=\pgfluamathrand@
+ \pgfluamath@install@function\pgfmathrnd@=\pgfluamathrnd@
+ \pgfluamath@install@function\pgfmathrnd=\pgfluamathrnd@
+ % \pgfluamath@install@function\pgfmathtrue@=\pgfluamathtrue@
+ % \pgfluamath@install@function\pgfmathfalse@=\pgfluamathfalse@
+ % \pgfluamath@install@function\pgfmathnot@=\pgfluamathnot@
+ % \pgfluamath@install@function\pgfmathhex@=\pgfluamathhex@
+ % \pgfluamath@install@function\pgfmathHex@=\pgfluamathHex@
+ % \pgfluamath@install@function\pgfmathoct@=\pgfluamathoct@
+ % \pgfluamath@install@function\pgfmathbin@=\pgfluamathbin@
+ % \pgfluamath@install@function\pgfmathand@=\pgfluamathand@
+ % \pgfluamath@install@function\pgfmathor@=\pgfluamathor@
+ % \pgfluamath@install@function\pgfmathfactorial@=\pgfluamathfactorial@
+ % \pgfluamath@install@function\pgfmathveclen@=\pgfluamathveclen@
+ % \pgfluamath@install@function\pgfmathcosh@=\pgfluamathcosh@
+ % \pgfluamath@install@function\pgfmathsinh@=\pgfluamathsinh@
+ % \pgfluamath@install@function\pgfmathtanh@=\pgfluamathtanh@
+ % \pgfluamath@install@function@unimplemented{ceil}%
+ % \pgfluamath@install@function@unimplemented{frac}%
+ % \pgfluamath@install@function@unimplemented{log2}%
+ % \pgfluamath@install@function@unimplemented{log10}%
+ % \pgfluamath@install@function@unimplemented{equalto}%
+ % \pgfluamath@install@function@unimplemented{random}%
+ % \pgfluamath@install@function@unimplemented{setseed}%
+ % \pgfluamath@install@function@unimplemented{Mod}%
+ % \pgfluamath@install@function@unimplemented{real}%
+ % \pgfluamath@install@function@unimplemented{notequal}%
+ \pgfluamath@install@function\pgfmathreciprocal=\pgfluamathreciprocal%
+ \pgfluamath@install@function\pgfpointnormalised=\pgfluamathpointnormalised
+}
+
+\def\pgfluamathgetresult#1{%
+ \edef\pgfmathresult{\pgfutil@directlua{tex.print(-1,#1)}}}
+
+\def\pgfluamathpi@{%
+ \pgfluamathgetresult{pgfluamathfunctions.pi()}}
+\def\pgfluamathe@{%
+ \pgfluamathgetresult{pgfluamathfunctions.e()}}
+\def\pgfluamathadd@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.add(#1,#2)}}
+\def\pgfluamathsubtract@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.substract(#1,#2)}}
+\def\pgfluamathneg@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.neg(#1)}}
+\def\pgfluamathmultiply@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.multiply(#1,#2)}}
+\def\pgfluamathdivide@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.divide(#1,#2)}}
+\def\pgfluamathabs@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.abs(#1)}}
+\def\pgfluamathround@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.round(#1)}}
+\def\pgfluamathfloor@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.floor(#1)}}
+\def\pgfluamathceil@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.ceil(#1)}}
+\def\pgfluamathgcd@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.gcd(#1,#2)}}
+\def\pgfluamathisprime@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.isprime(#1)}}
+\def\pgfluamathmax@#1{%
+ \pgfluamathgetresult{%
+ math.max(pgfluamathfunctions.split_braces_to_explist("#1"))}}
+\def\pgfluamathmin@#1{%
+ \pgfluamathgetresult{%
+ math.min(pgfluamathfunctions.split_braces_to_explist("#1"))}}
+\def\pgfluamathsin@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.Sin(#1)}}
+\def\pgfluamathcos@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.Cos(#1)}}
+\def\pgfluamathtan@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.Tan(#1)}}
+\def\pgfluamathmod@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.mod(#1,#2)}}
+\def\pgfluamathMod@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.Mod(#1,#2)}}
+\def\pgfluamathrad@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.rad(#1)}}
+\def\pgfluamathdeg@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.deg(#1)}}
+\def\pgfluamathatan@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.aTan(#1)}}
+\def\pgfluamathatantwo@#1#2{%
+ \pgfluamathgetresult{pgfluamathfunctions.aTan2(#1,#2)}}
+\def\pgfluamathasin@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.aSin(#1)}}
+\def\pgfluamathacos@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.aCos(#1)}}
+\def\pgfluamathcot@#1{%
+ \pgfluamathgetresult{1/pgfluamathfunctions.Tan(#1)}}
+\def\pgfluamathsec@#1{%
+ \pgfluamathgetresult{1/pgfluamathfunctions.Cos(#1)}}
+\def\pgfluamathcosec@#1{%
+ \pgfluamathgetresult{1/pgfluamathfunctions.Sin(#1)}}
+\def\pgfluamathexp@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.exp(#1)}}
+\def\pgfluamathln@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.log(#1)}}
+\def\pgfluamathlogten@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.log10(#1)}}
+\def\pgfluamathsqrt@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.sqrt(#1)}}
+\def\pgfluamathrnd@{%
+ \pgfluamathgetresult{pgfluamathfunctions.rnd()}}
+\def\pgfluamathrand@{%
+ \pgfluamathgetresult{pgfluamathfunctions.rand(-1,1)}}
+\def\pgfluamathfactorial@#1{%
+ \pgfluamathgetresult{pgfluamathfunctions.factorial(#1)}}
+\def\pgfluamathreciprocal#1{%
+ \pgfluamathgetresult{1/#1}}
+% \pgfluamath@install@function\pgfmath@pi=\pgfluamathpi@%
+% \pgfluamath@install@function\pgfmathpi=\pgfluamathpi@%
+% \pgfluamath@install@function\pgfmathe@=\pgfluamathe@%
+% \pgfluamath@install@function\pgfmathe=\pgfluamathe@%
+% \pgfluamath@install@function\pgfmathlessthan@=\pgfluamathlessthan@%
+% \pgfluamath@install@function\pgfmathless@=\pgfluamathlessthan@%
+% \pgfluamath@install@function\pgfmathgreaterthan@=\pgfluamathgreaterthan@%
+% \pgfluamath@install@function\pgfmathgreater@=\pgfluamathgreaterthan@%
+% \pgfluamath@install@function\pgfmathpow@=\pgfluamathpow@
+% \pgfluamath@install@function\pgfmathrand@=\pgfluamathrand@
+% \pgfluamath@install@function\pgfmathrand=\pgfluamathrand@
+% \pgfluamath@install@function\pgfmathrnd@=\pgfluamathrnd@
+% \pgfluamath@install@function\pgfmathrnd=\pgfluamathrnd@
+% \pgfluamath@install@function\pgfmathtrue@=\pgfluamathtrue@
+% \pgfluamath@install@function\pgfmathfalse@=\pgfluamathfalse@
+% \pgfluamath@install@function\pgfmathnot@=\pgfluamathnot@
+% \pgfluamath@install@function\pgfmathhex@=\pgfluamathhex@
+% \pgfluamath@install@function\pgfmathHex@=\pgfluamathHex@
+% \pgfluamath@install@function\pgfmathoct@=\pgfluamathoct@
+% \pgfluamath@install@function\pgfmathbin@=\pgfluamathbin@
+% \pgfluamath@install@function\pgfmathand@=\pgfluamathand@
+% \pgfluamath@install@function\pgfmathor@=\pgfluamathor@
+% \pgfluamath@install@function\pgfmathfactorial@=\pgfluamathfactorial@
+% \pgfluamath@install@function\pgfmathveclen@=\pgfluamathveclen@
+% \pgfluamath@install@function\pgfmathcosh@=\pgfluamathcosh@
+% \pgfluamath@install@function\pgfmathsinh@=\pgfluamathsinh@
+% \pgfluamath@install@function\pgfmathtanh@=\pgfluamathtanh@
+
+\def\pgfluamathpointnormalised#1{%
+ \pgf@process{#1}%
+ \pgfutil@directlua{%
+ pgfluamathfunctions.pointnormalised(%
+ \pgf@sys@tonumber{\pgf@x},\pgf@sys@tonumber{\pgf@y})}%
+ \ignorespaces}
+
+% Parser
+
+\newif\ifpgfluamathunitsdeclared
+
+\def\pgfluamathparse#1{%
+ \pgfluamathunitsdeclaredfalse
+ % The following "two passes" (TeX -> lua -> TeX -> lua -> TeX) is
+ % required for chadef'ed named boxes. The parser
+ % adds \number in front of the box name (e.g. \mybox ->
+ % \number\mybox). Then this is expanded to the chardef'ed number via
+ % \edef expansion.
+ \edef\pgfluamath@temp{%
+ \pgfutil@directlua{%
+ % Double quotes " are needed here. On the lua side, single quotes
+ % ' are used. Take care to don't mix them.
+ pgfluamathparser.parse("\pgfutil@luaescapestring{#1}")
+ tex.sprint(parsed_expression)}}%
+ % We can now feed back the evaluator.
+ \edef\pgfluamathresult{%
+ \pgfutil@directlua{%
+ pgfluamathparser.eval('\pgfluamath@temp')
+ if pgfluamathparser.result == nil then
+ tex.print('nil')
+ else
+ tex.print(pgfluamathparser.result)
+ end}}%
+ \csname pgfluamathunitsdeclared\pgfutil@directlua{%
+ if pgfluamathparser.units_declared == true then
+ tex.print('true')
+ else
+ tex.print('false')
+ end}\endcsname
+ \ifpgfluamathparseractive
+ \let\pgfmathresult\pgfluamathresult
+ \let\ifpgfmathunitsdeclared=\ifpgfluamathunitsdeclared
+ \fi}
+
+\endinput
+% NEW: CJ (06 March 2012) Work in progress
+\documentclass{minimal}
+
+\usepackage{pgfmath}
+
+\makeatletter
+\let\pgfutil@directlua\directlua
+
+\directlua{dofile('pgfmathparser.lua')}
+
+\def\pgfluamathdeclarefunction#1#2#3{%
+ \pgfutil@directlua{%
+ pgfluamath.declare_new_function('#1',#2,#3)}}
+
+\pgfluamathdeclarefunction{add}{2}{%
+ function (a,b) return a + b end}
+
+\pgfluamathdeclarefunction{substract}{2}{%
+ function (a,b) return a - (b) end}
+
+\pgfluamathdeclarefunction{neg}{1}{%
+ function (a) return -(a) end}
+
+\pgfluamathdeclarefunction{multiply}{2}{%
+ function (a,b) return a * b end}
+
+\pgfluamathdeclarefunction{divide}{2}{%
+ function (a,b) return a / b end}
+
+\pgfluamathdeclarefunction{pow}{2}{%
+ function (a,b) return math.pow(a,b) end}
+
+\pgfluamathdeclarefunction{deg}{1}{%
+ function (a) return math.deg(a) end}
+
+\pgfluamathdeclarefunction{ifthenelse}{3}{%
+ function (a,b,c) if a == 1 then return b else return c end end}
+
+\pgfluamathdeclarefunction{equal}{2}{%
+ function (a,b) if a == b then return 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{greater}{2}{%
+ function (a,b) if a > b then return 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{less}{2}{%
+ function (a,b) if a < b then return 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{notequal}{2}{%
+ function (a,b) if a < b or a > b then return 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{notless}{2}{%
+ function (a,b) if a >= b then return 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{notgreater}{2}{%
+ function (a,b) if a <= b then return 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{andPGF}{2}{%
+ function (a,b) if (a < 0 or a > 0) and (b < 0 or b > 0) then return
+ 1 else return 0 end end}
+
+\pgfluamathdeclarefunction{orPGF}{2}{%
+ function (a,b) if (a < 0 or a > 0) or (b < 0 or b > 0) then return 1
+ else return 0 end end}
+
+\pgfluamathdeclarefunction{modulo}{2}{%
+ % This is the definition of the lua % modulo operator
+ % The % operator cannot be used here (catcode issue)
+ function (a,b) return a - math.floor(a/b)*b end}
+
+\pgfluamathdeclarefunction{int}{1}{%
+ function (a) return a - pgfluamath.defined_functions.modulo.code(a,1) end}
+
+\pgfluamathdeclarefunction{frac}{1}{%
+ function (a) return pgfluamath.defined_functions.modulo.code(a,1) end}
+
+\pgfluamathdeclarefunction{factorial}{1}{%
+ function (a)
+ a = math.abs(pgfluamath.defined_functions.int.code(a))
+ if a == 1 then
+ return 1
+ else
+ return a * pgfluamath.defined_functions.factorial.code(a-1)
+ end
+ end}
+
+\pgfluamathdeclarefunction{sqrt}{1}{%
+ function (a) return math.sqrt(a) end}
+
+
+
+\def\pgfluamathparseandresult#1{%
+ \pgfutil@directlua{%
+ local s = pgfluamath.transform_math_expr('#1',pgfluamath.defined_functions_pattern)
+ texio.write_nl('pgfluamath: parsed expression "' .. s .. '"')
+ loadstring('tex.sprint(-1,' .. s .. ')')()}}
+
+\makeatother
+\begin{document}
+
+$\pgfluamathparseandresult{1+2} = 3$
+
+$\pgfluamathparseandresult{2*3} = 6$
+
+$\pgfluamathparseandresult{1--1} = 2$
+
+$\pgfluamathparseandresult{6/2} = 3$
+
+$\pgfluamathparseandresult{2^2} = 4$
+
+$\pgfluamathparseandresult{1>2} = 0$
+
+$\pgfluamathparseandresult{2>1} = 1$
+
+$\pgfluamathparseandresult{1!=1} = 0$
+
+$\pgfluamathparseandresult{1?2:3} = 2$
+
+$\pgfluamathparseandresult{1.0||0} = 1$
+
+$\pgfluamathparseandresult{1&&0} = 0$
+
+$\pgfluamathparseandresult{sqrt(2)} = \pgfmathparse{sqrt(2)}\pgfmathresult$
+
+%\pgfluamathparseandresult{{1,{2,3-7}[1],4}[1]^2}
+
+\end{document}
+% Local Variables:
+% TeX-engine: luatex
+% End: \ No newline at end of file
diff --git a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.functions.lua b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.functions.lua
new file mode 100644
index 00000000000..fa3c1872a58
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.functions.lua
@@ -0,0 +1,313 @@
+-- Copyright 2011 by Christophe Jorssen
+--
+-- This file may be distributed and/or modified
+--
+-- 1. under the LaTeX Project Public License and/or
+-- 2. under the GNU Public License.
+--
+-- See the file doc/generic/pgf/licenses/LICENSE for more details.
+--
+-- $Id: pgfluamath.functions.lua,v 1.9 2013/07/25 10:39:34 tantau Exp $
+--
+
+local pgfluamathfunctions = pgfluamathfunctions or {}
+
+local mathabs, mathacos, mathasin = math.abs, math.acos, math.asin
+local mathatan, mathatan2, mathceil = math.atan, math.atan2, math.ceil
+local mathcos, mathcosh, mathdeg = math.cos, math.cosh, math.deg
+local mathexp, mathfloor, mathfmod = math.exp, math.floor, math.fmod
+local mathfrexp, mathhuge, mathldexp = math.frexp, math.huge, math.ldexp
+local mathlog, mathlog10, mathmax = math.log, math.log10, math.max
+local mathmin, mathmodf, mathpi = math.min, math.modf, math.pi
+local mathpow, mathrad, mathrandom = math.pow, math.rad, math.random
+local mathrandomseed, mathsin = math.randomseed, math.sin
+local mathsinh, mathsqrt, mathtanh = math.sinh, math.sqrt, math.tanh
+local mathtan = math.tan
+
+function pgfluamathfunctions.add(x,y)
+ return x+y
+end
+
+function pgfluamathfunctions.substract(x,y)
+ return x-y
+end
+
+function pgfluamathfunctions.neg(x)
+ return -x
+end
+
+function pgfluamathfunctions.multiply(x,y)
+ return x*y
+end
+
+function pgfluamathfunctions.divide(x,y)
+ return x/y
+end
+
+function pgfluamathfunctions.pow(x,y)
+ return mathpow(x,y)
+end
+
+function pgfluamathfunctions.factorial(x)
+-- TODO: x must be an integer
+ if x == 0 then
+ return 1
+ else
+ return x * factorial(x-1)
+ end
+end
+
+function pgfluamathfunctions.deg(x)
+ return mathdeg(x)
+end
+
+function pgfluamathfunctions.ifthenelse(x,y,z)
+ if x~= 0 then
+ return y
+ else
+ return z
+ end
+end
+
+function pgfluamathfunctions.equal(x,y)
+ if x == y then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.greater(x,y)
+ if x > y then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.less(x,y)
+ if x < y then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.notequal(x,y)
+ if x ~= y then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.notless(x,y)
+ if x >= y then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.notgreater(x,y)
+ if x <= y then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.andPGF(x,y)
+ if (x ~= 0) and (y ~= 0) then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.orPGF(x,y)
+ if (x ~= 0) or (y ~= 0) then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.notPGF(x)
+ if x == 0 then
+ return 1
+ else
+ return 0
+ end
+end
+
+function pgfluamathfunctions.pi()
+ return mathpi
+end
+
+function pgfluamathfunctions.e()
+ return mathexp(1)
+end
+
+function pgfluamathfunctions.abs(x)
+ return mathabs(x)
+end
+
+function pgfluamathfunctions.floor(x)
+ return mathfloor(x)
+end
+
+function pgfluamathfunctions.ceil(x)
+ return mathceil(x)
+end
+
+function pgfluamathfunctions.exp(x)
+ return mathexp(x)
+end
+
+function pgfluamathfunctions.log(x)
+ return mathlog(x)
+end
+
+function pgfluamathfunctions.log10(x)
+ return mathlog10(x)
+end
+
+function pgfluamathfunctions.sqrt(x)
+ return mathsqrt(x)
+end
+
+function pgfluamathfunctions.rnd()
+ return mathrandom()
+end
+
+function pgfluamathfunctions.rand()
+ return mathrandom(-1,1)
+end
+
+function pgfluamathfunctions.deg(x)
+ return mathdeg(x)
+end
+
+function pgfluamathfunctions.rad(x)
+ return mathrad(x)
+end
+
+function pgfluamathfunctions.round(x)
+ if x<0 then
+ return -mathceil(mathabs(x))
+ else
+ return mathceil(x)
+ end
+end
+
+function pgfluamathfunctions.gcd(a, b)
+ if b == 0 then
+ return a
+ else
+ return gcd(b, a%b)
+ end
+end
+
+function pgfluamathfunctions.isprime(a)
+ local ifisprime = true
+ if a == 1 then
+ ifisprime = false
+ elseif a == 2 then
+ ifisprime = true
+-- if a > 2 then
+ else
+ local i, imax = 2, mathceil(mathsqrt(a)) + 1
+ while ifisprime and (i < imax) do
+ if gcd(a,i) ~= 1 then
+ ifisprime = false
+ end
+ i = i + 1
+ end
+ end
+ if ifisprime then
+ return 1
+ else
+ return 0
+ end
+end
+
+
+function pgfluamathfunctions.split_braces_to_explist(s)
+ -- (Thanks to mpg and zappathustra from fctt)
+ -- Make unpack available whatever lua version is used
+ -- (unpack in lua 5.1 table.unpack in lua 5.2)
+ local unpack = table.unpack or unpack
+ local t = {}
+ for i in s:gmatch('%b{}') do
+ table.insert(t, tonumber(i:sub(2, -2)))
+ end
+ return unpack(t)
+end
+
+function pgfluamathfunctions.split_braces_to_table(s)
+ local t = {}
+ for i in s:gmatch('%b{}') do
+ table.insert(t, tonumber(i:sub(2, -2)))
+ end
+ return t
+end
+
+function pgfluamathfunctions.mod(x,y)
+ if x/y < 0 then
+ return -(mathabs(x)%mathabs(y))
+ else
+ return mathabs(x)%mathabs(y)
+ end
+end
+
+function pgfluamathfunctions.Mod(x,y)
+ return mathabs(x)%mathabs(y)
+end
+
+function pgfluamathfunctions.Sin(x)
+ return mathsin(mathrad(x))
+end
+
+function pgfluamathfunctions.Cos(x)
+ return mathcos(mathrad(x))
+end
+
+function pgfluamathfunctions.Tan(x)
+ return mathtan(mathrad(x))
+end
+
+function pgfluamathfunctions.aSin(x)
+ return mathdeg(mathasin(x))
+end
+
+function pgfluamathfunctions.aCos(x)
+ return mathdeg(mathacos(x))
+end
+
+function pgfluamathfunctions.aTan(x)
+ return mathdeg(mathatan(x))
+end
+
+function pgfluamathfunctions.aTan2(y,x)
+ return mathdeg(mathatan2(y,x))
+end
+
+function pgfluamathfunctions.pointnormalised (pgfx, pgfy)
+ local pgfx_normalised, pgfy_normalised
+ if pgfx == 0. and pgfy == 0. then
+ -- Orginal pgf macro gives this result
+ tex.dimen['pgf@x'] = "0pt"
+ tex.dimen['pgf@y'] = "1pt"
+ else
+ pgfx_normalised = pgfx/math.sqrt(pgfx^2 + pgfy^2)
+ pgfx_normalised = pgfx_normalised - pgfx_normalised%0.00001
+ pgfy_normalised = pgfy/math.sqrt(pgfx^2 + pgfy^2)
+ pgfy_normalised = pgfy_normalised - pgfy_normalised%0.00001
+ tex.dimen['pgf@x'] = tostring(pgfx_normalised) .. "pt"
+ tex.dimen['pgf@y'] = tostring(pgfy_normalised) .. "pt"
+ end
+ return nil
+end
+
+return pgfluamathfunctions \ No newline at end of file
diff --git a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.parser.lua b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.parser.lua
new file mode 100644
index 00000000000..b059e334358
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgfluamath.parser.lua
@@ -0,0 +1,647 @@
+-- Copyright 2011 by Christophe Jorssen and Mark Wibrow
+--
+-- This file may be distributed and/or modified
+--
+-- 1. under the LaTeX Project Public License and/or
+-- 2. under the GNU Public License.
+--
+-- See the file doc/generic/pgf/licenses/LICENSE for more details.
+--
+-- $Id: pgfluamath.parser.lua,v 1.14 2012/04/29 20:36:29 ludewich Exp $
+
+local pgfluamathparser = pgfluamathparser or {}
+
+require("pgfluamath.functions")
+
+-- lpeg is always present in luatex
+local lpeg = require("lpeg")
+
+local S, P, R = lpeg.S, lpeg.P, lpeg.R
+local C, Cc, Ct = lpeg.C, lpeg.Cc, lpeg.Ct
+local Cf, Cg, Cs = lpeg.Cf, lpeg.Cg, lpeg.Cs
+local V = lpeg.V
+
+local space_pattern = S(" \n\r\t")^0
+
+local exponent_pattern = S("eE")
+
+local one_digit_pattern = R("09")
+local positive_integer_pattern = one_digit_pattern^1
+local integer_pattern = P("-")^-1 * positive_integer_pattern
+-- Valid positive decimals are |xxx.xxx|, |.xxx| and |xxx.|
+local positive_decimal_pattern = (one_digit_pattern^1 * P(".") *
+ one_digit_pattern^1) +
+ (P(".") * one_digit_pattern^1) +
+ (one_digit_pattern^1 * P("."))
+local decimal_pattern = P("-")^-1 * positive_decimal_pattern
+local float_pattern = decimal_pattern * exponent_pattern * integer_pattern
+local number_pattern = float_pattern + decimal_pattern + integer_pattern
+
+local at_pattern = P("@")
+
+local underscore_pattern = P("_")
+
+local lower_letter_pattern = R("az")
+local upper_letter_pattern = R("AZ")
+local letter_pattern = lower_letter_pattern + upper_letter_pattern
+local alphanum_pattern = letter_pattern + one_digit_pattern
+local alphanum__pattern = alphanum_pattern + underscore_pattern
+local alpha__pattern = letter_pattern + underscore_pattern
+
+local openparen_pattern = P("(")
+local closeparen_pattern = P(")")
+local opencurlybrace_pattern = P("{")
+local closecurlybrace_pattern = P("}")
+local openbrace_pattern = P("[")
+local closebrace_pattern = P("]")
+
+-- local string = P('"') * C((1 - P('"'))^0) * P('"')
+
+local orop_pattern = P("||")
+local andop_pattern = P("&&")
+
+local neqop_pattern = P("!=")
+
+local then_pattern = P("?")
+local else_pattern = P(":")
+local factorial_pattern = P("!")
+local not_mark_pattern = P("!")
+local radians_pattern = P("r")
+
+local comma_pattern = P(",")
+
+--[[
+local grammar = P {
+ -- "E" stands for expression
+ "ternary_logical_E",
+ ternary_logical_E = Cf(V("logical_or_E") *
+ Cg( then_mark * V("logical_or_E") * else_mark * V("logical_or_E"))^0,evalternary);
+ logical_or_E = Cf(V("logical_and_E") * Cg(orop * V("logical_and_E"))^0,evalbinary);
+ logical_and_E = Cf(V("equality_E") * Cg(andop * V("equality_E"))^0,evalbinary);
+ equality_E = Cf(V("relational_E") *
+ Cg((eqop * V("relational_E")) + (neqop * V("relational_E")))^0,evalbinary);
+ relational_E = Cf(V("additive_E") * Cg((lessop * V("additive_E")) +
+ (greatop * V("additive_E")) +
+ (lesseqop * V("additive_E")) +
+ (greateqop * V("additive_E")))^0,evalbinary);
+ additive_E = Cf(V("multiplicative_E") * Cg((addop * V("multiplicative_E")) +
+ (subop * V("multiplicative_E")))^0,evalbinary);
+ multiplicative_E = Cf(V("power_E") * Cg((mulop * V("power_E")) +
+ divop * V("power_E"))^0,evalbinary);
+ power_E = Cf(V("postfix_unary_E") * Cg(powop * V("postfix_unary_E"))^0,evalbinary);
+ postfix_unary_E = Cf(V("prefix_unary_E") * Cg(radians + factorial)^0,evalpostfixunary);
+ prefix_unary_E = Cf(Cg(not_mark + negop)^0 * V("E"),evalprefixunary),
+ E = string + float + decimal + integer / tonumber +
+ (openparen * V("ternary_logical_E") * closeparen) +
+ (func * param_beg * V("ternary_logical_E") *
+ (comma * V("ternary_logical_E"))^0 * param_end);
+}
+
+local parser = space_pattern * grammar * -1
+--]]
+
+-- NOTE: \pgfmathparse{pi/3.14} will fail giving pgfluamathfunctions.pi()3.14
+-- (the / is missing, probably gobbled by one of the captures of the grammar).
+
+pgfluamathparser.transform_operands = P({
+ 'transform_operands';
+
+ one_char = lpeg.P(1),
+ lowercase = lpeg.R('az'),
+ uppercase = lpeg.R('AZ'),
+ numeric = lpeg.R('09'),
+ dot = lpeg.P('.'),
+ exponent = lpeg.S('eE'),
+ sign_prefix = lpeg.S('-+'),
+ begingroup = lpeg.P('('),
+ endgroup = lpeg.P(')'),
+ backslash = lpeg.P'\\',
+ at = lpeg.P'@',
+
+ alphabetic = lpeg.V'lowercase' + lpeg.V'uppercase',
+ alphanumeric = lpeg.V'alphabetic' + lpeg.V'numeric',
+
+ integer = lpeg.V'numeric'^1,
+ real = lpeg.V'numeric'^0 * lpeg.V'dot' * lpeg.V'numeric'^1,
+ scientific = (lpeg.V'real' + lpeg.V'integer') * lpeg.V'exponent' * lpeg.V'sign_prefix'^0 * lpeg.V'integer',
+
+ number = lpeg.V'scientific' + lpeg.V'real' + lpeg.V'integer',
+ function_name = lpeg.V('alphabetic') * lpeg.V('alphanumeric')^0,
+
+ tex_cs = lpeg.V'backslash' * (lpeg.V'alphanumeric' + lpeg.V'at')^1,
+ tex_box_dimension_primative = lpeg.V'backslash' * (lpeg.P'wd' + lpeg.P'ht' + lpeg.P'dp'),
+ tex_register_primative = lpeg.V'backslash' * (lpeg.P'count' + lpeg.P'dimen'),
+
+ tex_primative = lpeg.V'tex_box_dimension_primative' + lpeg.V'tex_register_primative',
+ tex_macro = -lpeg.V'tex_primative' * lpeg.V'tex_cs',
+
+ tex_unit =
+ lpeg.P('pt') + lpeg.P('mm') + lpeg.P('cm') + lpeg.P('in') +
+ lpeg.P('ex') + lpeg.P('em') + lpeg.P('bp') + lpeg.P('pc') +
+ lpeg.P('dd') + lpeg.P('cc') + lpeg.P('sp'),
+
+ tex_register_named = lpeg.C(lpeg.V'tex_macro'),
+ tex_register_numbered = lpeg.C(lpeg.V'tex_register_primative') * lpeg.C(lpeg.V'integer'),
+ tex_register_basic = lpeg.Cs(lpeg.Ct(lpeg.V'tex_register_numbered' + lpeg.V'tex_register_named') / pgfluamathparser.process_tex_register),
+
+ tex_multiplier = lpeg.Cs((lpeg.V'tex_register_basic' + lpeg.C(lpeg.V'number')) / pgfluamathparser.process_muliplier),
+
+ tex_box_width = lpeg.Cs(lpeg.P('\\wd') / 'width'),
+ tex_box_height = lpeg.Cs(lpeg.P('\\ht') / 'height'),
+ tex_box_depth = lpeg.Cs(lpeg.P('\\dp') / 'depth'),
+ tex_box_dimensions = lpeg.V'tex_box_width' + lpeg.V'tex_box_height' + lpeg.V'tex_box_depth',
+ tex_box_named = lpeg.Cs(lpeg.Ct(lpeg.V'tex_box_dimensions' * lpeg.C(lpeg.V'tex_macro')) / pgfluamathparser.process_tex_box_named),
+ tex_box_numbered = lpeg.Cs(lpeg.Ct(lpeg.V'tex_box_dimensions' * lpeg.C(lpeg.V'number')) / pgfluamathparser.process_tex_box_numbered),
+ tex_box_basic = lpeg.V'tex_box_named' + lpeg.V'tex_box_numbered',
+
+ tex_register = lpeg.Cs(lpeg.V'tex_multiplier' * lpeg.V'tex_register_basic') + lpeg.V'tex_register_basic',
+ tex_box = lpeg.Cs(lpeg.Cs(lpeg.V'tex_multiplier') * lpeg.V'tex_box_basic') + lpeg.V'tex_box_basic',
+ tex_dimension = lpeg.Cs(lpeg.V'number' * lpeg.V'tex_unit' / pgfluamathparser.process_tex_dimension),
+
+ tex_operand = lpeg.Cs(lpeg.V'tex_dimension' + lpeg.V'tex_box' + lpeg.V'tex_register'),
+
+ function_name = lpeg.V'alphabetic' * (lpeg.V'alphanumeric'^1),
+ function_operand = lpeg.Cs(lpeg.Ct(lpeg.C(lpeg.V'function_name') * lpeg.C(lpeg.V'one_char') + lpeg.C(lpeg.V'function_name')) / pgfluamathparser.process_function),
+
+ -- order is (always) important!
+ operands = lpeg.V'tex_operand' + lpeg.V'number' + lpeg.V'function_operand',
+
+ transform_operands = lpeg.Cs((lpeg.V'operands' + 1)^0)
+ })
+
+-- Namespaces will be searched in the following order.
+pgfluamathparser.function_namespaces = {
+ 'pgfluamathfunctions', 'math', '_G'}
+
+pgfluamathparser.units_declared = false
+
+function pgfluamathparser.get_tex_box(box, dimension)
+ -- assume get_tex_box is only called when a dimension is required.
+ pgfluamathparser.units_declared = true
+ if dimension == 'width' then
+ return tex.box[box].width / 65536 -- return in points.
+ elseif dimension == 'height' then
+ return tex.box[box].height / 65536
+ else
+ return tex.box[box].depth / 65536
+ end
+end
+
+function pgfluamathparser.get_tex_register(register)
+ -- register is a string which could be a count or a dimen.
+ if pcall(tex.getcount, register) then
+ return tex.count[register]
+ elseif pcall(tex.getdimen, register) then
+ pgfluamathparser.units_declared = true
+ return tex.dimen[register] / 65536 -- return in points.
+ else
+ pgfluamathparser.error = 'I do not know the TeX register "' .. register '"'
+ return nil
+ end
+
+end
+
+function pgfluamathparser.get_tex_count(count)
+ -- count is expected to be a number
+ return tex.count[tonumber(count)]
+end
+
+function pgfluamathparser.get_tex_dimen(dimen)
+ -- dimen is expected to be a number
+ pgfluamathparser.units_declared = true
+ return tex.dimen[tonumber(dimen)] / 65536
+end
+
+function pgfluamathparser.get_tex_sp(dimension)
+ -- dimension should be a string
+ pgfluamathparser.units_declared = true
+ return tex.sp(dimension) / 65536
+end
+
+
+
+-- transform named box specification
+-- e.g., \wd\mybox -> pgfluamathparser.get_tex_box["mybox"].width
+--
+function pgfluamathparser.process_tex_box_named(box)
+ return 'pgfluamathparser.get_tex_box(\\number' .. box[2] .. ', "' .. box[1] .. '")'
+end
+
+-- transform numbered box specification
+-- e.g., \wd0 -> pgfluamathparser.get_tex_box["0"].width
+--
+function pgfluamathparser.process_tex_box_numbered(box)
+ return 'pgfluamathparser.get_tex_box("' .. box[2] .. '", "' .. box[1] .. '")'
+end
+
+-- transform a register
+-- e.g., \mycount -> pgfluamathparser.get_tex_register["mycount"]
+-- \dimen12 -> pgfluamathparser.get_tex_dimen[12]
+--
+function pgfluamathparser.process_tex_register(register)
+ if register[2] == nil then -- a named register
+ return 'pgfluamathparser.get_tex_register("' .. register[1]:sub(2, register[1]:len()) .. '")'
+ else -- a numbered register
+ return 'pgfluamathparser.get_tex_' .. register[1]:sub(2, register[1]:len()) .. '(' .. register[2] .. ')'
+ end
+end
+
+-- transform a 'multiplier'
+-- e.g., 0.5 -> 0.5* (when followed by a box/register)
+--
+function pgfluamathparser.process_muliplier(multiplier)
+ return multiplier .. '*'
+end
+
+-- transform an explicit dimension to points
+-- e.g., 1cm -> pgfluamathparser.get_tex_sp("1cm")
+--
+function pgfluamathparser.process_tex_dimension(dimension)
+ return 'pgfluamathparser.get_tex_sp("' .. dimension .. '")'
+end
+
+-- Check the type and 'namespace' of a function F.
+--
+-- If F cannot be found as a Lua function or a Lua number in the
+-- namespaces in containted in pgfluamathparser.function_namespaces
+-- then an error results.
+--
+-- if F is a Lua function and isn't followd by () (a requirement of Lua)
+-- then the parentheses are inserted.
+--
+-- e.g., random -> random() (if random is a function in the _G namespace)
+-- pi -> math.pi (if pi is a constant that is only in the math namespace)
+--
+function pgfluamathparser.process_function(function_table)
+ local function_name = function_table[1]
+ local char = function_table[2]
+ if (char == nil) then
+ char = ''
+ end
+ for _, namespace in pairs(pgfluamathparser.function_namespaces) do
+ local function_type = assert(loadstring('return type(' .. namespace .. '.' .. function_name .. ')'))()
+ if function_type == 'function' then
+ if not (char == '(') then
+ char = '()'
+ end
+ return namespace .. '.' .. function_name .. char
+ elseif function_type == 'number' then
+ return namespace .. '.' .. function_name .. char
+ end
+ end
+ pgfluamathparser.error = 'I don\'t know the function or constant \'' .. function_name .. '\''
+end
+
+
+pgfluamathparser.remove_spaces = lpeg.Cs((lpeg.S' \n\t' / '' + 1)^0)
+
+
+function pgfluamathparser.evaluate(expression)
+ assert(loadstring('pgfluamathparser._result=' .. expression))()
+ pgfluamathparser.result = pgfluamathparser._result
+end
+
+function pgfluamathparser.parse(expression)
+ pgfluamathparser.write_to_log("Parsing expression:" .. expression)
+ pgfluamathparser.units_declared = false
+
+ pgfluamathparser.error = nil
+ pgfluamathparser.result = nil
+
+ -- Remove spaces
+ expression = pgfluamathparser.remove_spaces:match(expression)
+
+ parsed_expression =
+ pgfluamathparser.transform_operands:match(expression)
+ pgfluamathparser.write_to_log("Transformed expression:"
+ .. parsed_expression)
+end
+
+function pgfluamathparser.eval(expression)
+ pgfluamathparser.write_to_log("Evaluating expression:" .. expression)
+ pcall(pgfluamathparser.evaluate, expression)
+ pgfluamathparser.write_to_log("Result:" .. pgfluamathparser.result)
+ if pgfluamathparser.result == nil then
+ pgfluamathparser.error = "Sorry, I could not evaluate '" .. expression .. "'"
+ return nil
+ else
+ return pgfluamathparser.result
+ end
+end
+
+pgfluamathparser.trace = true
+
+function pgfluamathparser.write_to_log (s)
+ if pgfluamathparser.trace then
+ texio.write_nl(s)
+ end
+end
+
+return pgfluamathparser
+
+--[[ NEW: 2012/02/21, CJ, work in progress
+-- We need 3 parsers (or 2, 2 and 3 could be merged)
+-- (1) To get the number associated with a (\chardef'ed) box (e.g.
+-- \ht\mybox -> \ht26)
+-- This is part of a TeX ->(\directlua == \edef) -> lua -> (lpeg parser 1)
+-- -> TeX -> (\directlua == \edef)
+-- (2) To transform math and functions operands
+-- (3) To transform units, dimen and count register
+
+-- TODO: strings delimited by "..."
+-- TODO: units. \pgfmathparse{12+1cm}\pgfmathresult and \the\dimexpr 12pt+1cm\relax have the same result. Note: \pgfmathparse{(12+1)cm} won't work in plain pgfmath.
+-- TODO: Parser 3
+
+
+pgfluamath = pgfluamath or {}
+
+pgfluamath.debug = true
+
+local lpeg = require('lpeg')
+local P, R, S, V = lpeg.P, lpeg.R, lpeg.S, lpeg.V
+local C, Cc, Cs = lpeg.C, lpeg.Cc, lpeg.Cs
+local Cf, Cg, Ct = lpeg.Cf, lpeg.Cg, lpeg.Ct
+local match = lpeg.match
+
+local space = S(' \n\t')
+
+local lowercase = R('az')
+local uppercase = R('AZ')
+local alphabetic = lowercase + uppercase
+
+local digit = R('09')
+
+local alphanumeric = alphabetic + digit
+
+local dot = P('.')
+local exponent = S('eE')
+local sign_prefix = S('+-')
+
+local integer = digit^1
+local float = (digit^1 * dot * digit^0) + (digit^0 * dot * digit^1)
+local scientific = (float + integer) * exponent * sign_prefix^-1 * integer
+
+local number = scientific + float + integer
+
+local at = P('@')
+
+local backslash = P('\\')
+
+local box_width = P('\\wd')
+local box_height = P('\\ht')
+local box_depth = P('\\dp')
+local box_dimension = box_width + box_height + box_depth
+
+local tex_cs = backslash * (alphabetic + at)^1
+
+local lparen = P('(')
+local rparen = P(')')
+
+local lbrace = P('{')
+local rbrace = P('}')
+
+local lbracket = P('[')
+local rbracket = P(']')
+
+local thenop = P('?')
+local elseop = P(':')
+
+local orop = P('||')
+local andop = P('&&')
+
+local eqop = P('==')
+local neqop = P('!=')
+
+local greaterop = P('>')
+local lessop = P('<')
+local greatereqop = P('>=')
+local lesseqop = P('<=')
+
+local addop = P('+')
+local subop = P('-')
+
+local mulop = P('*')
+local divop = P('/')
+
+local powop = P('^')
+
+local radop = P('r')
+
+local notop = P('!')
+local negop = P('-')
+
+local comma = P(',')
+
+function pgfluamath.namedbox_to_numberedbox (s)
+ -- Transforms '{\wd|\ht|\dp}\mybox' to '{\wd|\ht|\dp}\number\mybox'
+ local function transform (capture)
+ print('Captured ' .. capture)
+ return '\\number' .. capture
+ end
+ local dimension_of_a_named_box =
+ box_dimension * space^0 * (tex_cs / transform)
+ -- P(1) matches exactly one character
+ -- V(1) is the entry of the grammar with index 1. It defines the initial rule.
+ -- The manual says:
+ -- "If that entry is a string, it is assumed to be the name of the initial rule.
+ -- Otherwise, LPeg assumes that the entry 1 itself is the initial rule."
+ local grammar =
+ P({
+ [1] = (dimension_of_a_named_box + P(1)) * V(1) + P(true)
+ })
+ return print(match(Cs(grammar),s))
+end
+--[[
+namedbox_to_numberedbox('test')
+namedbox_to_numberedbox('\\test')
+namedbox_to_numberedbox('\\wd\\test')
+namedbox_to_numberedbox('\\wd\\test0')
+namedbox_to_numberedbox('\\wd\\test01')
+namedbox_to_numberedbox('\\wd\\test@t 012')
+namedbox_to_numberedbox(' \\wd \\test012')
+namedbox_to_numberedbox('\\wd\\test012\\test \\ht\\zozo0')
+namedbox_to_numberedbox('\\wd0')
+--]]
+
+-- Grammar (from lowest to highest precedence)
+-- Need to adjust to the precedences in plain pgfmath parser
+-- IfThenElse Expression
+local ITE_E = V('ITE_E')
+-- logical OR Expression
+local OR_E = V('OR_E')
+-- logical AND Expression
+local AND_E = V('AND_E')
+-- EQuality Expression
+local EQ_E = V('EQ_E')
+-- Relational EQuality Expression
+local REQ_E = V('REQ_E')
+-- ADDitive Expression
+local ADD_E = V('ADD_E')
+-- MULtiplicative Expression
+local MUL_E = V('MUL_E')
+-- POWer Expression
+local POW_E = V('POW_E')
+-- POSTfix Expression
+local POST_E = V('POST_E')
+-- PREfix Expression
+local PRE_E = V('PRE_E')
+-- ARRAY Expression
+local ARRAY_E = V('ARRAY_E')
+-- Expression
+local E = V('E')
+
+function pgfluamath.transform_math_expr (s, f_patt)
+ if pgfluamath.debug then
+ texio.write_nl('pgfluamath: parsing expression "' .. s ..'"')
+ end
+ -- f_patt extends the grammar dynamically at the time of the call to the
+ -- parser.
+ -- The idea is to have a set of predefined acceptable functions (via e.g.
+ -- \pgfmathdeclarefunction)
+ if not f_patt then
+ -- P(false) is a pattern that always fails
+ -- (neutral element for the + operator on patterns)
+ f_patt = P(false)
+ end
+ local function transform_ITE(a, b, c)
+ if not b then
+ return a
+ else
+ return string.format('pgfluamath.defined_functions.ifthenelse.code(%s,%s,%s)', a, b, c)
+ end
+ end
+ local function transform_binary(a, b, c)
+ if not b then
+ return a
+ else
+ return string.format('pgfluamath.defined_functions.%s.code(%s,%s)', b, a, c)
+ end
+ end
+ local function transform_postunary(a, b)
+ if not b then
+ return a
+ else
+ return string.format('pgfluamath.defined_functions.%s.code(%s)', b, a)
+ end
+ end
+ local function transform_preunary(a, b)
+ if not b then
+ return a
+ else
+ return string.format('pgfluamath.defined_functions.%s.code(%s)', a, b)
+ end
+ end
+ local function transform_array(a, b)
+ -- One exception to the mimmic of plain pgfmath. I do not use the equivalent array function to transform the arrays because I don't know how to handle both cases {1,{2,3}[1],4}[1] and {1,{2,3},4}[1][1] with the parser and the array function.
+ -- So I convert a pgf array to a lua table. One can access one entry of the table like this ({1,2})[1] (note the parenthesis, ie {1,2}[1] won't work).
+ local s
+ if not b then
+ s = '{'
+ else
+ s = '({'
+ end
+ for i = 1,#a do
+ -- We change the index to fit with pgfmath plain convention (index starts at 0 while in lua index starts at 1)
+ s = s .. '[' .. tostring(i-1) .. ']=' .. a[i]
+ if i < #a then
+ s = s .. ','
+ end
+ end
+ if b then
+ s = s .. '})'
+ for i = 1,#b do
+ s = s .. '[' .. b[i] .. ']'
+ end
+ else
+ s = s .. '}'
+ end
+ return s
+ end
+ local grammar =
+ lpeg.P({
+ 'ITE_E',
+ ITE_E = (OR_E * (thenop * OR_E * elseop * OR_E)^-1) / transform_ITE,
+ OR_E = (AND_E * (orop * Cc('orPGF') * AND_E)^-1) / transform_binary,
+ AND_E = (EQ_E * (andop * Cc('andPGF') * EQ_E)^-1) / transform_binary,
+ EQ_E = (REQ_E * ((eqop * Cc('equal') + neqop * Cc('notequal')) * REQ_E)^-1) / transform_binary,
+ REQ_E = (ADD_E * ((lessop * Cc('less') + greaterop * Cc('greater') + lesseqop * Cc('notgreater') + greatereqop * Cc('notless')) * ADD_E)^-1) / transform_binary,
+ ADD_E = Cf(MUL_E * Cg((addop * Cc('add') + subop * Cc('substract')) * MUL_E)^0,transform_binary),
+ MUL_E = Cf(POW_E * Cg((mulop * Cc('multiply') + divop * Cc('divide')) * POW_E)^0,transform_binary),
+ POW_E = Cf(POST_E * Cg(powop * Cc('pow') * POST_E)^0,transform_binary),
+ POST_E = (PRE_E * (radop * Cc('rad'))^-1) / transform_postunary,
+ PRE_E = ((notop * Cc('notPGF') + negop * Cc('neg'))^-1 * E) / transform_preunary,
+ ARRAY_E = (lbrace * Ct(ITE_E * (comma * ITE_E)^0) * rbrace * Ct((lbracket * ITE_E * rbracket)^0)) / transform_array,
+ E = ((integer + float)^-1 * tex_cs^1) + f_patt + C(number) + (lparen * ITE_E * rparen) + ARRAY_E + lbrace * ITE_E * rbrace
+ })
+ return lpeg.match(Cs(grammar),s)
+end
+
+function pgfluamath.ptransform_math_expr(s, f_patt)
+ local st = pgfluamath.transform_math_expr(s, f_patt)
+ if st ~= nil then
+ return texio.write_nl(st)
+ end
+end
+
+pgfluamath.defined_functions = {}
+pgfluamath.defined_functions_pattern = P(false)
+
+function pgfluamath.declare_new_function (name, nargs, code)
+ -- nil is true
+ -- The function name CANNOT be a lua reserved word (so no 'and' nor 'or')
+ if pgfluamath.defined_functions[name] then
+ print('Function ' .. name .. ' is already defined. ' ..
+ 'I overwrite it!')
+ end
+ pgfluamath.defined_functions[name] = {['name'] = name, ['nargs'] = nargs, ['code'] = code}
+
+ -- TODO
+ -- We need a function to dynamically (depending on the number of arguments) define a patten (in order to avoid the long ifcase-type structure).
+ local pattern
+ if nargs == 0 then
+ pattern = P(name) / function (s) return name .. '()' end
+ else if nargs == 1 then
+ pattern = ((P(name) * lparen * Cs(ITE_E) * rparen) / function (s) return 'pgfluamath.defined_functions.' .. name .. '.code(' .. s .. ')' end)
+ else if nargs == 2 then
+ pattern = (P(name) * lparen * Cs(ITE_E) * comma * Cs(ITE_E) * rparen / function (s1,s2) return 'pgfluamath.defined_functions.' .. name .. 'code(' .. s1 .. ',' .. s2 .. ')' end)
+ else if nargs == 3 then
+ pattern = (P(name) * lparen * Cs(ITE_E) * comma * Cs(ITE_E) * comma * Cs(ITE_E) * rparen / function (s1,s2,s3) return 'pgfluamath.defined_functions.' .. name .. 'code(' .. s1 .. ',' .. s2 .. ',' .. s3 .. ')' end)
+ end
+ end
+ end
+ end
+ -- TODO
+ -- This needs to be regenerated every time a new function is added, in conjunction with a sort of the table (see IMPORTANT below)
+ pgfluamath.defined_functions_pattern = pgfluamath.defined_functions_pattern + pattern
+end
+
+-- IMPORTANT: for 'function' with *0* argument, the longest string, the first
+-- ie declaring pi before pit won't work.
+pgfluamath.declare_new_function('pit',0)
+pgfluamath.declare_new_function('pi',0)
+pgfluamath.declare_new_function('exp',1)
+pgfluamath.declare_new_function('toto',1)
+pgfluamath.declare_new_function('gauss',2)
+
+pgfluamath.ptransform_math_expr('exp(exp(1+1))',pgfluamath.defined_functions_pattern)
+
+pgfluamath.ptransform_math_expr('1?(2?3:4^5):gauss(6+toto(7),8+9>10?11:12))',pgfluamath.defined_functions_pattern)
+
+pgfluamath.ptransform_math_expr('!(1!=-2)>3?(4+5*6+7?8||9&&10:11):12^13r||14')
+pgfluamath.ptransform_math_expr('-1^2\\test\\toto^3')
+pgfluamath.ptransform_math_expr('{1,{2+3,4}[1],5}[2]+6')
+pgfluamath.ptransform_math_expr('{1,{2+3,4},5}[1][1]')
+pgfluamath.ptransform_math_expr('{1,{2,3},4}[1][1]')
+pgfluamath.ptransform_math_expr('{1,{2,3}[1],4}[1]')
+
+--Loadstring: If it succeeds in converting the string to a *function*, it returns that function; otherwise, it returns nil and an error message.
+toto = loadstring('texio.write_nl(' .. pgfluamath.transform_math_expr('{1,{2,3},4}[1][1]') .. ')')
+toto()
+
+-- IMPORTANT NOTE!!
+-- local function add (a,b) will fail within loadstring. Needs to be global. loadstring opens a new chunk that does not know the local variables of other chunks.
+
+--toto = loadstring('texio.write_nl(' .. pgfluamath.transform_math_expr('{1,{2,3E-1+7}[1],4}[1]') .. ')')
+--toto()
+
+return pgfluamath