Skip to content

Instantly share code, notes, and snippets.

@GunnarFarneback
Created April 6, 2016 18:32
Show Gist options
  • Save GunnarFarneback/c970c9e63a33720bb71d0023f2c8a10f to your computer and use it in GitHub Desktop.
Save GunnarFarneback/c970c9e63a33720bb71d0023f2c8a10f to your computer and use it in GitHub Desktop.
Multiple break/continue in Julia, proof of concept
include("multibreak.jl")
println("standard Julia")
for i = 1:5
for j = 1:3
if i == 1 && j == 1
continue
elseif i == 2 && j == 2
break
elseif i == 3 && j == 2
break; continue
elseif i == 4 && j == 2
break; break
end
println(i, " ", j)
end
println(i)
end
println("multibreak macro")
@multibreak begin
for i = 1:5
for j = 1:3
if i == 1 && j == 1
continue
elseif i == 2 && j == 2
break
elseif i == 3 && j == 2
break; continue
elseif i == 4 && j == 2
break; break
end
println(i, " ", j)
end
println(i)
end
end
println("handcoded goto")
begin
for i = 1:5
for j = 1:3
if i == 1 && j == 1
@goto loop2continue
elseif i == 2 && j == 2
@goto loop2break
elseif i == 3 && j == 2
@goto loop1continue
elseif i == 4 && j == 2
@goto loop1break
end
println(i, " ", j)
@label loop2continue
end
@label loop2break
println(i)
@label loop1continue
end
@label loop1break
end
function multibreak_transform_break_and_continue(args, active_loops)
out = Any[]
nbreak = 0
ncontinue = 0
for arg in args
if Meta.isexpr(arg, :break)
if ncontinue > 0
error("Multibreak: continue can't precede a break")
end
nbreak += 1
elseif Meta.isexpr(arg, :continue)
if ncontinue > 0
error("Multibreak: multiple continue not allowed")
end
ncontinue += 1
elseif typeof(arg) == LineNumberNode
push!(out, arg)
else
push!(out, arg)
end
end
n = nbreak + ncontinue
if n > length(active_loops)
error("Multibreak: not enough nested loops for requested multi break/continue")
elseif n > 0
push!(out, Expr(:symbolicgoto,
symbol("loop",
active_loops[end - n + 1],
ncontinue == 0 ? "break" : "continue")))
end
return out
end
function multibreak_transform_ast(ast, loop_counter = [1], active_loops = Int[])
if typeof(ast) != Expr
return ast
end
if ast.head == :for
n = loop_counter[1]
active_loops = vcat(active_loops, n)
loop_counter[1] += 1
end
args = [multibreak_transform_ast(arg, loop_counter, active_loops) for arg in ast.args]
if ast.head == :for
arg2 = Expr(:block,
args[2],
Expr(:symboliclabel, symbol("loop", n, "continue")))
return Expr(:block,
Expr(:for, args[1], arg2),
Expr(:symboliclabel, symbol("loop", n, "break")))
elseif ast.head == :block
return Expr(:block,
multibreak_transform_break_and_continue(args, active_loops)...)
end
return Expr(ast.head, args...)
end
macro multibreak(blk)
multibreak_transform_ast(blk)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment