Created
April 6, 2016 18:32
-
-
Save GunnarFarneback/c970c9e63a33720bb71d0023f2c8a10f to your computer and use it in GitHub Desktop.
Multiple break/continue in Julia, proof of concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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