Convert String to function name

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>