This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Yevano's profile picture

Label Control Flow

Started by Yevano, 03 January 2016 - 09:40 PM
Yevano #1
Posted 03 January 2016 - 10:40 PM
As you all know, there's not always a nice way in Lua to break out of nested loops. E.g.,


local b = true
while b do
	while true do
		if endProgram then
			b = false
			break
		end
	end
end

Obviously this starts to look worse the more loops that you're nested in. Now, whether this can be blamed on bad programming practices or not is not really the point of this post, so I won't go into it. Anyways, I figured out a neat little way of solving this problem that some people might enjoy using.


mklabel("A", function() while true do
	mklabel("B", function() while true do
		breakfrom("A")
	end end)
end end)

print("Hello World!")

In this code, breakfrom("A") causes both nested functions to terminate, meaning that you get to jump right out of both nested loops without the usual fluff. Calling breakfrom("B") would have the same effect as just doing break.

The code is very simple, so I'll paste it here. For convenience if you want to try it out, pastebin get CFg347Tw brk.

local top

function mklabel(name, func)
    if not top then top = func end
    local isTop = top == func
    local suc, res = pcall(func)
    if not suc then
        if not res:find("__BREAKFROM") then error(res, -1) end
        local target = res:gsub("[^\:]+:[^\:]+: __BREAKFROM", "")
        if name ~= target then
            if isTop then
                error("Tried to break from label '" .. target .. "' which does not exist.", 2)
            end
            error("__BREAKFROM" .. target)
        end
    end
    if isTop then top = nil end
end

function breakfrom(name)
    error("__BREAKFROM" .. name)
end

As you can see it just unrolls the stack until the correct label is found. AFAIK it doesn't mess up error handling in any way since it detects whether the error is for the purpose of breaking or not.

So yeah, let me know if you find this useful!
Edited on 03 January 2016 - 09:52 PM
Creator #2
Posted 03 January 2016 - 10:52 PM
I found an even neater way:


breakfrom  = os.reboot()

Just joking, yours is very good. :)/>