From 3de6683607c3042def19b77ca8a338814d0a1575 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 8 May 2019 21:09:31 +0000 Subject: pgf revert again to r49607, after mistaken update git-svn-id: svn://tug.org/texlive/trunk@51047 c570f23f-e606-0410-a88d-b1316a301751 --- .../libraries/luamath/pgf/luamath/functions.lua | 616 ++++++++++----------- .../pgf/libraries/luamath/pgf/luamath/parser.lua | 475 ++++++++-------- .../libraries/luamath/pgflibraryluamath.code.tex | 10 +- 3 files changed, 551 insertions(+), 550 deletions(-) (limited to 'Master/texmf-dist/tex/generic/pgf/libraries/luamath') diff --git a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/functions.lua b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/functions.lua index 367d6ae298f..3eecaf99c0a 100644 --- a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/functions.lua +++ b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/functions.lua @@ -14,24 +14,24 @@ local pgfluamathfunctions = pgfluamathfunctions or {} -- Maps function names to their function. -- --- Note that this allows to register functions which are not in pgfluamathfunctions. +-- Note that this allows to register functions which are not in pgfluamathfunctions. -- -- Note that the string keys are not necessarily the same as the function --- names. In particular, the math expression "not(1,1)" will execute notPGF(1,1) +-- names. In particular, the math expression "not(1,1)" will execute notPGF(1,1) -- -- Note that each function which is added to pgfluamathfunctions will _automatically_ be inserted into this map, see __newindex. -- (I fear it will not be erased directly...) pgfluamathfunctions.stringToFunctionMap = {} local newFunctionAllocatedCallback = function(table,key,value) - local keyName = tostring(key):gsub("PGF","") - if not value then - stringToFunctionMap[keyName] = nil - elseif type(value) == 'function' then - -- remember it, and strip PGF suffix (i.e. remember 'not' instead of 'notPGF') - pgfluamathfunctions.stringToFunctionMap[keyName] = value - end - rawset(table,key,value) + local keyName = tostring(key):gsub("PGF","") + if not value then + stringToFunctionMap[keyName] = nil + elseif type(value) == 'function' then + -- remember it, and strip PGF suffix (i.e. remember 'not' instead of 'notPGF') + pgfluamathfunctions.stringToFunctionMap[keyName] = value + end + rawset(table,key,value) end setmetatable(pgfluamathfunctions, { __newindex = newFunctionAllocatedCallback }) @@ -56,16 +56,16 @@ pgfluamathfunctions.stringToFunctionMap["TrigFormat"] = nil -- choice is one of the valid choices in TrigFormat. function pgfluamathfunctions.setTrigFormat(choice) - if choice == 'deg' then - trigFormatToRadians = mathrad - radiansToTrigFormat = mathdeg - elseif choice == 'rad' then - local identity = function(x) return x end - trigFormatToRadians = identity - radiansToTrigFormat = identity - else - error("The argument '" .. tostring(choice) .. "' is no valid choice for setTrigFormat.") - end + if choice == 'deg' then + trigFormatToRadians = mathrad + radiansToTrigFormat = mathdeg + elseif choice == 'rad' then + local identity = function(x) return x end + trigFormatToRadians = identity + radiansToTrigFormat = identity + else + error("The argument '" .. tostring(choice) .. "' is no valid choice for setTrigFormat.") + end end pgfluamathfunctions.stringToFunctionMap["setTrigFormat"] = nil @@ -75,422 +75,422 @@ pgfluamathfunctions.stringToFunctionMap["setRandomSeed"] = nil ------------------------------------------- function pgfluamathfunctions.add(x,y) - return x+y + return x+y end function pgfluamathfunctions.subtract(x,y) - return x-y + return x-y end function pgfluamathfunctions.neg(x) - return -x + return -x end function pgfluamathfunctions.multiply(x,y) - return x*y + return x*y end function pgfluamathfunctions.veclen(x,y) - return mathsqrt(x*x+y*y) + return mathsqrt(x*x+y*y) end function pgfluamathfunctions.divide(x,y) - return x/y + return x/y end function pgfluamathfunctions.div(x,y) - return mathfloor(x/y) + return mathfloor(x/y) end function pgfluamathfunctions.pow(x,y) - -- do not use math.pow -- it is deprecated as of LUA 5.3 - return x^y + -- do not use math.pow -- it is deprecated as of LUA 5.3 + return x^y end function pgfluamathfunctions.factorial(x) -- TODO: x must be an integer - if x == 0 then - return 1 - else - return x * pgfluamathfunctions.factorial(x-1) - end + if x == 0 then + return 1 + else + return x * pgfluamathfunctions.factorial(x-1) + end end function pgfluamathfunctions.ifthenelse(x,y,z) - if x~= 0 then - return y - else - return z - end + 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 + 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 + 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 + if x < y then + return 1 + else + return 0 + end end function pgfluamathfunctions.min(x,y) - return mathmin(x,y) + return mathmin(x,y) end function pgfluamathfunctions.max(x,y) - return mathmax(x,y) + return mathmax(x,y) end function pgfluamathfunctions.notequal(x,y) - if x ~= y then - return 1 - else - return 0 - end + 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 + 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 + 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 + 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 + 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 + if x == 0 then + return 1 + else + return 0 + end end function pgfluamathfunctions.pi() - return mathpi + return mathpi end function pgfluamathfunctions.e() - return mathexp(1) + return mathexp(1) end function pgfluamathfunctions.abs(x) - return mathabs(x) + return mathabs(x) end function pgfluamathfunctions.floor(x) - return mathfloor(x) + return mathfloor(x) end function pgfluamathfunctions.ceil(x) - return mathceil(x) + return mathceil(x) end function pgfluamathfunctions.exp(x) - return mathexp(x) + return mathexp(x) end function pgfluamathfunctions.ln(x) - return mathlog(x) + return mathlog(x) end local logOf10 = mathlog(10) function pgfluamathfunctions.log10(x) - return mathlog(x) / logOf10 + return mathlog(x) / logOf10 end local logOf2 = mathlog(2) function pgfluamathfunctions.log2(x) - return mathlog(x) / logOf2 + return mathlog(x) / logOf2 end function pgfluamathfunctions.sqrt(x) - return mathsqrt(x) + return mathsqrt(x) end function pgfluamathfunctions.sign(x) - if x < 0 then - return -1.0 - elseif x == 0 then - return 0.0 - else - return 1.0 - end + if x < 0 then + return -1.0 + elseif x == 0 then + return 0.0 + else + return 1.0 + end end function pgfluamathfunctions.real(x) - -- "ensure that x contains a decimal point" is kind of a no-op here, isn't it!? - return x + -- "ensure that x contains a decimal point" is kind of a no-op here, isn't it!? + return x end function pgfluamathfunctions.rnd() - return mathrandom() + return mathrandom() end function pgfluamathfunctions.rand() - return -1 + mathrandom() *2 + return -1 + mathrandom() *2 end function pgfluamathfunctions.random(x,y) - if x == nil and y == nil then - return mathrandom() - elseif y == nil then - return mathrandom(x) - else - return mathrandom(x,y) - end + if x == nil and y == nil then + return mathrandom() + elseif y == nil then + return mathrandom(x) + else + return mathrandom(x,y) + end end function pgfluamathfunctions.deg(x) - return mathdeg(x) + return mathdeg(x) end function pgfluamathfunctions.rad(x) - return mathrad(x) + return mathrad(x) end function pgfluamathfunctions.round(x) - if x<0 then - return -mathfloor(mathabs(x)+0.5) - else - return mathfloor(x + 0.5) - end + if x<0 then + return -mathfloor(mathabs(x)+0.5) + else + return mathfloor(x + 0.5) + end end function pgfluamathfunctions.gcd(a, b) - if b == 0 then - return a - else - return pgfluamathfunctions.gcd(b, a%b) - end + if b == 0 then + return a + else + return pgfluamathfunctions.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 pgfluamathfunctions.gcd(a,i) ~= 1 then - ifisprime = false + 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 pgfluamathfunctions.gcd(a,i) ~= 1 then + ifisprime = false + end + i = i + 1 end - i = i + 1 - end - end - if ifisprime then - return 1 - else - return 0 - 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) + -- (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 + local t = {} + for i in s:gmatch('%b{}') do + table.insert(t, tonumber(i:sub(2, -2))) + end + return t end function pgfluamathfunctions.mathtrue() - return 1.0 + return 1.0 end pgfluamathfunctions.stringToFunctionMap["true"] = pgfluamathfunctions.mathtrue function pgfluamathfunctions.mathfalse() - return 0.0 + return 0.0 end pgfluamathfunctions.stringToFunctionMap["false"] = pgfluamathfunctions.mathfalse function pgfluamathfunctions.frac(a) - -- should be positive, apparently - return mathabs(a - pgfluamathfunctions.int(a)) + -- should be positive, apparently + return mathabs(a - pgfluamathfunctions.int(a)) end function pgfluamathfunctions.int(a) - if a < 0 then - return -mathfloor(mathabs(a)) - else - return mathfloor(a) - end + if a < 0 then + return -mathfloor(mathabs(a)) + else + return mathfloor(a) + end end function pgfluamathfunctions.iseven(a) - if (a % 2) == 0 then - return 1.0 - else - return 0.0 - end + if (a % 2) == 0 then + return 1.0 + else + return 0.0 + end end function pgfluamathfunctions.isodd(a) - if (a % 2) == 0 then - return 0.0 - else - return 1.0 - end + if (a % 2) == 0 then + return 0.0 + else + return 1.0 + end end function pgfluamathfunctions.mod(x,y) - if x/y < 0 then - return -(mathabs(x)%mathabs(y)) - else - return mathabs(x)%mathabs(y) - end + if x/y < 0 then + return -(mathabs(x)%mathabs(y)) + else + return mathabs(x)%mathabs(y) + end end function pgfluamathfunctions.Mod(x,y) - local tmp = pgfluamathfunctions.mod(x,y) - if tmp < 0 then - tmp = tmp + y - end - return tmp + local tmp = pgfluamathfunctions.mod(x,y) + if tmp < 0 then + tmp = tmp + y + end + return tmp end function pgfluamathfunctions.Sin(x) - return mathsin(trigFormatToRadians(x)) + return mathsin(trigFormatToRadians(x)) end pgfluamathfunctions.sin=pgfluamathfunctions.Sin function pgfluamathfunctions.cosh(x) - -- math.cosh is deprecated as of LUA 5.3 . reimplement it: - return 0.5* (mathexp(x) + mathexp(-x)) + -- math.cosh is deprecated as of LUA 5.3 . reimplement it: + return 0.5* (mathexp(x) + mathexp(-x)) end function pgfluamathfunctions.sinh(x) - -- math.sinh is deprecated as of LUA 5.3 . reimplement it: - return 0.5* (mathexp(x) - mathexp(-x)) + -- math.sinh is deprecated as of LUA 5.3 . reimplement it: + return 0.5* (mathexp(x) - mathexp(-x)) end local sinh = pgfluamathfunctions.sinh local cosh = pgfluamathfunctions.cosh function pgfluamathfunctions.tanh(x) - -- math.tanh is deprecated as of LUA 5.3 . reimplement it: - return sinh(x)/cosh(x) + -- math.tanh is deprecated as of LUA 5.3 . reimplement it: + return sinh(x)/cosh(x) end function pgfluamathfunctions.Cos(x) - return mathcos(trigFormatToRadians(x)) + return mathcos(trigFormatToRadians(x)) end pgfluamathfunctions.cos=pgfluamathfunctions.Cos function pgfluamathfunctions.Tan(x) - return mathtan(trigFormatToRadians(x)) + return mathtan(trigFormatToRadians(x)) end pgfluamathfunctions.tan=pgfluamathfunctions.Tan function pgfluamathfunctions.aSin(x) - return radiansToTrigFormat(mathasin(x)) + return radiansToTrigFormat(mathasin(x)) end pgfluamathfunctions.asin=pgfluamathfunctions.aSin function pgfluamathfunctions.aCos(x) - return radiansToTrigFormat(mathacos(x)) + return radiansToTrigFormat(mathacos(x)) end pgfluamathfunctions.acos=pgfluamathfunctions.aCos function pgfluamathfunctions.aTan(x) - return radiansToTrigFormat(mathatan(x)) + return radiansToTrigFormat(mathatan(x)) end pgfluamathfunctions.atan=pgfluamathfunctions.aTan local mathatan2 if math.atan2 == nil then - -- math.atan2 has been deprecated since LUA 5.3 - mathatan2 = function (y,x) return mathatan(y,x) end + -- math.atan2 has been deprecated since LUA 5.3 + mathatan2 = function (y,x) return mathatan(y,x) end else - mathatan2 = math.atan2 + mathatan2 = math.atan2 end function pgfluamathfunctions.aTan2(y,x) - return radiansToTrigFormat(mathatan2(y,x)) + return radiansToTrigFormat(mathatan2(y,x)) end pgfluamathfunctions.atan2=pgfluamathfunctions.aTan2 pgfluamathfunctions.atantwo=pgfluamathfunctions.aTan2 function pgfluamathfunctions.cot(x) - return pgfluamathfunctions.cos(x) / pgfluamathfunctions.sin(x) + return pgfluamathfunctions.cos(x) / pgfluamathfunctions.sin(x) end function pgfluamathfunctions.sec(x) - return 1 / pgfluamathfunctions.cos(x) + return 1 / pgfluamathfunctions.cos(x) end function pgfluamathfunctions.cosec(x) - return 1 / pgfluamathfunctions.sin(x) + return 1 / pgfluamathfunctions.sin(x) end function pgfluamathfunctions.pointnormalised (pgfx, pgfy) - local pgfx_normalised, pgfy_normalised - if pgfx == 0. and pgfy == 0. then - -- Original 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 + 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 local isnan = function(x) - return x ~= x + return x ~= x end pgfluamathfunctions.isnan = isnan @@ -509,44 +509,44 @@ local stringsub = string.sub -- like tonumber(x), but it also accepts nan, inf, infty, and the TeX FPU format function pgfluamathfunctions.tonumber(x) - if type(x) == 'number' then return x end - if not x then return x end - - local len = stringlen(x) - local result = globaltonumber(x) - if not result then - if len >2 and stringsub(x,2,2) == 'Y' and stringsub(x,len,len) == ']' then - -- Ah - some TeX FPU input of the form 1Y1.0e3] . OK. transform it - local flag = stringsub(x,1,1) - if flag == '0' then - -- ah, 0.0 - result = 0.0 - elseif flag == '1' then - result = globaltonumber(stringsub(x,3, len-1)) - elseif flag == '2' then - result = globaltonumber("-" .. stringsub(x,3, len-1)) - elseif flag == '3' then - result = nan - elseif flag == '4' then - result = infty - elseif flag == '5' then - result = -infty - end - else - local lower = x:lower() - if lower == 'nan' then - result = nan - elseif lower == "-nan" then - result = nan - elseif lower == 'inf' or lower == 'infty' then - result = infty - elseif lower == '-inf' or lower == '-infty' then - result = -infty - end - end - end - - return result + if type(x) == 'number' then return x end + if not x then return x end + + local len = stringlen(x) + local result = globaltonumber(x) + if not result then + if len >2 and stringsub(x,2,2) == 'Y' and stringsub(x,len,len) == ']' then + -- Ah - some TeX FPU input of the form 1Y1.0e3] . OK. transform it + local flag = stringsub(x,1,1) + if flag == '0' then + -- ah, 0.0 + result = 0.0 + elseif flag == '1' then + result = globaltonumber(stringsub(x,3, len-1)) + elseif flag == '2' then + result = globaltonumber("-" .. stringsub(x,3, len-1)) + elseif flag == '3' then + result = nan + elseif flag == '4' then + result = infty + elseif flag == '5' then + result = -infty + end + else + local lower = x:lower() + if lower == 'nan' then + result = nan + elseif lower == "-nan" then + result = nan + elseif lower == 'inf' or lower == 'infty' then + result = infty + elseif lower == '-inf' or lower == '-infty' then + result = -infty + end + end + end + + return result end local stringlen = string.len @@ -558,69 +558,69 @@ local stringbyte = string.byte local NULL_CHAR = string.byte("0",1) local function discardTrailingZeros(x) - local result = x - -- printf is too stupid: I would like to have - -- 1. a fast method - -- 2. a reliable method - -- 3. full precision of x - -- 4. a fixed point representation - -- the 'f' modifier has trailing zeros (stupid!) - -- the 'g' modified can switch to scientific notation (no-go!) - local periodOff = stringfind(result, '.',1,true) - if periodOff ~= nil then - -- strip trailing zeros - local chars = { stringbyte(result,1,#result) }; - local lastNonZero = #chars - for i = #chars, periodOff, -1 do - if chars[i] ~= NULL_CHAR then lastNonZero=i; break; end - end - if lastNonZero ~= #chars then - -- Ah: we had at least one trailing zero. - -- discard all but the last. - lastNonZero = mathmax(periodOff+1,lastNonZero) - end - result = stringsub(result, 1, lastNonZero) - end - return result; + local result = x + -- printf is too stupid: I would like to have + -- 1. a fast method + -- 2. a reliable method + -- 3. full precision of x + -- 4. a fixed point representation + -- the 'f' modifier has trailing zeros (stupid!) + -- the 'g' modified can switch to scientific notation (no-go!) + local periodOff = stringfind(result, '.',1,true) + if periodOff ~= nil then + -- strip trailing zeros + local chars = { stringbyte(result,1,#result) }; + local lastNonZero = #chars + for i = #chars, periodOff, -1 do + if chars[i] ~= NULL_CHAR then lastNonZero=i; break; end + end + if lastNonZero ~= #chars then + -- Ah: we had at least one trailing zero. + -- discard all but the last. + lastNonZero = mathmax(periodOff+1,lastNonZero) + end + result = stringsub(result, 1, lastNonZero) + end + return result; end local function discardTrailingZerosFromMantissa(x) - local mantissaStart = stringfind(x, "e") + local mantissaStart = stringfind(x, "e") - local mantissa = stringsub(x,1,mantissaStart-1) - local exponent = stringsub(x,mantissaStart) + local mantissa = stringsub(x,1,mantissaStart-1) + local exponent = stringsub(x,mantissaStart) - return discardTrailingZeros(mantissa) .. exponent + return discardTrailingZeros(mantissa) .. exponent end -- a helper function which has no catcode issues when communicating with TeX: function pgfluamathfunctions.tostringfixed(x) - if x == nil then - return "" - end + if x == nil then + return "" + end - return discardTrailingZeros(stringformat("%f", x)) + return discardTrailingZeros(stringformat("%f", x)) end -- converts an input number to a string which is accepted by the TeX FPU function pgfluamathfunctions.toTeXstring(x) - local result = "" - if x ~= nil then - if x == infty then result = "4Y0.0e0]" - elseif x == -infty then result = "5Y0.0e0]" - elseif isnan(x) then result = "3Y0.0e0]" - elseif x == 0 then result = "0Y0.0e0]" - else - result = discardTrailingZerosFromMantissa(stringformat("%.10e", x)) - if x > 0 then - result = "1Y" .. result .. "]" - else - result = "2Y" .. stringsub(result,2) .. "]" - end + local result = "" + if x ~= nil then + if x == infty then result = "4Y0.0e0]" + elseif x == -infty then result = "5Y0.0e0]" + elseif isnan(x) then result = "3Y0.0e0]" + elseif x == 0 then result = "0Y0.0e0]" + else + result = discardTrailingZerosFromMantissa(stringformat("%.10e", x)) + if x > 0 then + result = "1Y" .. result .. "]" + else + result = "2Y" .. stringsub(result,2) .. "]" + end + end end - end - return result + return result end return pgfluamathfunctions diff --git a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/parser.lua b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/parser.lua index 42b690e6cf8..30eff2e6992 100644 --- a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/parser.lua +++ b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgf/luamath/parser.lua @@ -8,7 +8,7 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more details. -- --- $Id$ +-- $Id$ -- -- usage: -- @@ -32,22 +32,22 @@ local V = lpeg.V local match = lpeg.match local space_pattern = S(" \n\r\t")^0 -local tex_unit = - P('pt') + P('mm') + P('cm') + P('in') + - -- while valid units, the font-depending ones need special attention... move them to the TeX side. For now. - -- P('ex') + P('em') + - P('bp') + P('pc') + +local tex_unit = + P('pt') + P('mm') + P('cm') + P('in') + + -- while valid units, the font-depending ones need special attention... move them to the TeX side. For now. + -- P('ex') + P('em') + + P('bp') + P('pc') + P('dd') + P('cc') + P('sp'); local one_digit_pattern = R("09") local positive_integer_pattern = one_digit_pattern^1 -- FIXME : it might be a better idea to remove '-' from all number_patterns! Instead, rely on the prefix operator 'neg' to implement negative numbers. -- Is that wise? It is certainly less efficient... -local integer_pattern = S("+-")^-1 * positive_integer_pattern +local integer_pattern = S("+-")^-1 * positive_integer_pattern -- Valid positive decimals are |xxx.xxx|, |.xxx| and |xxx.| -local positive_integer_or_decimal_pattern = positive_integer_pattern * ( P(".") * one_digit_pattern^0)^-1 + - (P(".") * one_digit_pattern^1) -local integer_or_decimal_pattern = S("+-")^-1 * positive_integer_or_decimal_pattern +local positive_integer_or_decimal_pattern = positive_integer_pattern * ( P(".") * one_digit_pattern^0)^-1 + + (P(".") * one_digit_pattern^1) +local integer_or_decimal_pattern = S("+-")^-1 * positive_integer_or_decimal_pattern local fpu_pattern = R"05" * P"Y" * positive_integer_or_decimal_pattern * P"e" * S("+-")^-1 * R("09")^1 * P"]" local unbounded_pattern = P"inf" + P"INF" + P"nan" + P"NaN" + P"Inf" local number_pattern = C(unbounded_pattern + fpu_pattern + integer_or_decimal_pattern * (S"eE" * integer_pattern + C(tex_unit))^-1) @@ -57,7 +57,7 @@ local underscore_pattern = P("_") local letter_pattern = R("az","AZ") local alphanum__pattern = letter_pattern + one_digit_pattern + underscore_pattern -local identifier_pattern = letter_pattern^1 * alphanum__pattern^0 +local identifier_pattern = letter_pattern^1 * alphanum__pattern^0 local openparen_pattern = P("(") * space_pattern local closeparen_pattern = P(")") @@ -94,56 +94,56 @@ local function eval (v1, op, v2) elseif (op == "*") then return v1 * v2 elseif (op == "/") then return v1 / v2 else - error("This function must not be invoked for operator "..op) + error("This function must not be invoked for operator "..op) end end local pgfStringToFunctionMap = pgfluamathfunctions.stringToFunctionMap local function function_eval(name, ... ) - local f = pgfStringToFunctionMap[name] - if not f then - error("Function '" .. name .. "' is undefined (did not find pgfluamathfunctions."..name .." (looked into pgfluamathfunctions.stringToFunctionMap))") - end - -- FIXME: validate signature - return f(...) + local f = pgfStringToFunctionMap[name] + if not f then + error("Function '" .. name .. "' is undefined (did not find pgfluamathfunctions."..name .." (looked into pgfluamathfunctions.stringToFunctionMap))") + end + -- FIXME: validate signature + return f(...) end -local func = - (C(identifier_pattern) * space_pattern * openparen_pattern * Exp * (comma_pattern * Exp)^0 * closeparen_pattern) / function_eval; +local func = + (C(identifier_pattern) * space_pattern * openparen_pattern * Exp * (comma_pattern * Exp)^0 * closeparen_pattern) / function_eval; local functionWithoutArg = identifier_pattern / function_eval -- this is what can occur as exponent after '^'. -- I have the impression that the priorities could be implemented in a better way than this... but it seems to work. -local pow_exponent = - -- allows 2^-4, 2^1e4, 2^2 - -- FIXME : why not 2^1e2 ? - Cg(C(integer_or_decimal_pattern) - -- 2^pi, 2^multiply(2,2) - + Cg(func+functionWithoutArg) - -- 2^(2+2) - + openparen_pattern * Exp * closeparen_pattern ) +local pow_exponent = + -- allows 2^-4, 2^1e4, 2^2 + -- FIXME : why not 2^1e2 ? + Cg(C(integer_or_decimal_pattern) + -- 2^pi, 2^multiply(2,2) + + Cg(func+functionWithoutArg) + -- 2^(2+2) + + openparen_pattern * Exp * closeparen_pattern ) local function prefix_eval(op, x) - if op == "-" then - return pgfluamathfunctions.neg(x) - elseif op == "!" then - return pgfluamathfunctions.notPGF(x) - else - error("This function must not be invoked for operator "..op) - end + if op == "-" then + return pgfluamathfunctions.neg(x) + elseif op == "!" then + return pgfluamathfunctions.notPGF(x) + else + error("This function must not be invoked for operator "..op) + end end local prefix_operator = C( S"-!" ) local prefix_operator_pattern = (prefix_operator * space_pattern * Cg(Prefix) ) / prefix_eval --- apparently, we need to distinguish between ! and != : +-- apparently, we need to distinghuish between ! and != : local postfix_operator = C( S"r!" - P"!=" ) + C(P"^") * space_pattern * pow_exponent pgfluamathfunctions.functionMustBeEvaluatedInTeX = function() - error("The function in this context cannot be evaluated by LUA because it depends on TeX macros.") + error("The function in this context cannot be evaluated by LUA because it depends on TeX macros.") end local ternary_eval = pgfluamathfunctions.ifthenelse @@ -156,117 +156,118 @@ local pow_eval = pgfluamathfunctions.pow -- @param op either nil or the postfix operator -- @param arg either nil or the (mandatory) argument for 'op' local function postfix_eval(prefix, op, arg) - local result - if op == nil then - result = prefix - elseif op == "r" then - if arg then error("parser setup error: expected nil argument") end - result = deg(prefix) - elseif op == "!" then - if arg then error("parser setup error: expected nil argument") end - result = factorial_eval(prefix) - elseif op == "^" then - if not arg then error("parser setup error: ^ with its argument") end - result = pow_eval(prefix, arg) - else - error("Parser setup error: " .. tostring(op) .. " unexpected in this context") - end - return result + local result + if op == nil then + result = prefix + elseif op == "r" then + if arg then error("parser setup error: expected nil argument") end + result = deg(prefix) + elseif op == "!" then + if arg then error("parser setup error: expected nil argument") end + result = factorial_eval(prefix) + elseif op == "^" then + if not arg then error("parser setup error: ^ with its argument") end + result = pow_eval(prefix, arg) + else + error("Parser setup error: " .. tostring(op) .. " unexpected in this context") + end + return result end local function equality_eval(v1, op, v2) - local fct - if (op == "==") then fct = pgfluamathfunctions.equal - elseif (op == "!=") then fct = pgfluamathfunctions.notequal - else - error("This function must not be invoked for operator "..op) - end - return fct(v1,v2) + local fct + if (op == "==") then fct = pgfluamathfunctions.equal + elseif (op == "!=") then fct = pgfluamathfunctions.notequal + else + error("This function must not be invoked for operator "..op) + end + return fct(v1,v2) end local function relational_eval(v1, op, v2) - local fct - if (op == "<") then fct = pgfluamathfunctions.less - elseif (op == ">") then fct = pgfluamathfunctions.greater - elseif (op == ">=") then fct = pgfluamathfunctions.notless - elseif (op == "<=") then fct = pgfluamathfunctions.notgreater - else - error("This function must not be invoked for operator "..op) - end - return fct(v1,v2) + local fct + if (op == "<") then fct = pgfluamathfunctions.less + elseif (op == ">") then fct = pgfluamathfunctions.greater + elseif (op == ">=") then fct = pgfluamathfunctions.notless + elseif (op == "<=") then fct = pgfluamathfunctions.notgreater + else + error("This function must not be invoked for operator "..op) + end + return fct(v1,v2) end -- @return either the box property or nil -- @param cs "wd", "ht", or "dp" -- @param intSuffix some integer local function get_tex_box(cs, intSuffix) - -- assume get_tex_box is only called when a dimension is required. - local result - pgfluamathparser.units_declared = true - local box =tex.box[tonumber(intSuffix)] - if not box then error("There is no box " .. intSuffix) end - if cs == "wd" then - result = box.width / 65536 - elseif cs == "ht" then - result = box.height / 65536 - elseif cs == "dp" then - result = box.depth / 65536 - else - result = nil - end - return result + -- assume get_tex_box is only called when a dimension is required. + local result + pgfluamathparser.units_declared = true + local box =tex.box[tonumber(intSuffix)] + if not box then error("There is no box " .. intSuffix) end + if cs == "wd" then + result = box.width / 65536 + elseif cs == "ht" then + result = box.height / 65536 + elseif cs == "dp" then + result = box.depth / 65536 + else + result = nil + end + return result end local function controlsequence_eval(cs, intSuffix) - local result - if intSuffix and #intSuffix >0 then - if cs == "count" then - result= pgfluamathparser.get_tex_count(intSuffix) - elseif cs == "dimen" then - result= pgfluamathparser.get_tex_dimen(intSuffix) - else - result = get_tex_box(cs,intSuffix) - if not result then - -- this can happen - we cannot expand \chardef'ed boxes here. - -- this will be done by the TeX part - error('I do not know/support the TeX register "\\' .. cs .. '"') - end - end - else - result = pgfluamathparser.get_tex_register(cs) - end - return result + local result + if intSuffix and #intSuffix >0 then + if cs == "count" then + result= pgfluamathparser.get_tex_count(intSuffix) + elseif cs == "dimen" then + result= pgfluamathparser.get_tex_dimen(intSuffix) + else + result = get_tex_box(cs,intSuffix) + if not result then + -- this can happen - we cannot expand \chardef'ed boxes here. + -- this will be done by the TeX part + error('I do not know/support the TeX register "\\' .. cs .. '"') + end + end + else + result = pgfluamathparser.get_tex_register(cs) + end + return result end pgfluamathparser.units_declared = false 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 - error('I do not know the TeX register "' .. register .. '"') - return nil - end + -- 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 + 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)] + -- 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 + -- 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 + -- dimension should be a string + pgfluamathparser.units_declared = true + return tex.sp(dimension) / 65536 end @@ -281,66 +282,66 @@ local LogicalAnd = V"LogicalAnd" local pgftonumber = pgfluamathfunctions.tonumber local tonumber_withunit = pgfluamathparser.get_tex_sp local function number_optional_units_eval(x, unit) - if not unit then - return pgftonumber(x) - else - return tonumber_withunit(x) - end + if not unit then + return pgftonumber(x) + else + return tonumber_withunit(x) + end end -- @param scale the number. -- @param controlsequence either nil in which case just the number must be returned or a control sequence -- @see controlsequence_eval local function scaled_controlsequence_eval(scale, controlsequence, intSuffix) - if controlsequence==nil then - return scale - else - return scale * controlsequence_eval(controlsequence, intSuffix) - end + if controlsequence==nil then + return scale + else + return scale * controlsequence_eval(controlsequence, intSuffix) + end end -- Grammar -- --- for me: +-- for me: -- - use '/' to evaluate all expressions which contain a _constant_ number of captures. -- - use Cf to evaluate expressions which contain a _dynamic_ number of captures -- -- see unittest_luamathparser.tex for tons of examples local G = P{ "initialRule", - initialRule = space_pattern* Exp * -1; - -- ternary operator (or chained ternary operators): - -- FIXME : is this chaining a good idea!? - Exp = Cf( LogicalOr * Cg(P"?" * space_pattern * LogicalOr * P":" *space_pattern * LogicalOr )^0, ternary_eval) ; - LogicalOr = Cf(LogicalAnd * (P"||" * space_pattern * LogicalAnd)^0, pgfluamathfunctions.orPGF); - LogicalAnd = Cf(Equality * (P"&&" * space_pattern * Equality)^0, pgfluamathfunctions.andPGF); - Equality = Cf(Relational * Cg(EqualityOp * Relational)^0, equality_eval); - Relational = Cf(Summand * Cg(RelationalOp * Summand)^0, relational_eval); - Summand = Cf(Term * Cg(TermOp * Term)^0, eval) ; - Term = Cf(Prefix * Cg(FactorOp * Prefix)^0, eval); - Prefix = prefix_operator_pattern + Postfix; - -- this calls 'postfix_eval' with nil arguments if it is no postfix operation.. but that does not hurt (right?) - Postfix = Factor * (postfix_operator * space_pattern)^-1 / postfix_eval; - Factor = - ( - number_pattern / number_optional_units_eval * - -- this construction will evaluate number_pattern with 'number_optional_units_eval' FIRST. - -- also accept '0.5 \pgf@x' here: - space_pattern *controlsequence_pattern^-1 / scaled_controlsequence_eval - + func - + functionWithoutArg - + openparen_pattern * Exp * closeparen_pattern - + controlsequence_pattern / controlsequence_eval - ) *space_pattern - ; + initialRule = space_pattern* Exp * -1; + -- ternary operator (or chained ternary operators): + -- FIXME : is this chaining a good idea!? + Exp = Cf( LogicalOr * Cg(P"?" * space_pattern * LogicalOr * P":" *space_pattern * LogicalOr )^0, ternary_eval) ; + LogicalOr = Cf(LogicalAnd * (P"||" * space_pattern * LogicalAnd)^0, pgfluamathfunctions.orPGF); + LogicalAnd = Cf(Equality * (P"&&" * space_pattern * Equality)^0, pgfluamathfunctions.andPGF); + Equality = Cf(Relational * Cg(EqualityOp * Relational)^0, equality_eval); + Relational = Cf(Summand * Cg(RelationalOp * Summand)^0, relational_eval); + Summand = Cf(Term * Cg(TermOp * Term)^0, eval) ; + Term = Cf(Prefix * Cg(FactorOp * Prefix)^0, eval); + Prefix = prefix_operator_pattern + Postfix; + -- this calls 'postfix_eval' with nil arguments if it is no postfix operation.. but that does not hurt (right?) + Postfix = Factor * (postfix_operator * space_pattern)^-1 / postfix_eval; + Factor = + ( + number_pattern / number_optional_units_eval * + -- this construction will evaluate number_pattern with 'number_optional_units_eval' FIRST. + -- also accept '0.5 \pgf@x' here: + space_pattern *controlsequence_pattern^-1 / scaled_controlsequence_eval + + func + + functionWithoutArg + + openparen_pattern * Exp * closeparen_pattern + + controlsequence_pattern / controlsequence_eval + ) *space_pattern + ; } -- does not reset units_declared. local function pgfmathparseinternal(str) - local result = match(G,str) - if result == nil then - error("The string '" .. str .. "' is no valid PGF math expression. Please check for syntax errors.") - end - return result + local result = match(G,str) + if result == nil then + error("The string '" .. str .. "' is no valid PGF math expression. Please check for syntax errors.") + end + return result end @@ -348,12 +349,12 @@ end -- -- @param str a string like "1+1" which is accepted by the PGF math language -- @return the result of the expression. --- +-- -- Throws an error if the string is no valid expression. function pgfluamathparser.pgfmathparse(str) - pgfluamathparser.units_declared = false + pgfluamathparser.units_declared = false - return pgfmathparseinternal(str) + return pgfmathparseinternal(str) end local pgfmathparse = pgfluamathparser.pgfmathparse @@ -378,7 +379,7 @@ local stackOfLocalFunctions = {} -- -- ATTENTION: local functions behave DIFFERENTLY in LUA! -- In LUA, local variables are not expanded whereas TeX expands them. --- The difference is +-- The difference is -- -- declare function={mu1(\x,\i)=\x^\i;} -- \pgfmathparse{mu1(-5,2)} --> -25 @@ -392,53 +393,53 @@ local stackOfLocalFunctions = {} -- BUT: that "simulated expansion" broke the second case because LUA will evaluate "x" and hand -5 to the local function. -- I decided to keep it as is. Perhaps we should fix PGF's expansion approach in TeX (which is ugly anyway) function pgfluamathparser.pushLocalExpressionFunction(name, numArgs, expression) - -- now we have "tmpVar1^tmpVar2" instead of "#1^#2" - local normalizedExpr = expression:gsub("#", tmpFunctionArgumentPrefix) - local restores = {} - local tmpVars = {} - for i=1,numArgs do - local tmpVar = tmpFunctionArgumentPrefix .. tostring(i) - tmpVars[i] = tmpVar - end - - local newFunction = function(...) - local args = table.pack(...) - - -- define "tmpVar1" ... "tmpVarN" to return args[i]. - -- Of course, we need to restore "tmpVar" after we return! - for i=1,numArgs do - local tmpVar = tmpVars[i] - local value = args[i] - restores[i] = pgfStringToFunctionMap[tmpVar] - pgfStringToFunctionMap[tmpVar] = function () return value end - end - - -- parse our expression. - - -- FIXME : this here is an attempt to mess around with "units_declared". - -- It would be better to call pgfmathparse and introduce some - -- semaphore to check if pgfmathparse is a nested call-- in this case, it should - -- not reset units_declared. But there is no "finally" block and pcall is crap (looses stack trace). - local success,result = pcall(pgfmathparseinternal, normalizedExpr) - - -- remove 'tmpVar1', ... from the function table: - for i=1,numArgs do - local tmpVar = tmpVars[i] - pgfStringToFunctionMap[tmpVar] = restores[i] - end - - if success==false then error(result) end - return result - end - table.insert(stackOfLocalFunctions, name) - pgfStringToFunctionMap[name] = newFunction + -- now we have "tmpVar1^tmpVar2" instead of "#1^#2" + local normalizedExpr = expression:gsub("#", tmpFunctionArgumentPrefix) + local restores = {} + local tmpVars = {} + for i=1,numArgs do + local tmpVar = tmpFunctionArgumentPrefix .. tostring(i) + tmpVars[i] = tmpVar + end + + local newFunction = function(...) + local args = table.pack(...) + + -- define "tmpVar1" ... "tmpVarN" to return args[i]. + -- Of course, we need to restore "tmpVar" after we return! + for i=1,numArgs do + local tmpVar = tmpVars[i] + local value = args[i] + restores[i] = pgfStringToFunctionMap[tmpVar] + pgfStringToFunctionMap[tmpVar] = function () return value end + end + + -- parse our expression. + + -- FIXME : this here is an attempt to mess around with "units_declared". + -- It would be better to call pgfmathparse and introduce some + -- semaphore to check if pgfmathparse is a nested call-- in this case, it should + -- not reset units_declared. But there is no "finally" block and pcall is crap (looses stack trace). + local success,result = pcall(pgfmathparseinternal, normalizedExpr) + + -- remove 'tmpVar1', ... from the function table: + for i=1,numArgs do + local tmpVar = tmpVars[i] + pgfStringToFunctionMap[tmpVar] = restores[i] + end + + if success==false then error(result) end + return result + end + table.insert(stackOfLocalFunctions, name) + pgfStringToFunctionMap[name] = newFunction end function pgfluamathparser.popLocalExpressionFunction() - local name = stackOfLocalFunctions[#stackOfLocalFunctions] - pgfStringToFunctionMap[name] = nil - -- this removes the last element: - table.remove(stackOfLocalFunctions) + local name = stackOfLocalFunctions[#stackOfLocalFunctions] + pgfStringToFunctionMap[name] = nil + -- this removes the last element: + table.remove(stackOfLocalFunctions) end @@ -446,36 +447,36 @@ end -- @param expression the input expression (string) -- @param outputFormatChoice 0 if the result should be a fixed point number, 1 if it should be in FPU format -- @param showErrorMessage (boolean) true if any error should be displayed, false if errors should simply result in an invocation of TeX's parser (the default) --- +-- -- it defines \pgfmathresult and \ifpgfmathunitsdeclared function pgfluamathparser.texCallParser(expression, outputFormatChoice, showErrorMessage) - local success, result - if showErrorMessage then - result = pgfmathparse(expression) - success = true - else - success, result = pcall(pgfmathparse, expression) - end - - if success and result then - local result_str - if outputFormatChoice == 0 then - -- luamath/output format=fixed - result_str = tostringfixed(result) - else - -- luamath/output format=fixed - result_str = tostringfpu(result) - end - tex.sprint("\\def\\pgfmathresult{" .. result_str .. "}") - if pgfluamathparser.units_declared then - tex.sprint("\\pgfmathunitsdeclaredtrue") - else - tex.sprint("\\pgfmathunitsdeclaredfalse") - end - else - tex.sprint("\\def\\pgfmathresult{}") - tex.sprint("\\pgfmathunitsdeclaredfalse") - end + local success, result + if showErrorMessage then + result = pgfmathparse(expression) + success = true + else + success, result = pcall(pgfmathparse, expression) + end + + if success and result then + local result_str + if outputFormatChoice == 0 then + -- luamath/output format=fixed + result_str = tostringfixed(result) + else + -- luamath/output format=fixed + result_str = tostringfpu(result) + end + tex.sprint("\\def\\pgfmathresult{" .. result_str .. "}") + if pgfluamathparser.units_declared then + tex.sprint("\\pgfmathunitsdeclaredtrue") + else + tex.sprint("\\pgfmathunitsdeclaredfalse") + end + else + tex.sprint("\\def\\pgfmathresult{}") + tex.sprint("\\pgfmathunitsdeclaredfalse") + end end return pgfluamathparser 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 index 300ba52e989..c559a0cc1ba 100644 --- a/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgflibraryluamath.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/libraries/luamath/pgflibraryluamath.code.tex @@ -62,15 +62,15 @@ \pgfutil@ifluatex \let\pgfutil@directlua\directlua \pgfutil@directlua{% - tex.enableprimitives('pgfutil@',{'luaescapestring'})}% + tex.enableprimitives('pgfutil@',{'luaescapestring'})} \else - \def\pgfutil@directlua#1{}% - \def\pgfutil@luaescapestring#1{}% + \def\pgfutil@directlua#1{} + \def\pgfutil@luaescapestring#1{} \fi \pgfutil@directlua{% pgfluamathfunctions = require("pgf.luamath.functions") - pgfluamathparser = require("pgf.luamath.parser")}% + pgfluamathparser = require("pgf.luamath.parser")} % Patch some configuration macros such that the modifications are @@ -78,7 +78,7 @@ \pgfkeys{ /pgf/trig format/deg/.add code={}{\directlua{pgfluamathfunctions.setTrigFormat("deg")}\aftergroup\pgfmath@settrigformat}, /pgf/trig format/rad/.add code={}{\directlua{pgfluamathfunctions.setTrigFormat("rad")}\aftergroup\pgfmath@settrigformat}, -}% +} % ... and reactivate the key: \pgfmathiftrigonometricusesdeg{% \pgfkeys{/pgf/trig format/deg}% -- cgit v1.2.3