Here I post a script that tries to interpret expressions provided in the form of strings and constructs the “corresponding” functions.
The problem comes from here.
But this post seems more suitable to host the (possible) discussion.
At the moment only some functions are “read” correctly.
The aim was however to build a small calculator for some predefined functions.
And in any case there is a case that causes the function that does the “parsing” to fail.
I have idea how to work around the problem, but I would like to ask for someone’s suggestion to have a “cleaner” solution.
la piccola calcolatatrice
julia> df=Dict("log"=>log, "sin"=>sin, "*"=>*,"+"=>+,"-"=>-,"^"=>^, "∘"=>∘)
Dict{String, Function} with 7 entries:
"∘" => ∘
"-" => -
"log" => log
"^" => ^
"*" => *
"+" => +
"sin" => sin
julia> function splitpar(str)
splitpos=[]
cp=0
for (i,c) in enumerate(str)
cp= cp+(c=='(')-(c==')')
c==','&& cp==0 && push!(splitpos,i)
end
splitpos
end
splitpar (generic function with 1 method)
julia> function splitinpos(s2s,pos)
ss=String[]
pos=[0;pos;length(s2s)+1]
for i in (2:length(pos))
push!(ss,s2s[pos[i-1]+1:pos[i]-1])
end
ss
end
splitinpos (generic function with 1 method)
julia> function str2func(str)
lff=findfirst('(', str)
op=df[str[1:lff-1]]
if !occursin('(',str[lff+1:end])
par=split(str[lff+1:end-1],',')
tp=tryparse.(Int,par)
n=only(filter(!isnothing,tp))
return ((a...)->op(n,a...))
else
s2s=str[lff+1:end-1]
par=splitinpos(s2s,splitpar(s2s))
return (x...)->op(
[str2func(p)(x[indexin(intersect(join(vars), p),vars)]
...) for p in par]...)
end
end
str2func (generic function with 1 method)
julia> vars=['x','y','z']
3-element Vector{Char}:
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
'y': ASCII/Unicode U+0079 (category Ll: Letter, lowercase)
'z': ASCII/Unicode U+007A (category Ll: Letter, lowercase)
julia> str3= "+(*(+(3,x),*(-2,y)),*(2,x),+(*(3,x),*(4,y)))"
"+(*(+(3,x),*(-2,y)),*(2,x),+(*(3,x),*(4,y)))"
julia> str2func(str3)(1,-1)
9
julia> str4= "*(+(3,x),*(-2,z),*(1,x,z))"
"*(+(3,x),*(-2,z),*(1,x,z))"
julia> str2func(str4)(1,-1,2) #-32
-32
julia> str5= "+(*(+(3,x),*(-2,y),*(1,x,z)),*(+(3,y),*(-2,z),*(1,x,z)))"
"+(*(+(3,x),*(-2,y),*(1,x,z)),*(+(3,y),*(-2,z),*(1,x,z)))"
julia> str2func(str5)(1,-1,2) # 0
0
julia> str6= "+(*(+(3,x),*(-2,z),*(1,x)),*(+(3,y),*(-2,x),*(1,x,z)))"
"+(*(+(3,x),*(-2,z),*(1,x)),*(+(3,y),*(-2,x),*(1,x,z)))"
julia> str2func(str6)(1,-1,2)
ERROR: BoundsError: attempt to access Tuple{Int64, Int64} at index [3]
Stacktrace:
---
# the operation *(-2,z) indexes the 'z' which is in the third position, but the group *(+(3,x),*(-2,z),*(1,x)) it only has two distinct variables. The same expression with *(1,y) instead of *(1,x) does not in fact raise the same problem-
julia> str7= "+(*(+(3,x),*(-2,z),*(1,y)),*(+(3,y),*(-2,x),*(1,x,z)))"
"+(*(+(3,x),*(-2,z),*(1,y)),*(+(3,y),*(-2,x),*(1,x,z)))"
julia> str2func(str7)(1,-1,2)# 8
8
julia>