[SOLVED] Handling error exceptions for assert(loadstring(str))() ?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
unixfreak
Citizen
Posts: 69
Joined: Thu Oct 15, 2015 6:25 am
Location: Bristol, UK
Contact:

[SOLVED] Handling error exceptions for assert(loadstring(str))() ?

Post by unixfreak » Tue Aug 14, 2018 8:54 pm

I am trying to add scriptable lua to a console as part of a game, for example to change variables quickly or run custom lua code to edit levels etc.

I have figured out i can use something like this:

Code: Select all

local out = assert(loadstring(console.command))()
Where the console uses text input to supply the console.command variable. Eg; User types some lua code into the console, when they press return, the above code line will execute.

This allows me to enter commands directly into the game whilst it is running, such as:

Code: Select all

world.gravity = 2300
Where world.gravity is a variable within the actual love2d project.
And also to help modify levels very fast, being able to type actual lua code, for example;

Code: Select all

for _, e in (world.enemies) do editor:remove(e) end
Essentially this is being run as;

Code: Select all

assert(loadstring("world.gravity = 2300"))()
This works fine, however, if there is a syntax error... the entire love2d application crashes to the blue error screen. How can i stop this from happening so i can instead print "error" to the console instead of crashing the entire program?

For context; This is what i am trying to achieve; https://i.imgur.com/mEfBQYn.jpg The lines which start with DEBUG are the commands that were entered into the in-game console. Here's the project/file which i've added this to: https://github.com/Jigoku/boxclip/blob/ ... e.lua#L115

The problem is that i cannot find a way to stop the game crashing if invalid syntax is entered. Does anyone know if there is a way to do this?
Last edited by unixfreak on Tue Aug 14, 2018 9:55 pm, edited 3 times in total.

User avatar
pgimeno
Party member
Posts: 1495
Joined: Sun Oct 18, 2015 2:58 pm

Re: Handling error exceptions for assert(loadstring(str))() ?

Post by pgimeno » Tue Aug 14, 2018 9:19 pm

Looks like a job for pcall.
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

User avatar
unixfreak
Citizen
Posts: 69
Joined: Thu Oct 15, 2015 6:25 am
Location: Bristol, UK
Contact:

Re: Handling error exceptions for assert(loadstring(str))() ?

Post by unixfreak » Tue Aug 14, 2018 9:33 pm

pgimeno wrote:
Tue Aug 14, 2018 9:19 pm
Looks like a job for pcall.
Hi, thanks for replying. I previously looked up that function, but can't understand how i would use it here.
How would i go about using pcall for this snippet?

Code: Select all

local out = assert(loadstring(console.command))()
console:print(out)
I have tried something such as:

Code: Select all

local out = pcall(assert(loadstring(console.command))())
				
if out then
	console:print(out)
else
	console:print("ERROR: invalid syntax!")
end
But i get:

Code: Select all

Error: console.lua:115: bad argument #1 to 'pcall' (value expected)
stack traceback:
	[string "boot.lua"]:637: in function <[string "boot.lua"]:633>
	[C]: in function 'pcall'
	console.lua:115: in function 'keypressed'
	input.lua:35: in function <input.lua:31>
	[string "boot.lua"]:503: in function <[string "boot.lua"]:493>
	[C]: in function 'xpcall'

User avatar
unixfreak
Citizen
Posts: 69
Joined: Thu Oct 15, 2015 6:25 am
Location: Bristol, UK
Contact:

Re: Handling error exceptions for assert(loadstring(str))() ?

Post by unixfreak » Tue Aug 14, 2018 9:46 pm

Oh nevermind, i just got this working;

Code: Select all

local out = pcall(function() assert(loadstring(console.command))() end)
				
if out then 
	console:print(out)
else
	console:print("ERROR: invalid lua snytax!")
end
This works!
Thanks for reminding me of pcall, i gave up the other day trying to solve this, but misunderstood how to use it properly.

Solved i guess, thanks. :awesome:

User avatar
pgimeno
Party member
Posts: 1495
Joined: Sun Oct 18, 2015 2:58 pm

Re: Handling error exceptions for assert(loadstring(str))() ?

Post by pgimeno » Tue Aug 14, 2018 9:48 pm

You probably don't want to use assert, as that would need more layers of error handling. Try this:

Code: Select all

local fn, err = loadstring(console.command)
if not fn then
  console:print(err)
else
  local ok, result = pcall(fn)
  if not ok then
    -- There was an error, so result is an error. Print it out.
    console:print(result)
  elseif result then
    console:print(result)
  end
end
Before submitting I saw your post. That creates one extra function on the fly. I just discussed in another thread why that's best avoided, and the above method does just that. You can't avoid creating the function with the user code, but you can avoid creating the anonymous wrapper function around assert().
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

User avatar
unixfreak
Citizen
Posts: 69
Joined: Thu Oct 15, 2015 6:25 am
Location: Bristol, UK
Contact:

Re: Handling error exceptions for assert(loadstring(str))() ?

Post by unixfreak » Tue Aug 14, 2018 9:55 pm

By the way, i posted to soon about this being solved, whilst it didn't crash on invalid syntax, it did crash when the syntax was valid (something about expecting string/boolean error).

pgimeno wrote:
Tue Aug 14, 2018 9:48 pm
You probably don't want to use assert, as that would need more layers of error handling. Try this:

Code: Select all

local fn, err = loadstring(console.command)
if not fn then
  console:print(err)
else
  local ok, result = pcall(fn)
  if not ok then
    -- There was an error, so result is an error. Print it out.
    console:print(result)
  elseif result then
    console:print(result)
  end
end
Before submitting I saw your post. That creates one extra function on the fly. I just discussed in another thread why that's best avoided, and the above method does just that. You can't avoid creating the function with the user code, but you can avoid creating the anonymous wrapper function around assert().
I just tried your snippet, and that works perfectly, along with the extra information that shows the actual error message you would get from lua on the command line, which is a huge bonus. https://i.imgur.com/Ed3NmTs.png

Many thanks!

User avatar
pgimeno
Party member
Posts: 1495
Joined: Sun Oct 18, 2015 2:58 pm

Re: [SOLVED] Handling error exceptions for assert(loadstring(str))() ?

Post by pgimeno » Tue Aug 14, 2018 9:59 pm

Yeah, you missed returning the value for pcall: pcall(function() return assert(...

Edit: also, you missed the second argument, now that I look closer. The first argument is always a boolean. That was probably the problem.
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

User avatar
unixfreak
Citizen
Posts: 69
Joined: Thu Oct 15, 2015 6:25 am
Location: Bristol, UK
Contact:

Re: [SOLVED] Handling error exceptions for assert(loadstring(str))() ?

Post by unixfreak » Tue Aug 14, 2018 10:04 pm

pgimeno wrote:
Tue Aug 14, 2018 9:59 pm
Yeah, you missed returning the value for pcall: pcall(function() return assert(...

Edit: also, you missed the second argument, now that I look closer. The first argument is always a boolean. That was probably the problem.
Yeah, looking at that now, i see that is the case. Can't thank you enough for a solution. Cheers. :awesome:

User avatar
pgimeno
Party member
Posts: 1495
Joined: Sun Oct 18, 2015 2:58 pm

Re: [SOLVED] Handling error exceptions for assert(loadstring(str))() ?

Post by pgimeno » Tue Aug 14, 2018 10:44 pm

You're welcome. Now that I think about it, I've realized that that's only half-baked, as it only deals with one return value, without even distinguishing nil from false or from no value. In the console of Lua and LuaJIT that works perfectly:

Code: Select all

> return nil
nil
> return
> return false
false
> return 1, 2
1	2
A more complete solution that behaves more like the Lua console would be like this:

Code: Select all

local fn, err = loadstring(console.command)
if not fn then
  console:print(err)
else
  local result = {pcall(fn)}
  local ok = table.remove(result, 1)
  if not ok then
    console:print(result[1])
  else
    for i = 1, #result do
      result[i] = tostring(result[i])
    end
    console:print(table.concat(result, '\t')) -- well, tab handling isn't perfect in graphics mode but it does something
  end
end
(Disclaimer: not tested). Unfortunately that generates quite some single-use objects, but well. Of course, you can always just omit printing the return value and call it a day. Or for extra functionality, you could replace tostring() with inspect() to help debugging (after requiring inspect.lua)
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

Post Reply

Who is online

Users browsing this forum: No registered users and 8 guests