% 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: