#WRT https://github.com/JuliaLang/julia/issues/5571#issuecomment-157608127 function terse_lambda(l_args::Vector{Symbol}, new_ff::Expr) if length(l_args)==0 return new_ff elseif length(l_args)==1 Expr(:->, l_args[1], new_ff ) else Expr(:->, Expr(:tuple,l_args...), new_ff ) end end function terse_treechange(ff::Expr) #Need to search the tree from left most node, to right #This is depth first I think (CHKLOGIC) function rec(path::Vector{Int},gg::Expr) new_tail = Any[] l_args = Symbol[] for (child_ii, hh) in enumerate(gg.args) if typeof(hh)==Expr c_path=[path...,child_ii] new_hh, c_l_args = rec(c_path,hh) if length(c_l_args)>0 push!(l_args, c_l_args...) end push!(new_tail, new_hh) elseif hh==:_ path_str = join(path,"b") #There may be a way to use the existing hygine mechnanism's to avoid a nameclash here #For now I describe them with the path c_l_arg = Symbol("xx$(path_str)t$(child_ii)") push!(l_args, c_l_arg) push!(new_tail, c_l_arg) else push!(new_tail, hh) end end new_gg = Expr(gg.head, new_tail...) (new_gg, l_args) end new_ff, ol_args = rec(Int[], ff) terse_lambda(ol_args, new_ff) end function terse!(ff) ff end function terse!(ff::Expr) const prec_other = Set(map(Symbol,["->", "if"])) const prec_assignment = Set(map(Symbol,["=", ":=", "+=", "-=", "*=", "/=", "//=", ".//=", ".*=", "./=", "|\\=|", "|.\\=|", "^=", ".^=", "÷=", ".÷=", "%=", ".%=", "|\|=|", "&=", "\$=", "=>", "<<=", ">>=", ">>>=", "~", "|.+=|", "|.-=|"])) const prec_conditional = Set([:?]) const prec_arrow = Set(map(Symbol,["", "'(--", "-->", "←", "→", "↔", "↚", "↛", "↠", "↣", "↦", "↮", "⇎", "⇏", "⇒", "⇔", "⇴", "⇶", "⇷", "⇸", "⇹", "⇺", "⇻", "⇼", "⇽", "⇾", "⇿", "⟵", "⟶", "⟷", "⟷", "⟹", "⟺", "⟻", "⟼", "⟽", "⟾", "⟿", "⤀", "⤁", "⤂", "⤃", "⤄", "⤅", "⤆", "⤇", "⤌", "⤍", "⤎", "⤏", "⤐", "⤑", "⤔", "⤕", "⤖", "⤗", "⤘", "⤝", "⤞", "⤟", "⤠", "⥄", "⥅", "⥆", "⥇", "⥈", "⥊", "⥋", "⥎", "⥐", "⥒", "⥓", "⥖", "⥗", "⥚", "⥛", "⥞", "⥟", "⥢", "⥤", "⥦", "⥧", "⥨", "⥩", "⥪", "⥫", "⥬", "⥭", "⥰", "⧴", "⬱", "⬰", "⬲", "⬳", "⬴", "⬵", "⬶", "⬷", "⬸", "⬹", "⬺", "⬻", "⬼", "⬽", "⬾", "⬿", "⭀", "⭁", "⭂", "⭃", "⭄", "⭇", "⭈", "⭉", "⭊", "⭋", "⭌", "←", "→))"])) const prec_above = union(prec_other, prec_assignment,prec_conditional, prec_arrow) function high_prec_node(gg::Expr) gg.head in prec_above end const prec_below = Set([:*,:+,:-,:/,:÷]) #Their many be others function low_prec_node(gg::Expr) #Certain nodes should not be transformed inside of, even if they are the top node gg.head == :call && gg.args[1] in prec_below end ####################### rewrite_nodes = Expr[] function need_rewrite!(gg) gg==:_ #My parent is a rewrite candiated if I am a blank node end function need_rewrite!(gg::Expr, top=false) at_peak = ((top && !low_prec_node(gg)) #Don't internally change within low_prec_node, even if at top || high_prec_node(gg)) #Do internally change with nodes of precences to high to propergate upwards need_rewrite_at_parent = false for child in gg.args child_need_rewrite = need_rewrite!(child) this_child_demand_granparent_rewrite = child_need_rewrite && ((at_peak && child==:_) || !at_peak) if this_child_demand_granparent_rewrite need_rewrite_at_parent=true break end end if need_rewrite_at_parent return true end #I can be rewritten as I am not demanding my parents be rewritten for ii in 1:length(gg.args) child = gg.args[ii] child_need_rewrite = need_rewrite!(child) if child_need_rewrite && at_peak gg.args[ii]=terse_treechange(child) end end return false end rewrite_top = need_rewrite!(ff,true) #println(rewrite_top) if rewrite_top terse_treechange(ff) else ff end end macro terse(ff) terse!(ff) end #Failing, #I'm not sure this failure is not infact the prefered behavour :(_ ? "true" : "false") |> terse! #→ (x -> x) ? "true" : "false") :(_ ? _ : 0) |> terse! #→ (x -> x) ? (y -> y) : 0 #Failing, Can't Fix #As (_) is interpretted as the same as _ :(map((_), v)) |> terse! #→ map(x -> x, v) #Won't Fix #Only standalone _ are broken, iuf they form part of even a simple expression eg `1_` they work #code only expressions are being rewritten, not symbols :(_)|>terse! #→ x -> x :(f = _)|>terse! #→ f = x -> x #Passing terse!(:(map(_ + 2, v) )) terse!(:(_ + 2)) terse!(:(f=_+2) ) terse!(:(x->_+2) ) terse!(:(map(_ + 2, v) )) terse!(:(f(_,b))) terse!(:(f(a,_))) terse!(:(f(_,_))) terse!(:(2_^2)) terse!(:(2_^_)) terse!(:(map(2_ + 2, v))) terse!(:(map(abs,_))) terse!(:(map(2_ + 2, _))) terse!(:(a[_])) terse!(:(a[_,_])) terse!(:(a[_,1_])) :(f(_,2_)) |> terse! :(map(2_ + 2, _)) |> terse! #→ x -> map(y -> 2y + 2, x) :(map(2_ - _, v, w)) |> terse! #→ map((x, y) -> 2x - y, v, w) :(map(2_ - _, v, _)) |> terse! #→ x -> map((y, z) -> 2y - z, v, x) :(map(2_ - _, _, _)) |> terse! #→ (x, y) -> map((z, w) -> 2z - w, x, y) :(map(_, v))|>terse! #→ x -> map(x, v) :(f = 2_)|>terse! #→ f = x -> 2x :(x -> x^_)|>terse! #→ x -> y -> x^y :(_ && _)|>terse! #→ (x, y) -> x && y :(!_ && _)|>terse! #→ (x, y) -> !x && y :(2v[_])|> terse! #→ x -> 2v[x] (good) :(2f(_)) |> terse! #→ 2*(x -> f(x)) (not so good)