Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline macro via :meta expressions #8297

Merged
merged 3 commits into from
Sep 20, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions base/cartesian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const CARTESIAN_DIMS = 4
# myfunction(A::AbstractArray, I::Int...N)
# where N can be an integer or symbol. Currently T...N generates a parser error.
macro ngenerate(itersym, returntypeexpr, funcexpr)
if isa(funcexpr, Expr) && funcexpr.head == :macrocall && funcexpr.args[1] == symbol("@inline")
funcexpr = Base._inline(funcexpr.args[2])
end
isfuncexpr(funcexpr) || error("Requires a function expression")
esc(ngenerate(itersym, returntypeexpr, funcexpr.args[1], N->sreplace!(copy(funcexpr.args[2]), itersym, N)))
end
Expand Down Expand Up @@ -57,6 +60,9 @@ macro nsplat(itersym, args...)
else
error("Wrong number of arguments")
end
if isa(funcexpr, Expr) && funcexpr.head == :macrocall && funcexpr.args[1] == symbol("@inline")
funcexpr = Base._inline(funcexpr.args[2])
end
isfuncexpr(funcexpr) || error("Second argument must be a function expression")
prototype = funcexpr.args[1]
body = funcexpr.args[2]
Expand Down
3 changes: 2 additions & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1384,4 +1384,5 @@ export
@inbounds,
@simd,
@label,
@goto
@goto,
@inline
41 changes: 41 additions & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ macro eval(x)
:($(esc(:eval))($(Expr(:quote,x))))
end

macro inline(ex)
esc(_inline(ex))
end

_inline(ex::Expr) = pushmeta!(ex, :inline)
_inline(arg) = arg

## some macro utilities ##

find_vars(e) = find_vars(e, {})
Expand Down Expand Up @@ -95,3 +102,37 @@ function localize_vars(expr, esca)
end
Expr(:localize, :(()->($expr)), v...)
end

function pushmeta!(ex::Expr, sym::Symbol)
if ex.head == :function
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, sym)
else
unshift!(body.args, Expr(:meta, sym))
end
elseif (ex.head == :(=) && typeof(ex.args[1]) == Expr && ex.args[1].head == :call)
ex = Expr(:function, ex.args[1], Expr(:block, Expr(:meta, sym), ex.args[2]))
# else
# ex = Expr(:withmeta, ex, sym)
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 metaargs[i] == sym
if length(metaargs) == 1
shift!(body.args) # get rid of :meta Expr
else
deleteat!(metaargs, i) # delete this portion of the metadata
end
return true
end
end
end
false
end
popmeta!(arg, sym) = false
7 changes: 3 additions & 4 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2496,10 +2496,9 @@ const inline_incompletematch_allowed = false

inline_worthy(body, cost::Real) = true
function inline_worthy(body::Expr, cost::Real=1.0) # precondition: 0<cost
# if isa(body.args[1],QuoteNode) && (body.args[1]::QuoteNode).value === :inline
# shift!(body.args)
# return true
# end
if popmeta!(body, :inline)
return true
end
symlim = 1+5/cost
if length(body.args) < symlim
symlim *= 16
Expand Down
2 changes: 1 addition & 1 deletion src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jl_sym_t *compositetype_sym; jl_sym_t *type_goto_sym;
jl_sym_t *global_sym; jl_sym_t *tuple_sym;
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
jl_sym_t *boundscheck_sym; jl_sym_t *copyast_sym;
jl_sym_t *simdloop_sym;
jl_sym_t *simdloop_sym; jl_sym_t *meta_sym;

typedef struct {
int64_t a;
Expand Down
3 changes: 3 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3006,6 +3006,9 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
"Warning: could not attach metadata for @simd loop.\n");
return NULL;
}
else if (head == meta_sym) {
return literal_pointer_val((jl_value_t*)jl_nothing); // will change as new metadata gets added
}
else {
if (!strcmp(head->name, "$"))
jl_error("syntax: prefix $ in non-quoted expression");
Expand Down
3 changes: 3 additions & 0 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl)
else if (ex->head == simdloop_sym) {
return (jl_value_t*)jl_nothing;
}
else if (ex->head == meta_sym) {
return (jl_value_t*)jl_nothing;
}
jl_errorf("unsupported or misplaced expression %s", ex->head->name);
return (jl_value_t*)jl_nothing;
}
Expand Down
1 change: 1 addition & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3261,6 +3261,7 @@ void jl_init_types(void)
newvar_sym = jl_symbol("newvar");
copyast_sym = jl_symbol("copyast");
simdloop_sym = jl_symbol("simdloop");
meta_sym = jl_symbol("meta");
}

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ extern jl_sym_t *abstracttype_sym; extern jl_sym_t *bitstype_sym;
extern jl_sym_t *compositetype_sym; extern jl_sym_t *type_goto_sym;
extern jl_sym_t *global_sym; extern jl_sym_t *tuple_sym;
extern jl_sym_t *boundscheck_sym; extern jl_sym_t *copyast_sym;
extern jl_sym_t *simdloop_sym;
extern jl_sym_t *simdloop_sym; extern jl_sym_t *meta_sym;


// object accessors -----------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ TESTS = all core keywordargs numbers strings unicode collections hashing \
suitesparse complex version pollfd mpfr broadcast socket floatapprox \
priorityqueue readdlm reflection regex float16 combinatorics dates \
sysinfo rounding ranges mod2pi euler show lineedit replcompletions \
backtrace repl test examples goto llvmcall grisu
backtrace repl test examples goto llvmcall grisu meta

default: all

Expand Down
27 changes: 27 additions & 0 deletions test/meta.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# test meta-expressions that annotate blocks of code

module MetaTest

using Base.Test

function f(x)
y = x+5
z = y*y
q = z/y
m = q-3
end

@inline function f_inlined(x)
y = x+5
z = y*y
q = z/y
m = q-3
end

g(x) = f(2x)
g_inlined(x) = f_inlined(2x)

@test g(3) == g_inlined(3)
@test f(3) == f_inlined(3)

end
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ testnames = [
"floatapprox", "readdlm", "reflection", "regex", "float16", "combinatorics",
"sysinfo", "rounding", "ranges", "mod2pi", "euler", "show",
"lineedit", "replcompletions", "repl", "test", "examples", "goto",
"llvmcall", "grisu", "nullable"
"llvmcall", "grisu", "nullable", "meta"
]
@unix_only push!(testnames, "unicode")

Expand Down