Luawe the Wayfarer Engine's scripting language All pages

When something goes wrong

Every script has mistakes in it at some point. Luawe tries to say plainly what is wrong and where. This page shows the kinds of mistake there are, how to read what the game says about them, and how a script can deal with trouble itself.

Mistakes the editor sees

Some mistakes show before the level runs. The editor looks a script over as you type.

A red line marks text that is not Luawe at all: a missing end, a bracket that is never closed, a word in the wrong place. A script with a red line cannot run. The message, under the mouse and below the box, says what was expected:

It prints

the 'if' on line 3 is never closed: it needs 'end' (found the end of the script)

A yellow line marks something that is Luawe but looks wrong, most often a name that nothing gives a value to. That is nearly always a typing mistake, and the editor guesses what was meant:

It prints

'prnt' has no value: nothing in this script gives it one (did you mean 'print'?)
'things' has nothing called 'fnd' (did you mean 'find'?)

A script with yellow lines does run. Whether it works is another matter.

Mistakes that show while the level runs

Other mistakes only show when the line is reached. The task stops there, and the script output says what happened in red, with the script's name and the line:

It prints

door.luawe:12: attempt to index a nil value (variable 'door') (reading 'tween')

Click the line in the script output to go to that line of the script.

Only the task that hit the mistake stops. The level carries on, and so do the other scripts and every other task of this one.

Reading the messages

The script output saysIt means
attempt to index a nil value (variable 'door')door is nil, and the script asked it for something (door.x, door:tween()). Often things.find did not find the thing: check its name
attempt to call a nil value (global 'prnt')There is no function called that. Look for a typing mistake
attempt to do arithmetic on a nil valueA value in a sum is missing
attempt to do arithmetic on a string valueText was used as a number: use tonumber()
attempt to compare number with string< and > need two numbers or two strings
attempt to concatenate a nil valueA value joined with .. is missing
this thing is goneThe thing was destroyed, or its time was up. Ask thing.exists first
this task ran for too long without waitingA loop went on and on. Put a wait() in it

Saying that something is wrong

error stops the task with a message of your own. assert does so when a value is false or nil, and otherwise gives the value back, which makes it a good guard:

local door = assert(things.find("door"), "this script needs a thing called door")
door.alpha = 0.5

If the level has no thing called door, the script output says so in your words, instead of failing later with something harder to read.

warn writes a yellow line to the script output and carries on. Use it for what is odd but not fatal.

Catching a mistake

pcall calls a function and catches whatever goes wrong inside it. It gives true and the function's results, or false and the error:

local function risky(n)
    if n > 2 then
        error("too big: " .. n)
    end
    return n * 10
end

print(pcall(risky, 1))
print(pcall(risky, 5))

It prints

true 10
false door.luawe:3: too big: 5

The error is the message, with where it happened put before it. error(message, 0) leaves the place out.

An error need not be text. Any value can be thrown, and pcall hands back that very value:

local ok, problem = pcall(function()
    error({ code = 7, reason = "no key" })
end)
print(ok, problem.code, problem.reason)

It prints

false 7 no key

xpcall is pcall with a function that looks at the error first, for example to add where the script was:

local ok, report = xpcall(function()
    local missing = nil
    return missing.x
end, function(message)
    return "caught: " .. message
end)
print(ok, report)

It prints

false caught: door.luawe:3: attempt to index a nil value (variable 'missing') (reading 'x')

Finding out what a script does

There is no debugger. The tools are the ones every programmer uses first:

  • print the values you are unsure of. print("got here", lives, door) costs nothing and answers most questions. A thing prints as what it is, for example block "door" #3.
  • type(value) says what kind of value something is.
  • debug.traceback() gives the lines of the functions that called each other to get to where the script is now, as text to print.
local function inner()
    print(debug.traceback("how did we get here?"))
end
local function outer()
    inner()
end
outer()

It prints

how did we get here?
    door.luawe:2: in function 'inner'
    door.luawe:5: in function 'outer'
    door.luawe:7: in the script

In a test play, what scripts print also shows in a corner of the screen for a few seconds, so you can watch a value while playing.

Next: things, the cube and the camera.