Skip to content

Commit 612b0c5

Browse files
committed
Make standalone prefix /> work. Improved lowering.
1 parent 87df76e commit 612b0c5

File tree

2 files changed

+68
-17
lines changed

2 files changed

+68
-17
lines changed

src/expr.jl

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -324,25 +324,74 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
324324
args[1] = Expr(headsym, args[1].args...)
325325
headsym = :const
326326
end
327-
elseif headsym == Symbol("/>")
327+
elseif headsym == Symbol("/>") || headsym == Symbol("\\>")
328328
freearg = gensym()
329-
cargs = [args[1], freearg, args[2:end]...]
330-
reorder_parameters!(cargs, 2)
331-
return Expr(:->, freearg, Expr(:call, cargs...))
332-
elseif headsym == Symbol("\\>")
333-
freearg = gensym()
334-
cargs = [args[1], args[2:end]..., freearg]
335-
reorder_parameters!(cargs, 2)
336-
return Expr(:->, freearg, Expr(:call, cargs...))
329+
callex = only(args)
330+
@assert Meta.isexpr(callex, :call)
331+
args = callex.args
332+
func = headsym == Symbol("/>") ?
333+
:(JuliaSyntax.fixbutfirst) :
334+
:(JuliaSyntax.fixbutlast)
335+
if length(args) >= 2 && Meta.isexpr(args[2], :parameters)
336+
return Expr(:call, func, args[2], args[1], args[3:end]...)
337+
else
338+
return Expr(:call, func, args...)
339+
end
337340
elseif headsym == :chain
338-
return Expr(:call, :(JuliaSyntax.chain), args...)
341+
if kind(node_args[1]) in KSet"/> \>"
342+
return Expr(:call, :(JuliaSyntax.compose_chain), args...)
343+
else
344+
return Expr(:call, :(JuliaSyntax.chain), args...)
345+
end
339346
end
340347
return Expr(headsym, args...)
341348
end
342349

350+
#-------------------------------------------------------------------------------
351+
# Targets for lowering /> and \> syntax
352+
353+
# For use with />
354+
struct FixButFirst{F,Args,Kws}
355+
f::F
356+
args::Args
357+
kwargs::Kws
358+
end
359+
360+
(f::FixButFirst)(x) = f.f(x, f.args...; f.kwargs...)
361+
362+
"""
363+
Fix all arguments except for the first
364+
"""
365+
fixbutfirst(f, args...; kws...) = FixButFirst(f, args, kws)
366+
367+
# For use with \>
368+
struct FixButLast{F,Args,Kws}
369+
f::F
370+
args::Args
371+
kwargs::Kws
372+
end
373+
374+
(f::FixButLast)(x) = f.f(f.args..., x; f.kwargs...)
375+
376+
"""
377+
Fix all arguments except for the last
378+
"""
379+
fixbutlast(f, args...; kws...) = FixButLast(f, args, kws)
380+
343381
chain(x, f, fs...) = chain(f(x), fs...)
344382
chain(x) = x
345383

384+
struct ComposeChain{Funcs}
385+
fs::Funcs
386+
end
387+
388+
(f::ComposeChain)(x) = chain(x, f.fs...)
389+
390+
compose_chain(fs...) = ComposeChain(fs)
391+
392+
393+
#-------------------------------------------------------------------------------
394+
346395
Base.Expr(node::SyntaxNode) = _to_expr(node)
347396

348397
function build_tree(::Type{Expr}, stream::ParseStream; kws...)

src/parser.jl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -827,20 +827,22 @@ end
827827
# x /> A.f(y) ==> (chain x (/> (. A (quote f)) y))
828828
function parse_curry_chain(ps::ParseState)
829829
mark = position(ps)
830-
parse_range(ps)
831-
has_chain = false
830+
nterms = 0
831+
if (k = peek(ps); k != K"/>" && k != K"\>")
832+
parse_range(ps)
833+
nterms += 1
834+
end
832835
while (k = peek(ps); k == K"/>" || k == K"\>")
833836
bump(ps, TRIVIA_FLAG)
834837
m = position(ps)
835838
parse_range(ps)
836-
if peek_behind(ps).kind == K"call"
837-
has_chain = true
838-
reset_node!(ps, position(ps), kind=k)
839-
else
839+
nterms += 1
840+
if peek_behind(ps).kind != K"call"
840841
emit(ps, m, K"error", error="Expected call to the right of />")
841842
end
843+
emit(ps, m, k)
842844
end
843-
if has_chain
845+
if nterms > 1
844846
emit(ps, mark, K"chain")
845847
end
846848
end

0 commit comments

Comments
 (0)