Skip to content

RFC: Improvement to hygienic macros #6910

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

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
7 changes: 4 additions & 3 deletions base/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -801,12 +801,13 @@ end
macro keymap(keymaps)
dict = keymap_unify(keymap_prepare(keymaps))
body = keymap_gen_body(dict, dict)
esc(quote
(s, data) -> begin
# Bindings of s and data are non-hygienic, visible to body
quote
($:s, $:data) -> begin
$body
return :ok
end
end)
end
end

const escape_defaults = merge!(
Expand Down
2 changes: 1 addition & 1 deletion base/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ function shell_completions(string,pos)
end
r = (nextind(string, pos-sizeof(name))):pos
return ret, r, true
elseif isexpr(arg, :escape) && (isexpr(arg.args[1], :incomplete) || isexpr(arg.args[1], :error))
elseif isexpr(arg, :incomplete) || isexpr(arg, :error)
r = first(last_parse):prevind(last_parse, last(last_parse))
partial = scs[r]
ret, range = completions(partial, endof(partial))
Expand Down
3 changes: 2 additions & 1 deletion base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ function precompile(f, args::Tuple)
end
end

esc(e::ANY) = Expr(:escape, e)
# Neuter esc but for convenience don't remove it yet - it's deprecated
esc(e::ANY) = e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the @deprecate macro to print a deprecation warning. The deprecation declarations are consolidated into the base/deprecated.jl file to make them easy to find.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On May 21, 2014, at 3:36 PM, pao wrote:

You can use the @deprecate macro to print a deprecation warning.
Probably better to use the terser, "Returns its argument."

Good suggestions. I will make these updates after a day or two to
let others weigh in.

On May 21, 2014, at 3:30 PM, Kevin Squire wrote:

Thanks for making thing so clear.

I don't see anything to be gained by obfuscation! I used
approximately the same form of commit log that we used to use at
Progress Software.

--Dave Moon


macro boundscheck(yesno,blk)
# hack: use this syntax since it avoids introducing line numbers
Expand Down
7 changes: 7 additions & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,10 @@ function localize_vars(expr, esca)
end
Expr(:localize, :(()->($expr)), v...)
end

# Enable hygiene in all quotes inside this annotation
# This is useful for subroutines of macro expanders
export @hygienic
macro hygienic(exp)
Expr(:with_hygiene, exp)
end
28 changes: 14 additions & 14 deletions base/printf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export @printf, @sprintf

### printf formatter generation ###

function gen(s::String)
@hygienic function gen(s::String)
args = {}
blk = Expr(:block, :(local neg, pt, len, exp))
for x in parse(s)
Expand Down Expand Up @@ -131,7 +131,7 @@ end

### printf formatter generation ###

function special_handler(flags::ASCIIString, width::Int)
@hygienic function special_handler(flags::ASCIIString, width::Int)
@gensym x
blk = Expr(:block)
pad = '-' in flags ? rpad : lpad
Expand All @@ -146,7 +146,7 @@ function special_handler(flags::ASCIIString, width::Int)
x, ex, blk
end

function pad(m::Int, n, c::Char)
@hygienic function pad(m::Int, n, c::Char)
if m <= 1
:($n > 0 && write(out,$c))
else
Expand Down Expand Up @@ -208,7 +208,7 @@ function print_exp(out, exp)
write(out, char('0'+rem(exp,10)))
end

function gen_d(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_d(flags::ASCIIString, width::Int, precision::Int, c::Char)
# print integer:
# [dDiu]: print decimal digits
# [o]: print octal digits
Expand All @@ -226,8 +226,7 @@ function gen_d(flags::ASCIIString, width::Int, precision::Int, c::Char)
# interpret the number
prefix = ""
if lowercase(c)=='o'
f = '#' in flags ? :int_0ct : :int_oct
push!(blk.args, :(($f)($x)))
push!(blk.args, '#' in flags ? :(int_0ct($x)) : :(int_oct($x)))
elseif c=='x'
'#' in flags && (prefix = "0x")
push!(blk.args, :(int_hex($x)))
Expand Down Expand Up @@ -287,7 +286,7 @@ function gen_d(flags::ASCIIString, width::Int, precision::Int, c::Char)
:(($x)::Real), ex
end

function gen_f(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_f(flags::ASCIIString, width::Int, precision::Int, c::Char)
# print to fixed trailing precision
# [fF]: the only choice
#
Expand Down Expand Up @@ -348,7 +347,7 @@ function gen_f(flags::ASCIIString, width::Int, precision::Int, c::Char)
:(($x)::Real), ex
end

function gen_e(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_e(flags::ASCIIString, width::Int, precision::Int, c::Char)
# print float in scientific form:
# [e]: use 'e' to introduce exponent
# [E]: use 'E' to introduce exponent
Expand Down Expand Up @@ -419,7 +418,7 @@ function gen_e(flags::ASCIIString, width::Int, precision::Int, c::Char)
:(($x)::Real), ex
end

function gen_c(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_c(flags::ASCIIString, width::Int, precision::Int, c::Char)
# print a character:
# [cC]: both the same for us (Unicode)
#
Expand All @@ -440,7 +439,7 @@ function gen_c(flags::ASCIIString, width::Int, precision::Int, c::Char)
:(($x)::Integer), blk
end

function gen_s(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_s(flags::ASCIIString, width::Int, precision::Int, c::Char)
# print a string:
# [sS]: both the same for us (Unicode)
#
Expand Down Expand Up @@ -475,7 +474,7 @@ end

# TODO: faster pointer printing.

function gen_p(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_p(flags::ASCIIString, width::Int, precision::Int, c::Char)
# print pointer:
# [p]: the only option
#
Expand All @@ -495,7 +494,7 @@ function gen_p(flags::ASCIIString, width::Int, precision::Int, c::Char)
:(($x)::Ptr), blk
end

function gen_g(flags::ASCIIString, width::Int, precision::Int, c::Char)
@hygienic function gen_g(flags::ASCIIString, width::Int, precision::Int, c::Char)
error("printf \"%g\" format specifier not implemented")
end

Expand Down Expand Up @@ -751,7 +750,7 @@ is_str_expr(ex) =
isa(ex,Expr) && (ex.head == :string || (ex.head == :macrocall && isa(ex.args[1],Symbol) &&
endswith(string(ex.args[1]),"str")))

function _printf(macroname, io, fmt, args)
@hygienic function _printf(macroname, io, fmt, args)
isa(fmt, String) || error("$macroname: format must be a plain static string (no interpolation or prefix)")
sym_args, blk = gen(fmt)
if length(sym_args) != length(args)
Expand Down Expand Up @@ -780,7 +779,8 @@ macro sprintf(args...)
!isempty(args) || error("@sprintf: called with zero arguments")
isa(args[1], String) || is_str_expr(args[1]) ||
error("@sprintf: first argument must be a format string")
:(sprint(io->$(_printf("@sprintf", :io, args[1], args[2:end]))))
io = gensym("io")
:(sprint($io->$(_printf("@sprintf", io, args[1], args[2:end]))))
end

end # module
32 changes: 18 additions & 14 deletions base/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -286,50 +286,54 @@ function spawn(pc::ProcessChainOrNot,cmds::ErrOrCmds,stdios::StdIOSet,exitcb::Ca
end


# Generates non-hygienic bindings of in, out, err
# and close_in, close_out, close_err
macro setup_stdio()
esc(
quote
close_in,close_out,close_err = false,false,false
in,out,err = stdios
$:close_in, $:close_out, $:close_err = false, false, false
$:in, $:out, $:err = stdios
if isa(stdios[1],Pipe)
if stdios[1].handle==C_NULL
error("pipes passed to spawn must be initialized")
end
elseif isa(stdios[1],FileRedirect)
in = FS.open(stdios[1].filename,JL_O_RDONLY)
close_in = true
$:in = FS.open(stdios[1].filename,JL_O_RDONLY)
$:close_in = true
elseif isa(stdios[1],IOStream)
in = FS.File(RawFD(fd(stdios[1])))
$:in = FS.File(RawFD(fd(stdios[1])))
end
if isa(stdios[2],Pipe)
if stdios[2].handle==C_NULL
error("pipes passed to spawn must be initialized")
end
elseif isa(stdios[2],FileRedirect)
out = FS.open(stdios[2].filename,JL_O_WRONLY|JL_O_CREAT|(stdios[2].append?JL_O_APPEND:JL_O_TRUNC),S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
close_out = true
$:out = FS.open(stdios[2].filename,JL_O_WRONLY|JL_O_CREAT|(stdios[2].append?JL_O_APPEND:JL_O_TRUNC),S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
$:close_out = true
elseif isa(stdios[2],IOStream)
out = FS.File(RawFD(fd(stdios[2])))
$:out = FS.File(RawFD(fd(stdios[2])))
end
if isa(stdios[3],Pipe)
if stdios[3].handle==C_NULL
error("pipes passed to spawn must be initialized")
end
elseif isa(stdios[3],FileRedirect)
err = FS.open(stdios[3].filename,JL_O_WRONLY|JL_O_CREAT|(stdios[3].append?JL_O_APPEND:JL_O_TRUNC),S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
close_err = true
$:err = FS.open(stdios[3].filename,JL_O_WRONLY|JL_O_CREAT|(stdios[3].append?JL_O_APPEND:JL_O_TRUNC),S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
$:close_err = true
elseif isa(stdios[3],IOStream)
err = FS.File(RawFD(fd(stdios[3])))
$:err = FS.File(RawFD(fd(stdios[3])))
end
end)
end

# Depends on non-hygienic bindings of in, out, err
# and close_in, close_out, close_err
macro cleanup_stdio()
esc(
quote
close_in && close(in)
close_out && close(out)
close_err && close(err)
$:close_in && close($:in)
$:close_out && close($:out)
$:close_err && close($:err)
end)
end

Expand Down
5 changes: 3 additions & 2 deletions base/stream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -717,12 +717,13 @@ end
#end

macro uv_write(n,call)
# binding of uvw is supposed to be non-hygienic, visible to caller
esc(quote
check_open(s)
uvw = c_malloc(_sizeof_uv_write+$(n))
$:uvw = c_malloc(_sizeof_uv_write+$(n))
err = $call
if err < 0
c_free(uvw)
c_free($:uvw)
uv_error("write", err)
end
end)
Expand Down
Loading