Skip to content

Commit

Permalink
Merge pull request #5832 from mbauman/editmacro
Browse files Browse the repository at this point in the history
Add edit, less and code_* macros, mirroring which
  • Loading branch information
StefanKarpinski committed Apr 8, 2014
2 parents 2e54c38 + 4337bb8 commit 648f74e
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 29 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Library improvements

* New functions `minmax` and `extrema` ([#5275]).

* New macros `@edit`, `@less`, `@code_typed`, `@code_lowered`, `@code_llvm` and `@code_native` that all function like `@which` ([#5832]).

* `consume(p)` extended to `consume(p, args...)`, allowing it
to optionally pass `args...` back to the producer ([#4775]).

Expand Down Expand Up @@ -756,6 +758,7 @@ Too numerous to mention.
[#3605]: https://github.com/JuliaLang/julia/pull/3605
[#3233]: https://github.com/JuliaLang/julia/pull/3233
[#4811]: https://github.com/JuliaLang/julia/pull/4811
[#5832]: https://github.com/JuliaLang/julia/pull/5832

[packages chapter]: http://docs.julialang.org/en/latest/manual/packages/
[sorting functions]: http://docs.julialang.org/en/latest/stdlib/sort/
Expand Down
2 changes: 2 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,5 @@ end
export nnz

scale!{T<:Base.LinAlg.BlasReal}(X::Array{T}, s::Complex) = error("scale!: Cannot scale a real array by a complex value in-place. Use scale(X::Array{Real}, s::Complex) instead.")

@deprecate which(f::Callable, args...) @which f(args...)
6 changes: 6 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,12 @@ export
@allocated,
@profile,
@which,
@edit,
@less,
@code_typed,
@code_lowered,
@code_llvm,
@code_native,
@windows,
@unix,
@osx,
Expand Down
2 changes: 1 addition & 1 deletion base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2741,7 +2741,7 @@ function replace_tupleref!(ast, e::ANY, tupname, vals, sv, i0)
end
end

function code_typed(f::Callable, types)
function code_typed(f::Callable, types::(Type...))
asts = {}
for x in _methods(f,types,-1)
linfo = x[3].func.code
Expand Down
56 changes: 35 additions & 21 deletions base/interactiveutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ function less(file::String, line::Integer)
run(`$pager +$(line)g $file`)
end
less(file::String) = less(file, 1)

edit(f::Union(Function,DataType)) = edit(functionloc(f)...)
edit(f::Union(Function,DataType), t) = edit(functionloc(f,t)...)
less(f::Union(Function,DataType)) = less(functionloc(f)...)
less(f::Union(Function,DataType), t) = less(functionloc(f,t)...)
edit(f::Callable) = edit(functionloc(f)...)
edit(f::Callable, t::(Type...)) = edit(functionloc(f,t)...)
less(f::Callable) = less(functionloc(f)...)
less(f::Callable, t::(Type...)) = less(functionloc(f,t)...)

function edit( m::Method )
tv, decls, file, line = arg_decl_parts(m)
Expand Down Expand Up @@ -187,53 +186,68 @@ versioninfo(verbose::Bool) = versioninfo(STDOUT,verbose)

# searching definitions

function which(f::Callable, args...)
function which(f::Callable, t::(Type...))
if !isgeneric(f)
throw(ErrorException("not a generic function, no methods available"))
end
ms = methods(f, map(a->(isa(a,Type) ? Type{a} : typeof(a)), args))
isempty(ms) && throw(MethodError(f, args))
ms = methods(f, t)
isempty(ms) && throw(MethodError(f, t))
ms[1]
end

macro which(ex0)
if isa(ex0,Expr) &&
any(a->(Meta.isexpr(a,:kw) || Meta.isexpr(a,:parameters)), ex0.args)
typesof(args...) = map(a->(isa(a,Type) ? Type{a} : typeof(a)), args)

function gen_call_with_extracted_types(fcn, ex0)
if isa(ex0, Expr) &&
any(a->(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex0.args)
# keyword args not used in dispatch, so just remove them
args = filter(a->!(Meta.isexpr(a,:kw) || Meta.isexpr(a,:parameters)), ex0.args)
return Expr(:call, :which, map(esc, args)...)
args = filter(a->!(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex0.args)
return Expr(:call, fcn, esc(args[1]),
Expr(:call, :typesof, map(esc, args[2:end])...))
end
if isa(ex0, Expr) && ex0.head == :call
return Expr(:call, :which, map(esc, ex0.args)...)
return Expr(:call, fcn, esc(ex0.args[1]),
Expr(:call, :typesof, map(esc, ex0.args[2:end])...))
end
ex = expand(ex0)
exret = Expr(:call, :error, "expression is not a function call")
if !isa(ex, Expr)
# do nothing -> error
elseif ex.head == :call
if any(e->(isa(e,Expr) && e.head==:(...)), ex0.args) &&
isa(ex.args[1],TopNode) && ex.args[1].name == :apply
exret = Expr(:call, ex.args[1], :which,
if any(e->(isa(e, Expr) && e.head==:(...)), ex0.args) &&
isa(ex.args[1], TopNode) && ex.args[1].name == :apply
exret = Expr(:call, ex.args[1], fcn,
Expr(:tuple, esc(ex.args[2])),
map(esc, ex.args[3:end])...)
Expr(:call, :typesof, map(esc, ex.args[3:end])...))
else
exret = Expr(:call, :which, map(esc, ex.args)...)
exret = Expr(:call, fcn, esc(ex.args[1]),
Expr(:call, :typesof, map(esc, ex.args[2:end])...))
end
elseif ex.head == :body
a1 = ex.args[1]
if isa(a1, Expr) && a1.head == :call
a11 = a1.args[1]
if a11 == :setindex!
exret = Expr(:call, :which, a11, map(esc, a1.args[2:end])...)
exret = Expr(:call, fcn, a11,
Expr(:call, :typesof, map(esc, a1.args[2:end])...))
end
end
elseif ex.head == :thunk
exret = Expr(:call, :error, "expression is not a function call, or is too complex for @which to analyze; "
exret = Expr(:call, :error, "expression is not a function call, "
* "or is too complex for @which to analyze; "
* "break it down to simpler parts if possible")
end
exret
end

for fname in [:which, :less, :edit, :code_typed, :code_lowered, :code_llvm, :code_native]
@eval begin
macro ($fname)(ex0)
gen_call_with_extracted_types($fname, ex0)
end
end
end

# `methodswith` -- shows a list of methods using the type given

function methodswith(t::Type, m::Module, showparents::Bool=false)
Expand Down
10 changes: 5 additions & 5 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ isgeneric(f::ANY) = (isa(f,Function)||isa(f,DataType)) && isa(f.env,MethodTable)

function_name(f::Function) = isgeneric(f) ? f.env.name : (:anonymous)

code_lowered(f::Function,t::Tuple) = map(m->uncompressed_ast(m.func.code), methods(f,t))
code_lowered(f::Function,t::(Type...)) = map(m->uncompressed_ast(m.func.code), methods(f,t))
methods(f::ANY,t::ANY) = map(m->m[3], _methods(f,t,-1))::Array{Any,1}
_methods(f::ANY,t::ANY,lim) = _methods(f,{(t::Tuple)...},length(t::Tuple),lim,{})
function _methods(f::ANY,t::Array,i,lim::Integer,matching::Array{Any,1})
Expand Down Expand Up @@ -136,10 +136,10 @@ function _dump_function(f, t::ANY, native, wrapper)
str
end

code_llvm (f::Callable, types::Tuple) = print(_dump_function(f, types, false, false))
code_native(f::Callable, types::Tuple) = print(_dump_function(f, types, true, false))
code_llvm (f::Callable, types::(Type...)) = print(_dump_function(f, types, false, false))
code_native(f::Callable, types::(Type...)) = print(_dump_function(f, types, true, false))

function functionlocs(f::Union(Function,DataType), types=(Any...))
function functionlocs(f::Callable, types=(Type...))
locs = Any[]
for m in methods(f, types)
lsd = m.func.code::LambdaStaticData
Expand All @@ -154,7 +154,7 @@ function functionlocs(f::Union(Function,DataType), types=(Any...))
locs
end

functionloc(f::Union(Function,DataType), types=(Any...)) = functionlocs(f, types)[1]
functionloc(f::Callable, types=(Any...)) = functionlocs(f, types)[1]

function function_module(f::Function, types=(Any...))
m = methods(f, types)
Expand Down
28 changes: 26 additions & 2 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ Getting Around

Edit the definition of a function, optionally specifying a tuple of types to indicate which method to edit.

.. function:: @edit

Evaluates the arguments to the function call, determines their types, and calls the ``edit`` function on the resulting expression

.. function:: less(file::String, [line])

Show a file using the default pager, optionally providing a starting line number. Returns to the julia prompt when you quit the pager.
Expand All @@ -57,6 +61,10 @@ Getting Around

Show the definition of a function using the default pager, optionally specifying a tuple of types to indicate which method to see.

.. function:: @less

Evaluates the arguments to the function call, determines their types, and calls the ``less`` function on the resulting expression

.. function:: clipboard(x)

Send a printed form of ``x`` to the operating system clipboard ("copy").
Expand Down Expand Up @@ -89,9 +97,9 @@ Getting Around

Search documentation for functions related to ``string``.

.. function:: which(f, args...)
.. function:: which(f, types)

Return the method of ``f`` (a ``Method`` object) that will be called for the given arguments.
Return the method of ``f`` (a ``Method`` object) that will be called for arguments with the given types.

.. function:: @which

Expand Down Expand Up @@ -5520,18 +5528,34 @@ Internals

Returns an array of lowered ASTs for the methods matching the given generic function and type signature.

.. function:: @code_lowered

Evaluates the arguments to the function call, determines their types, and calls the ``code_lowered`` function on the resulting expression

.. function:: code_typed(f, types)

Returns an array of lowered and type-inferred ASTs for the methods matching the given generic function and type signature.

.. function:: @code_typed

Evaluates the arguments to the function call, determines their types, and calls the ``code_typed`` function on the resulting expression

.. function:: code_llvm(f, types)

Prints the LLVM bitcodes generated for running the method matching the given generic function and type signature to STDOUT.

.. function:: @code_llvm

Evaluates the arguments to the function call, determines their types, and calls the ``code_llvm`` function on the resulting expression

.. function:: code_native(f, types)

Prints the native assembly instructions generated for running the method matching the given generic function and type signature to STDOUT.

.. function:: @code_native

Evaluates the arguments to the function call, determines their types, and calls the ``code_native`` function on the resulting expression

.. function:: precompile(f,args::(Any...,))

Compile the given function `f` for the argument tuple (of types) `args`, but do not execute it.

0 comments on commit 648f74e

Please sign in to comment.