Skip to content

Commit

Permalink
fix bug in nested quote and nested $ with splatting
Browse files Browse the repository at this point in the history
In general, the outermost quote evaluates the innermost $:

```
julia> y = 2
2

julia> x = :y
:y

julia> :(:(f($$x)))
:($(Expr(:quote, :(f($(Expr(:$, :y)))))))

julia> eval(ans)
:(f(2))

julia> :(:(f($x)))
:($(Expr(:quote, :(f($(Expr(:$, :x)))))))

julia> eval(ans)
:(f(y))
```

I triple-checked that this is how lisp works.

For splatting, you generally want to put extra `$`s inside the `...`.
E.g. `:(:(f($(($x)...))))` will cause the elements of `x` to be
splatted after two evaluations:

```
julia> x = [:a,:b];

julia> :(:(f($(($x)...))))
:($(Expr(:quote, :(f($(Expr(:$, :(([:a,:b]...,)))))))))

julia> eval(ans)
:(f(a,b))
```

This commit also fixes printing expressions with nested quote.
The problem is that printing works by surrounding an expression with
`:( )` and using `$` inside for Exprs that don't have surface syntax.
However, if the expression contains quotes, those quotes "capture"
any `$` expressions inside, preventing them from being evaluated by
the printer's outermost `:( )`.
For now I fixed this by reserving `quote`, `:( )`, and `$` only for
the outermost expression, and using `Expr` for inner quotes.
This works but leads to really ugly output. I believe the only way
to improve it is to introduce surface syntax for Exprs with arbitrary
head symbols, and for non-interpolating quote.
  • Loading branch information
JeffBezanson committed Feb 15, 2015
1 parent fddc978 commit 9ef1720
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 11 deletions.
27 changes: 19 additions & 8 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ end
show_comma_array(io::IO, itr, o, c) = show_delim_array(io, itr, o, ',', c, false)
show(io::IO, t::Tuple) = show_delim_array(io, t, '(', ',', ')', true)

show(io::IO, s::Symbol) = show_unquoted(io, QuoteNode(s))
show(io::IO, s::Symbol) = show_unquoted_quote_expr(io, s, 0, 0)

## Abstract Syntax Tree (AST) printing ##

Expand Down Expand Up @@ -228,7 +228,7 @@ show(io::IO, s::Symbol) = show_unquoted(io, QuoteNode(s))
typealias ExprNode Union(Expr, QuoteNode, SymbolNode, LineNumberNode,
LabelNode, GotoNode, TopNode)
print (io::IO, ex::ExprNode) = (show_unquoted(io, ex); nothing)
show (io::IO, ex::ExprNode) = show_unquoted(io, QuoteNode(ex))
show (io::IO, ex::ExprNode) = show_unquoted_quote_expr(io, ex, 0, 0)
show_unquoted(io::IO, ex) = show_unquoted(io, ex, 0, 0)
show_unquoted(io::IO, ex, indent::Int) = show_unquoted(io, ex, indent, 0)
show_unquoted(io::IO, ex, ::Int,::Int) = show(io, ex)
Expand Down Expand Up @@ -385,8 +385,15 @@ function show_unquoted(io::IO, ex::SymbolNode, ::Int, ::Int)
show_expr_type(io, ex.typ)
end

show_unquoted(io::IO, ex::QuoteNode, indent::Int, prec::Int) =
show_unquoted_quote_expr(io, ex.value, indent, prec)
function show_unquoted(io::IO, ex::QuoteNode, indent::Int, prec::Int)
if isa(ex.value, Symbol)
show_unquoted_quote_expr(io, ex.value, indent, prec)
else
print(io, "\$(QuoteNode(")
show(io, ex.value)
print(io, "))")
end
end

function show_unquoted_quote_expr(io::IO, value, indent::Int, prec::Int)
if isa(value, Symbol) && !(value in quoted_syms)
Expand Down Expand Up @@ -611,7 +618,7 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
elseif is(head, :block) || is(head, :body)
show_block(io, "begin", ex, indent); print(io, "end")

elseif is(head, :quote) && nargs == 1
elseif is(head, :quote) && nargs == 1 && isa(args[1],Symbol)
show_unquoted_quote_expr(io, args[1], indent, 0)

elseif is(head, :gotoifnot) && nargs == 2
Expand Down Expand Up @@ -643,9 +650,13 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
end
print(io, '"', a..., '"')

elseif is(head, :&) && length(args) == 1
print(io, '&')
show_unquoted(io, args[1])
elseif (is(head, :&)#= || is(head, :$)=#) && length(args) == 1
print(io, head)
a1 = args[1]
parens = (isa(a1,Expr) && a1.head !== :tuple) || (isa(a1,Symbol) && isoperator(a1))
parens && print(io, "(")
show_unquoted(io, a1)
parens && print(io, ")")

# transpose
elseif (head === symbol('\'') || head === symbol(".'")) && length(args) == 1
Expand Down
5 changes: 3 additions & 2 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -3278,11 +3278,12 @@ So far only the second case can actually occur.
(if (and (= d 0) (length= x 2))
(cadr x)
(if (splice-expr? (cadr x))
(wrap-with-splice (julia-bq-expand (cadr (cadr (cadr (cadr x)))) (- d 1)))
`(call (top splicedexpr) (inert $)
(call (top append_any) ,(julia-bq-bracket (cadr x) (- d 1))))
`(call (top _expr) (inert $) ,(julia-bq-expand (cadr x) (- d 1))))))
((not (contains (lambda (e) (and (pair? e) (eq? (car e) '$))) x))
`(copyast (inert ,x)))
((or (> d 0) (not (any splice-expr? x)))
((not (any splice-expr? x))
`(call (top _expr) ,.(map (lambda (ex) (julia-bq-expand ex d)) x)))
(else
(let loop ((p (cdr x)) (q '()))
Expand Down
5 changes: 4 additions & 1 deletion test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2164,4 +2164,7 @@ f8631{T}(::Type{(T...)}, x::Tuple) = 2

# issue caused by 8d0037cb377257fc4232c8526b12337dd7bdf0a7
args8d003 = (:x, :y)
@test eval(:(:(f($($(args8d003...)))))) == :(f(x,y))
@test eval(:(:(f($(($args8d003)...))))) == :(f(x,y))
x8d003 = Any[:y8d003]
y8d003 = 777
@test eval(:(string(:(f($($(x8d003...))))))) == "f(777)"
6 changes: 6 additions & 0 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,9 @@ let q1 = parse(repr(:("$(a)b"))),
@test q2.args[1].head == :string
@test q2.args[1].args == [:ab,]
end

x8d003 = 2
let a = Expr(:quote,Expr(:$,:x8d003))
@test eval(parse(repr(a))) == a
@test eval(eval(parse(repr(a)))) == 2
end

0 comments on commit 9ef1720

Please sign in to comment.