summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/x-calcmath.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/x-calcmath.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/x-calcmath.lua289
1 files changed, 159 insertions, 130 deletions
diff --git a/Master/texmf-dist/tex/context/base/x-calcmath.lua b/Master/texmf-dist/tex/context/base/x-calcmath.lua
index fcb6b7470a6..e4d5da139f9 100644
--- a/Master/texmf-dist/tex/context/base/x-calcmath.lua
+++ b/Master/texmf-dist/tex/context/base/x-calcmath.lua
@@ -6,7 +6,8 @@ if not modules then modules = { } end modules ['x-calcmath'] = {
license = "see context related readme files"
}
-local format, lower, upper, gsub = string.format, string.lower, string.upper, string.gsub
+local format, lower, upper, gsub, sub = string.format, string.lower, string.upper, string.gsub, string.sub
+local lpegmatch = lpeg.match
tex = tex or { }
@@ -71,8 +72,8 @@ local symbols = {
}
local function nsub(str,tag,pre,post)
- return (str:gsub(tag .. "(%b())", function(body)
- return pre .. nsub(body:sub(2,-2),tag,pre,post) .. post
+ return (gsub(str,tag .. "(%b())", function(body)
+ return pre .. nsub(sub(body,2,-2),tag,pre,post) .. post
end))
end
@@ -80,87 +81,87 @@ function calcmath.totex(str,mode)
if not frozen then freeze() end
local n = 0
-- crap
- str = str:gsub("%s+" , ' ')
+ str = gsub(str,"%s+",' ')
-- xml
- str = str:gsub("&(.-);", entities)
+ str = gsub(str,"&(.-);",entities)
-- ...E...
- str = str:gsub("([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}")
+ str = gsub(str,"([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}")
-- ^-..
- str = str:gsub( "%^([%-%+]*%d+)", "^{%1}")
+ str = gsub(str,"%^([%-%+]*%d+)", "^{%1}")
-- ^(...)
- str = nsub(str, "%^", "^{", "}")
+ str = nsub(str,"%^", "^{", "}")
-- 1/x^2
repeat
- str, n = str:gsub("([%d%w%.]+)/([%d%w%.]+%^{[%d%w%.]+})", "\\frac{%1}{%2}")
+ str, n = gsub(str,"([%d%w%.]+)/([%d%w%.]+%^{[%d%w%.]+})", "\\frac{%1}{%2}")
until n == 0
-- todo: autoparenthesis
-- int(a,b,c)
for k, v in next, list_2_1 do
- repeat str, n = str:gsub(k,v) until n == 0
+ repeat str, n = gsub(str,k,v) until n == 0
end
-- int(a,b)
for k, v in next, list_2_2 do
- repeat str, n = str:gsub(k, v) until n == 0
+ repeat str, n = gsub(str,k,v) until n == 0
end
-- int(a)
for k, v in next, list_2_3 do
- repeat str, n = str:gsub(k, v) until n == 0
+ repeat str, n = gsub(str,k,v) until n == 0
end
-- sin(x) => {\\sin(x)}
for k, v in next, list_1_1 do
- repeat str, n = str:gsub(k, v) until n == 0
+ repeat str, n = gsub(str,k,v) until n == 0
end
-- mean
str = nsub(str, "mean", "\\OVERLINE{", "}")
-- (1+x)/(1+x) => \\FRAC{1+x}{1+x}
repeat
- str, n = str:gsub("(%b())/(%b())", function(a,b)
- return "\\FRAC{" .. a:sub(2,-2) .. "}{" .. b:sub(2,-2) .. "}"
+ str, n = gsub(str,"(%b())/(%b())", function(a,b)
+ return "\\FRAC{" .. sub(a,2,-2) .. "}{" .. sub(b,2,-2) .. "}"
end )
until n == 0
-- (1+x)/x => \\FRAC{1+x}{x}
repeat
- str, n = str:gsub("(%b())/([%+%-]?[%.%d%w]+)", function(a,b)
- return "\\FRAC{" .. a:sub(2,-2) .. "}{" .. b .. "}"
+ str, n = gsub(str,"(%b())/([%+%-]?[%.%d%w]+)", function(a,b)
+ return "\\FRAC{" .. sub(a,2,-2) .. "}{" .. b .. "}"
end )
until n == 0
-- 1/(1+x) => \\FRAC{1}{1+x}
repeat
- str, n = str:gsub("([%.%d%w]+)/(%b())", function(a,b)
- return "\\FRAC{" .. a .. "}{" .. b:sub(2,-2) .. "}"
+ str, n = gsub(str,"([%.%d%w]+)/(%b())", function(a,b)
+ return "\\FRAC{" .. a .. "}{" .. sub(b,2,-2) .. "}"
end )
until n == 0
-- 1/x => \\FRAC{1}{x}
repeat
- str, n = str:gsub("([%.%d%w]+)/([%+%-]?[%.%d%w]+)", "\\FRAC{%1}{%2}")
+ str, n = gsub(str,"([%.%d%w]+)/([%+%-]?[%.%d%w]+)", "\\FRAC{%1}{%2}")
until n == 0
-- times
- str = str:gsub("%*", " ")
+ str = gsub(str,"%*", " ")
-- symbols -- we can use a table substitution here
- str = str:gsub("([<>=][<>=]*)", symbols)
+ str = gsub(str,"([<>=][<>=]*)", symbols)
-- functions
- str = nsub(str, "sqrt", "\\SQRT{", "}")
- str = nsub(str, "exp", "e^{", "}")
- str = nsub(str, "abs", "\\left|", "\\right|")
+ str = nsub(str,"sqrt", "\\SQRT{", "}")
+ str = nsub(str,"exp", "e^{", "}")
+ str = nsub(str,"abs", "\\left|", "\\right|")
-- d/D
- str = nsub(str, "D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}")
- str = str:gsub("D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}")
+ str = nsub(str,"D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}")
+ str = gsub(str,"D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}")
-- f/g
for k,v in next, list_3 do -- todo : prepare k,v
- str = nsub(str, "D"..v,"{\\RM "..v.."}^{\\PRIME}(",")")
- str = nsub(str, v,"{\\RM "..v.."}(",")")
+ str = nsub(str,"D"..v,"{\\RM "..v.."}^{\\PRIME}(",")")
+ str = nsub(str,v,"{\\RM "..v.."}(",")")
end
-- more symbols
for k,v in next, list_4_1 do
- str = str:gsub(k, v)
+ str = gsub(str,k,v)
end
-- parenthesis (optional)
if mode == 2 then
- str = str:gsub("%(", "\\left\(")
- str = str:gsub("%)", "\\right\)")
+ str = gsub(str,"%(", "\\left\(")
+ str = gsub(str,"%)", "\\right\)")
end
-- csnames
- str = str:gsub("(\\[A-Z]+)", lower)
+ str = gsub(str,"(\\[A-Z]+)", lower)
-- trace
--~ print(str)
-- report
@@ -191,19 +192,20 @@ if false then
-- Df Dg {\rm f}^{\prime}
-- f() g() {\rm f}()
+
-- valid utf8
local S, P, R, C, V, Cc, Ct = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct
local space = S(" \n\r\t")^0
- local number_x = P("-")^-1 * R("09")^1
- local real_x = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1
- local number = Cc("number") * C(number_x) * space
- local real = Cc("real") * C(real_x) * space
- local float = Cc("float") * C(real_x) * lpeg.P("E") * lpeg.C(number_x) * space
- local identifier = Cc("identifier") * C(R("az","AZ")^1) * space
- local compareop = P("<") + P("=") + P(">") + P(">=") + P("<=") + P("&gt;") + P("&lt;")
- local factorop = Cc("factor") * C(S("+-^,") + compareop ) * space
+ local integer = P("-")^-1 * R("09")^1
+ local realpart = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1
+ local number = Cc("number") * C(integer) * space
+ local real = Cc("real") * C(realpart) * space
+ local float = Cc("float") * C(realpart) * lpeg.P("E") * lpeg.C(integer) * space
+ local identifier = Cc("identifier") * C(R("az","AZ")) * space
+ local compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P("&gt;") + P("&lt;")) * space
+ local factorop = Cc("factor") * C(S("+-^_,")) * space
local termop = Cc("term") * C(S("*/")) * space
local constant = Cc("constant") * C(P("pi") + lpeg.P("inf")) * space
local functionop = Cc("function") * C(R("az")^1) * space
@@ -212,123 +214,150 @@ if false then
local grammar = P {
"expression",
- expression = Ct(V("factor" ) * (factorop * V("factor" ))^0),
- factor = Ct(V("term" ) * (termop * V("term" ))^0),
+ expression = Ct(V("factor") * ((factorop+compareop) * V("factor"))^0),
+ factor = Ct(V("term") * (termop * V("term"))^0),
term = Ct(
float + real + number +
(open * V("expression") * close) +
- (functionop * open * V("expression") * close) +
+ (functionop * open * (V("expression") * (P(",") * V("expression"))^0) * close) +
+ (functionop * V("term")) +
constant + identifier
),
}
+
local parser = space * grammar * -1
+ local texprint = function(...) texio.write(table.concat{ ... }) end
+
+ local function has_factor(t)
+ for i=1,#t do
+ if t[i] == "factor" then
+ return true
+ end
+ end
+ end
+
function totex(t)
if t then
- local one, two, three = t[1], t[2], t[3]
- if one == "number" then
- return two
- elseif one == "real" then
- return two
- elseif one == "float" then
- return format("\\scinot{%s}{%s}", two, three)
- elseif one == "identifier" then
- return format(" %s ", two)
- elseif one == "constant" then
- return format("\\%s ", two)
- elseif one == "function" then
- if two == "sqrt" then
- return format("\\sqrt{%s}", totex(three))
- elseif two == "exp" then
- return format(" e^{%s}", totex(three))
- elseif two == "abs" then
- return format("\\left|%s\\right|", totex(three))
- elseif two == "mean" then
- return format("\\overline{%s}", totex(three))
- elseif two == "int" or two == "prod" or two == "sum" then --brrr, we need to parse better for ,,
- local tt = three
- if #tt == 1 then
- return format("\\%s{%s}", two ,totex(tt[1]))
- elseif #tt == 4 then
- return format("\\%s^{%s}{%s}", two ,totex(tt[1]), totex(tt[4]))
- elseif #tt == 7 then
- return format("\\%s^{%s}_{%s}{%s}", two ,totex(tt[1]), totex(tt[4]), totex(tt[7]))
- end
- elseif #two == 1 then
- return format("%s(%s)", two, totex(three))
- else
- return format("\\%s(%s)", two, totex(three))
- end
- elseif one == "factor" then
- if two == '^' then
- return format("^{%s}%s",totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "")
- else
- if two == ">=" then
- two = "\\ge "
- elseif two == "<=" then
- two = "\\le "
- elseif two == "&gt;" then
- two = "> "
- elseif two == "&lt;" then
- two = "< "
- end
- return format("%s%s%s", two, totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "")
- end
- elseif one == "term" then
- if two == '/' then
- if #t > 4 then
- return format("\\frac{%s}{%s}", totex(three), totex({unpack(t,4,#t)}))
+ local one = t[1]
+ if type(one) == "string" then
+ local two, three = t[2], t[3]
+ if one == "number" then
+ texprint(two)
+ elseif one == "real" then
+ texprint(two)
+ elseif one == "float" then
+ texprint("\\scinot{",two,"}{",three,"}")
+ elseif one == "identifier" then
+ texprint(two)
+ elseif one == "constant" then
+ texprint("\\"..two)
+ elseif one == "function" then
+ if two == "sqrt" then
+ texprint("\\sqrt{")
+ totex(three)
+ texprint("}")
+ elseif two == "exp" then
+ texprint(" e^{")
+ totex(three)
+ texprint("}")
+ elseif two == "abs" then
+ texprint("\\left|")
+ totex(three)
+ texprint("\\right|")
+ elseif two == "mean" then
+ texprint("\\overline{")
+ totex(three)
+ texprint("}")
+ elseif two == "int" or two == "prod" or two == "sum" then
+ local four, five = t[4], t[5]
+ if five then
+ texprint("\\"..two.."^{")
+ totex(three)
+ texprint("}_{")
+ totex(four)
+ texprint("}")
+ totex(five)
+ elseif four then
+ texprint("\\"..two.."^{")
+ totex(three)
+ texprint("}")
+ totex(four)
+ elseif three then
+ texprint("\\"..two.." ") -- " " not needed
+ totex(three)
+ else
+ texprint("\\"..two)
+ end
else
- return format("\\frac{%s}{%s}", totex(three), totex(t[4]))
+ texprint("\\"..two.."(")
+ totex(three)
+ texprint(")")
end
- elseif two == '*' then
- local times = "\\times "
- return format("%s%s%s", times, totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "")
- else
- return format("%s%s%s", two, totex(three), (#t>3 and totex({unpack(t,4,#t)})) or "")
end
- elseif two == "factor" then
- if three == '^' then
- return format("%s^{%s}", totex(one), totex(t[4]))
- else
- if two == ">=" then
- two = "\\ge "
- elseif two == "<=" then
- two = "\\le "
- elseif two == "&gt;" then
- two = "> "
- elseif two == "&lt;" then
- two = "< "
+ else
+ local nt = #t
+ local hasfactor = has_factor(t)
+ if hasfactor then
+ texprint("\\left(")
+ end
+ totex(one)
+ for i=2,nt,3 do
+ local what, how, rest = t[i], t[i+1], t[i+2]
+ if what == "factor" then
+ if how == '^' or how == "_" then
+ texprint(how)
+ texprint("{")
+ totex(rest)
+ texprint("}")
+ else
+ texprint(how)
+ totex(rest)
+ end
+ elseif what == "term" then
+ if how == '/' then
+ texprint("\\frac{")
+ totex(rest)
+ texprint("}{")
+ totex(t[i+3] or "")
+ texprint("}")
+ elseif how == '*' then
+ texprint("\\times")
+ totex(rest)
+ else
+ texprint(how)
+ totex(three)
+ end
+ elseif what == "compare" then
+ if two == ">=" then
+ texprint("\\ge")
+ elseif two == "<=" then
+ texprint("\\le")
+ elseif two == "&gt;" then
+ texprint(">")
+ elseif two == "&lt;" then
+ texprint("<")
+ end
+ totex(three)
end
- return format("%s%s", totex(one), (#t>1 and totex({unpack(t,2,#t)})) or "")
end
- elseif two == "term" then
- if three == '/' then
- return format("\\frac{%s}{%s}", totex(one), (#t>3 and totex({unpack(t,4,#t)})) or "")
- else
- return format("%s%s", totex(one), (#t>1 and totex({unpack(t,2,#t)})) or "")
+ if hasfactor then
+ texprint("\\right)")
end
- else
- return totex(one)
end
end
- return ""
end
calcmath = { }
function calcmath.parse(str)
- return parser:match(str)
+ return lpegmatch(parser,str)
end
function calcmath.tex(str)
- str = totex(parser:match(str))
- print(str)
+ str = totex(lpegmatch(parser,str))
return (str == "" and "[error]") or str
end
end
-
---~ compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P("&gt;")/">" + P("&lt;")/"<") * space
---~ comparison = Ct(V("expression") * (compareop * V("expression"))^0),