Search code examples
parsingsyntaxjuliaparentheses

How to automatically parenthesize an arbitrary Julia expression


Given a syntactically valid, but otherwise arbitrary, Julia expression, such as

3 - 4 > 1 & 2 + 2 == 4 | 10 - 5 > 2

or

2 + 9 - 8 * 8 ^ 7 / 2 == 8 + 8 / 1 ^ 2

...is there a convenient way to fully parenthesize the expression in a way consistent with Julia's standard parsing of it?

One approach that won't go far enough:

julia> parse("3 - 4 > 1 & 2+2 == 4 | 10 - 5 > 2")
:(3 - 4 > 1 & 2 + 2 == (4 | 10) - 5 > 2)

julia> parse("2 + 9 - 8 * 8 ^ 7 / 2 == 8 + 8 / 1 ^ 2")
:((2 + 9) - (8 * 8^7) / 2 == 8 + 8 / 1^2)

For example, for the last case, by "full parenthesized" I mean:

:(((2 + 9) - ((8 * (8 ^ 7)) / 2)) == (8 + (8 / (1 ^ 2))))

Is there something else?


Solution

  • You need some code to traverse the quoted expression recursively.

    I have made an example here which works for infix operations like +, - and will fail if you use function calls like this f(a)

    Each of the Expressions has 3 fields, head, typ, and args, but only head and args are usesful as typ is mostly Any most of the time. You can see this using

    expr = :(1+2*3)
    typeof(expr)
    fieldnames(expr)
    expr.head
    expr.args
    
    # full solution
    function bracketit(expr)
      if expr isa Symbol
        return string(expr)
      elseif expr isa Expr
        if expr.head == :call
          return string("(",bracketit(expr.args[2]),expr.args[1],bracketit(expr.args[3]),")")
        elseif expr.head == :comparison
          return string("(",bracketit.(expr.args)...,")")
        end
      else
        return(string(expr))
      end
    end
    
    exprA = :(3 - 4 > 1 & 2 + 2 == 4 | 10 - 5 > 2) 
    bracketit(exprA) #((3-4)>((1&2)+2)==((4|10)-5)>2)
    
    exprB = :(2 + 9 - 8 * 8 ^ 7 / 2 == 8 + 8 / 1 ^ 2) #(((2+9)-((8*(8^7))/2))==(8+(8/(1^2))))
    bracketit(exprB)