RosettaCodeData/Task/Arithmetic-evaluation/Pluto/arithmetic-evaluation.pluto
2026-04-30 12:34:36 -04:00

87 lines
2.2 KiB
Text

-- If string is empty, returns zero.
local function to_double_or_zero(s)
local n = tonumber(s)
return n ? n : 0
end
local function multiply(s)
local b = s:split("*"):map(|c| -> to_double_or_zero(c))
return tostring(b[1] * b[2])
end
local function divide(s)
local b = s:split("/"):map(|c| -> to_double_or_zero(c))
return tostring(b[1] / b[2])
end
local function add(s)
local t = s:gsub("^%+", ""):gsub("%++", "+")
local b = t:split("+"):map(|c| -> to_double_or_zero(c))
return tostring(b[1] + b[2])
end
local function subtract(s)
local t = s:gsub("(%+%-|%-%+)", "-")
if "--" in t then return add(t:replace("--", "+")) end
local b = t:split("-"):map(|c| -> to_double_or_zero(c))
return tostring(#b == 3 ? -b[2] - b[3] : b[1] - b[2])
end
local function eval_exp(s)
local t = s:gsub("[()]", "")
local pmd = "%d+%.?%d*%s*[*/]%s*[+-]?%d+%.?%d*"
local pm = "%*"
local pas = "%-?%d+%.?%d*%s*[+-]%s*[+-]?%d+%.?%d*"
local pa = "%d%+"
while true do
local exp = t:match(pmd)
if !exp then break end
local exp2 = exp:match(pm)
if exp2 then
t = t:replace(exp, multiply(exp))
else
t = t:replace(exp, divide(exp))
end
end
while true do
local exp = t:match(pas)
if !exp then break end
local exp2 = exp:match(pa)
if exp2 then
t = t:replace(exp, add(exp))
else
t = t:replace(exp, subtract(exp))
end
end
return t
end
local function eval_arithmetic_exp(s)
local t = s:gsub("%s", ""):gsub("^%+", "")
local ppara = "%([^()]*%)"
while true do
local exp = t:match(ppara)
if !exp then break end
t = t:replace(exp, eval_exp(exp))
end
return to_double_or_zero(eval_exp(t))
end
({
"2+3",
"2+3/4",
"2*3-4",
"2*(3+4)+5/6",
"2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10",
"2*-3--4+-0.25",
"-4 - 3",
"((((2))))+ 3 * 5",
"1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10",
"1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1"
}):foreach(|s| -> do
local r = eval_arithmetic_exp(s)
if r % 1.0 == 0 then r = math.round(r) end
print($"{s} = {r}")
end)