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

Exceptional - Easy error catching!

Started by Lignum, 11 February 2015 - 12:59 PM
Lignum #1
Posted 11 February 2015 - 01:59 PM
Exceptional adds an exception-style error handling system to Lua. If you've ever used a language with exceptions, you should be able to get familiar with the API fairly quickly.

Example usage:

os.unloadAPI(shell.resolve("exceptional"))
os.loadAPI(shell.resolve("exceptional"))

try {
	function()
		--# Is handled.
		throw {
			Type = "ItDoesntWorkError",
			WhatDoesntWork = "It just doesn't work!"
		}

		--# These aren't actually called because throw terminates the function.
		--# Throws a LuaError.
		error("Some boring error.")

		--# Is caught by the catch statement because it's unhandled.
		throw {
			Type = "SomeException"
		}

		--# If an exception doesn't have a handler and there is no catch statement,
		--# the exception is suppressed completely.
	end
} :LuaError {
	function(e)
		--# e is the exception table
		printError("There was an error on line " .. e.Line .. " in chunk \"" .. e.Chunk .. "\"!")
		printError("Details: " .. e.Message)
	end
} :ItDoesntWorkError {
	function(e)
		printError("It doesn't work on line " .. e.Line .. " in chunk \"" .. e.Chunk .. "\"!")
		printError("Details: " .. e.WhatDoesntWork)
	end
} :catch {
	function(e)
		printError("Caught exception of type " .. e.Type .. " on line " .. e.Line .. " in chunk \"" .. e.Chunk .. "\"!")
	end
}

Download:
Pastebin link
or

pastebin get bfVk3qWR exceptional

The project is on GitHub now!
Edited on 12 February 2015 - 03:03 PM
MKlegoman357 #2
Posted 11 February 2015 - 03:23 PM
Very nice! :)/> Though you have to keep in mind that the error message may not always be a string. Also, the user might want to throw their own custom exceptions (classes, etc..).
Lignum #3
Posted 11 February 2015 - 03:31 PM
Very nice! :)/> Though you have to keep in mind that the error message may not always be a string. Also, the user might want to throw their own custom exceptions (classes, etc..).
Thank you! Currently, this is just a fancy interface for error/pcall, which only supports non-string errors from Lua 5.2 on. However, if I ever change how it works, I'll be sure to keep that in mind.
Edited on 11 February 2015 - 02:32 PM
MKlegoman357 #4
Posted 11 February 2015 - 03:42 PM
Thank you! Currently, this is just a fancy interface for error/pcall, which only supports non-string errors from Lua 5.2 on. However, if I ever change how it works, I'll be sure to keep that in mind.

Actually, Lua 5.1 supports any type of error message: strings, numbers, tables, functions, threads, userdata.

EDIT: Of course it's just a fancy interface, but it's really nice to have something like try-catch statement in Lua. pcall and error are not the best-looking ones.
Edited on 11 February 2015 - 02:44 PM
Lignum #5
Posted 11 February 2015 - 03:54 PM
Actually, Lua 5.1 supports any type of error message: strings, numbers, tables, functions, threads, userdata.

EDIT: Of course it's just a fancy interface, but it's really nice to have something like try-catch statement in Lua. pcall and error are not the best-looking ones.

Well, not quite. Lua just tostrings the input. error({ 1, 2, 3 }) gives me "table: [address]".
Regardless, I'll work on allowing you to specify an exception type using the throw function as well as catching exception types. Thinking about it, it sounds more complicated than it is so expect to see it soon :)/>.
MKlegoman357 #6
Posted 11 February 2015 - 06:46 PM
Well, not quite. Lua just tostrings the input. error({ 1, 2, 3 }) gives me "table: [address]".
Regardless, I'll work on allowing you to specify an exception type using the throw function as well as catching exception types. Thinking about it, it sounds more complicated than it is so expect to see it soon :)/>.

That's probably because you used 'print' which uses 'tostring' internally. Here, try this one:


local s, e = pcall(function()
  error({test=123})
end)

print(e.test)

Anyway, good luck with exception types! :)/>
Lignum #7
Posted 12 February 2015 - 02:24 PM
That's probably because you used 'print' which uses 'tostring' internally. Here, try this one:


...

Anyway, good luck with exception types! :)/>

That's nil for me on CCEmuRedux and Minecraft. Are you perhaps using CCLite? Because strange things happen on CCLite.

Anyway, I've added them! Redownload the paste to get the update. Check the OP for example usage.

EDIT: You also no longer have to call exceptional.init and exceptional.cleanup. It's done automatically now.
Edited on 12 February 2015 - 03:03 PM
ElvishJerricco #8
Posted 12 February 2015 - 07:11 PM
Oh this could be fantastic with LuaLua. Having exception classes should be sweet. Could I include this with LuaLua? I could even add syntax similar to the table / string call syntax to make this even nicer considering the simplified anonymous function syntax already there.


try \()
    throw ||MyException new| initWithMessage:"error!"|
end:LuaError \(e)
    -- ...
end:MyException \(e)
    -- ...
end
Lignum #9
Posted 12 February 2015 - 07:28 PM
Oh this could be fantastic with LuaLua. Having exception classes should be sweet. Could I include this with LuaLua? I could even add syntax similar to the table / string call syntax to make this even nicer considering the simplified anonymous function syntax already there.

Sure! I actually did want to make this for LuaLua at first because of its simplicity but decided to go with Lua to target a wider audience. But if you want to make a LuaLua version, I'm not stopping you. Good luck!
MKlegoman357 #10
Posted 12 February 2015 - 07:37 PM
Oh, custom exceptions look really really interesting. Good job! The LuaLua example also looks very nice.

BTW, about the 'error', looks like CC uses 'tostring' in 'error' but the actual Lua 5.1 doesn't and lets you pass any parameter. I tested that with LÖVE 2D, offline Lua 5.1 interactive interpreter (Ubuntu, apt-get package) and some online Lua 5.1 interpreters and they all allowed to pass any parameters to 'error'. I either am missing something here or the 'error' implementation in LuaJ is wrong. Could anyone confirm that?
Lignum #11
Posted 13 February 2015 - 07:48 PM
BTW, about the 'error', looks like CC uses 'tostring' in 'error' but the actual Lua 5.1 doesn't and lets you pass any parameter. I tested that with LÖVE 2D, offline Lua 5.1 interactive interpreter (Ubuntu, apt-get package) and some online Lua 5.1 interpreters and they all allowed to pass any parameters to 'error'. I either am missing something here or the 'error' implementation in LuaJ is wrong. Could anyone confirm that?

I seem to have figured it out…

print(type(({pcall(error, 1, 0)})[2]))

In ComputerCraft that code prints "string".
In Lua 5.1 it prints "number".

So yes, LuaJ's implementation is wrong. This is also backed up by this (see bottom).
ElvishJerricco #12
Posted 13 February 2015 - 11:19 PM
Yea I started experimenting, and because of the way LuaLua objects work, they can't be properly thrown by this. Which is unfortunate. It'd be perfectly fine if not for this LuaJ bug =/