REPL раскрывается как Read—Eval—Print Loop. Вводишь код — он тут же исполняется, результат показывается.
while true do
io.write("lua> ")
local input = io.read("*l") -- <1>
if not input then -- <2>
os.exit()
end
local chunk, reason = load("return " .. input, "=stdin", "t") -- <3>
if not chunk then -- <4>
chunk, reason = load(input, "=stdin", "t")
end
if not chunk then -- <5>
io.stderr:write("Syntax error: " .. reason .. "\n")
else
local result = table.pack(xpcall(chunk, debug.traceback)) -- <6>
local success = table.remove(result, 1)
result.n = result.n - 1
if not success then
io.stderr:write("Runtime error: " .. result[1] .. "\n")
elseif result.n > 0 then -- <7>
print(table.unpack(result, 1, result.n))
end
end
end
Комментарии:
io.read("*l")
читает одну строку без \n
в конце.Возвращается nil
, если юзер нажмёт ^D
. Закрываемся.
load
грузит код в фукцию.
Здесь мы сначала пытаемся подставить в начало return
. Это обрабатывает код
типа 20 * math.log(math.sqrt(10), 10)
— то есть все выражения.
Значение "=stdin"
используется для подстановки в сообщения об ошибках:
> load([[error("test")]], "=test", "t")()
test:1: test
stack traceback:
[C]: in function 'error'
test:1: in main chunk
(...tail calls...)
[C]: in ?
Если load
вернуло ошибку, был дан некорректный синтаксис. Так как добавили
return
сначала, ошибка могла возникнуть от этого. Например, если ввели код
вроде pi = 3
— все стейтменты.
Пробуем скомпилировать без return
.
Если и теперь не скомпировалось, то во введённом коде синтаксическая ошибка, о чём мы пишем.
Тут два момента.
xpcall
выполняет функцию (скомпилированный код) так, что при ошибке
программа не крашится, а вызывает debug.traceback
для получения
трейсбэка. Мы его потом напишем.
table.pack
используем вместо {}
, чтобы ловить nil
в выхлопных
значениях функции. Эта функция записывает в таблицу число всех элементов,
ей переданных: table.pack(nil, nil, nil).n == 3
.
Если код (pi = e
) не вернул какого-либо значения, даже nil
, то result.n
будет равен нулю. Тогда мы ничего не пишем.
Результат:
$ lua5.3 repl.lua
lua> 1, 2
1 2
lua> nil, 2
nil 2
lua> nil, nil, nil, 4, nil, nil
nil nil nil nil 4 nil
lua> print("Hello!")
Hello!
lua> blah
nil
lua> synt@x 3rr0r
Syntax error: stdin:1: syntax error near '@'
lua> runtimeError()
Runtime error: stdin:1: attempt to call a nil value (global 'runtimeError')
stack traceback:
stdin:1: in main chunk
[C]: in function 'xpcall'
repl.lua:24: in main chunk
[C]: in ?
lua> os.exit()
table.pack
и операторе #
на примере REPL:
2019-06-12, fingercomp, cc-ru.gitlab.iopcall
и load
в Lua:
2018-08-07, Fingercomp, gist.gitlab.io