Skip to content

Commit

Permalink
Check more than the first expression for :meta
Browse files Browse the repository at this point in the history
This fixes the primary problem in JuliaLang#11595, but is not enough on its
own to recapture full performance. Interestingly, this does not appear to
cause a measurable slowing of the compilation of base.
  • Loading branch information
timholy authored and tkelman committed Jun 8, 2015
1 parent 8d68131 commit 1be9f2a
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 32 deletions.
73 changes: 43 additions & 30 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,45 +119,58 @@ function pushmeta!(ex::Expr, sym::Symbol, args::Any...)
else
tag = Expr(sym, args...)
end

if ex.head == :function
found, metaex = findmeta(ex)
if found
push!(metaex.args, tag)
else
body::Expr = ex.args[2]
if !isempty(body.args) && isa(body.args[1], Expr) && (body.args[1]::Expr).head == :meta
push!((body.args[1]::Expr).args, tag)
elseif isempty(body.args)
push!(body.args, Expr(:meta, tag))
push!(body.args, nothing)
else
unshift!(body.args, Expr(:meta, tag))
end
elseif (ex.head == :(=) && typeof(ex.args[1]) == Expr && ex.args[1].head == :call)
ex = Expr(:function, ex.args[1], Expr(:block, Expr(:meta, tag), ex.args[2]))
# else
# ex = Expr(:withmeta, ex, sym)
unshift!(body.args, Expr(:meta, tag))
end
ex
end

function popmeta!(body::Expr, sym::Symbol)
if isa(body.args[1],Expr) && (body.args[1]::Expr).head === :meta
metaargs = (body.args[1]::Expr).args
for i = 1:length(metaargs)
if (isa(metaargs[i], Symbol) && metaargs[i] == sym) ||
(isa(metaargs[i], Expr) && metaargs[i].head == sym)
if length(metaargs) == 1
shift!(body.args) # get rid of :meta Expr
else
deleteat!(metaargs, i) # delete this portion of the metadata
end
body.head == :block || return false, []
found, metaex = findmeta_block(body)
if !found
return false, []
end
metaargs = metaex.args
for i = 1:length(metaargs)
if isa(metaargs[i], Symbol) && (metaargs[i]::Symbol) == sym
deleteat!(metaargs, i)
return true, []
elseif isa(metaargs[i], Expr) && (metaargs[i]::Expr).head == sym
ret = (metaargs[i]::Expr).args
deleteat!(metaargs, i)
return true, ret
end
end
false, []
end
popmeta!(arg, sym) = (false, [])

if isa(metaargs[i], Symbol)
return (true, [])
elseif isa(metaargs[i], Expr)
return (true, metaargs[i].args)
function findmeta(ex::Expr)
if ex.head == :function || (ex.head == :(=) && typeof(ex.args[1]) == Expr && ex.args[1].head == :call)
body::Expr = ex.args[2]
body.head == :block || error(body, " is not a block expression")
return findmeta_block(ex)
end
error(ex, " is not a function expression")
end

function findmeta_block(ex::Expr)
for a in ex.args
if isa(a, Expr)
if (a::Expr).head == :meta
return true, a::Expr
elseif (a::Expr).head == :block
found, exb = findmeta_block(a)
if found
return found, exb
end
end
end
end
return (false, [])
return false, Expr(:block)
end
popmeta!(arg, sym) = (false, [])
4 changes: 2 additions & 2 deletions doc/devdocs/meta.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ that a given block of code has special properties: you might always
want to inline it, or you might want to turn on special compiler
optimization passes. Starting with version 0.4, julia has a
convention that these instructions can be placed inside a ``:meta``
expression, which must be the first expression in the body of a
function.
expression, which is typically (but not necessarily) the first
expression in the body of a function.

``:meta`` expressions are created with macros. As an example, consider
the implementation of the ``@inline`` macro::
Expand Down
23 changes: 23 additions & 0 deletions test/meta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,29 @@ body.args = ast.args[3].args
@test popmeta!(body, :test) == (true, [42])
@test popmeta!(body, :nonexistent) == (false, [])

metaex = Expr(:meta, :foo)
ex1 = quote
$metaex
x*x+1
end
metaex = Expr(:meta, :foo)
ex2 = quote
y = x
$metaex
y*y+1
end
metaex = Expr(:block, Expr(:meta, :foo))
ex3 = quote
y = x
$metaex
x*x+1
end

@test popmeta!(ex1, :foo)[1]
@test popmeta!(ex2, :foo)[1]
@test popmeta!(ex3, :foo)[1]
@test !(popmeta!(:(x*x+1), :foo)[1])

end


Expand Down

0 comments on commit 1be9f2a

Please sign in to comment.