Those are fun examples but not very general-purpose. acorn looks more general-purpose but at first browse I couldn’t see how metaprogramming could be done, so math.js’s parsing still seems like the more official way.
How are you transferring ASTs between separate languages anyway, strings? If so, that would explain the post; it’s not that the Expr
ession is not structured right, it’s that printing and string
deparses the same way to infix notation. I don’t know of a way to reduce infix notation as much as possible; it’s not possible entirely because some operators are infix-only, like _?_:_
.
If you replace the operators with alphabetical symbols or expressions, it will be deparsed to function calls like you need; in the general case, it’s just a matter of recursively visiting nested Expr
and replacing operator symbols mapped to alternate names. I imagine you did something similar in R.
julia> ex = :( +(x, /(y, z)) )
:(x + y / z)
julia> ex.args[1] = :(math.add); ex.args[3].args[1] = :(math.divide); ex
:(math.add(x, math.divide(y, z)))
julia> string(ex)
"math.add(x, math.divide(y, z))"
julia> function replacesymbols!(ex::Expr, symbolmap::AbstractDict{Symbol})
ex.head = get(symbolmap, ex.head, ex.head)
for i in eachindex(ex.args)
arg = ex.args[i]
if arg isa Symbol
ex.args[i] = get(symbolmap, arg, arg)
elseif arg isa Expr
replacesymbols!(arg, symbolmap)
end
end
ex # input is already mutated so not a necessary return
end
julia> altops = Dict(:+ => :(math.add),
:- => :(math.subtract),
:* => :(math.multiply),
:/ => :(math.divide),
);
julia> ex = :(a+b/c*e-f^g) # note that ^ is not in mapping
:((a + (b / c) * e) - f ^ g)
julia> replacesymbols!(ex, altops)
:(math.subtract(math.add(a, math.multiply(math.divide(b, c), e)), f ^ g))
julia> string(ex)
"math.subtract(math.add(a, math.multiply(math.divide(b, c), e)), f ^ g)"
Bear in mind that there aren’t always built-in alphabetical aliases for infix operators in Julia, for example ÷
has div
but +
is by itself, so only eval
the expression prior to replacement in Julia.