Lua load function seems to expect a second argument. Why?

SDK 1.9.1 Mac

Per the docs, the entire Lua 5.4 API should be available.

I'm having trouble calling the load function.

Code sample inspired by this stackoverflow answer:

local func, err = load("return function(a,b) return a+b end")
if func then
  local ok, add = pcall(func)
  if ok then
    print(add(2,3))
  else
    print("Execution error:", add)
  end
else
  print("Compilation error:", err)
end

This should print 5, but this is the Simulator console output:

level.lua:32: bad argument #2 to 'load' (number expected, got no value)
stack traceback:
	[C]: in function 'load'
	level.lua:32: in function 'LoadFile'
	main.lua:6: in function 'startGame'
	[C]: in function 'xpcall'
	main.lua:10: in main chunk
main.lua:15: level.lua:32: bad argument #2 to 'load' (number expected, got no value)
stack traceback:
	[C]: in function 'error'
	main.lua:15: in main chunk
main.lua:15: level.lua:32: bad argument #2 to 'load' (number expected, got no value)
stack traceback:
	[C]: in function 'error'
	main.lua:15: in main chunk
main.lua:15: level.lua:32: bad argument #2 to 'load' (number expected, got no value)
stack traceback:
	[C]: in function 'error'
	main.lua:15: in main chunk

Argument #2 should be optional, and also not be a number but a string (parameter chunkname)
Is this a bug in the SDK?

It also seems that io.open(path,"r") from Lua cannot be used. I understand this, given that you don't want to expose the entire filesystem to a game. But I'd say the Inside Playdate docs are misleading because it mentions thatthe entire Lua Api should be available

Yes, sorry about that messaging. As far as I know we support the full set of Lua language features, but not every library or API that comes with it. We'll try to clarify this in the docs.

2 Likes

That would be nice, thanks.

What can you tell me about the load function specifically?

I don't think load() is supported in the SDK because the runtime is using only the VM and not the precompiler which translate Lua into byte code. This is mainly for performance reason.

But you can use playdate.file.load() to load a Lua file that was compiled by pdc
https://sdk.play.date/1.9.1/#f-file.load

Can you explain a bit more the reason why you would like to use load()?

In fact, I think it could be a good decision to not support load from a security standpoint.

My use case is very specific. I'm porting an older Lua project. Loading a level file that contains parts Lua tables and parts proprietary format. I'm parsing the proprietary format myself and would like to load the Lua bits.

The solution for me is to simply split this to multiple files, and convert the Lua tables to json using json.encode()

A nice-to-have would be a binary format for level data maybe. The json objects are huge for tile based
level data

Out of curiosity I would be interested in a code sample for file.load and how to create those pdz files

I would suggest to not use json but instead keep using lua. This would be more faster to load.
For some project where I actually parse files, I sometimes export the result as Lua file that I can load later because it is so much faster to do so (https://devforum.play.date/t/a-list-of-helpful-libraries-and-code/221/72). I would imagine that using Lua file would even be faster than binary file actually (that you would still need to read and convert as Lua table anyway).

If a lua file in your project is not called by any other file using import, pdc will save it as a pdz file (which is mostly Lua byte code) and you can load it using playdate.file.load() or playdate.file.run()

Here an example code where I load a pdz file.
https://devforum.play.date/t/splitting-a-game-into-several-functional-binaries-nics-plugin-manager/1387/5

Excellent. The sample was helpful to figure out whether I needed the relative filepath with extension. Thanks!

In the link you posted, you already mention a function that can save a lua table to a file. If you want to go from some static jsons to lua, this online tool might help: JSON Lua table converter - MAGEDDO

I realize that this is an old post, but if it helps someone else out, I figured out that the second parameter is the length of the string that you're passing in. I'm starting with simple Javascript code and need to transform it to Lua and execute it. So I'm starting with something like this:
"function nextCard() {return "322";}"

and I have to transform the string to Lua:

"return function() return true end"

And then use this to execute it:

function Evergreen:dynamicExecuteScript(script)
   local length = #script
   local func, err = load(script, length)
   if func ~= nil then
	  local ok, myFunc = pcall(func)
	  if ok then
		 local result = myFunc()
		 return result
	  end
   end

   return nil
end

Oops, I didn't realize that worked in the simulator. We include the compiler part of the Lua runtime in the simulator so that you can enter and run code from the console, but I should have disabled it in the load command because that's not available on the device. We don't have a lot of room for the firmware, so we need to trim wherever we can.

Just a heads up, this will stop working in a future update!

I was afraid you might say something like that if I mentioned it, but I'd prefer to know sooner than later. If you ever make a PD2, this would be very high on my wishlist of api's to include. Or a simple javascript interpreter. Either one. Thanks.

1 Like