T wo T r:repl.lua
From LuaTeXWiki
--- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro>
---
--- Further hacked by others.
---
--- Permission is hereby granted, free of charge, to any person
--- obtaining a copy of this software and associated documentation
--- files (the "Software"), to deal in the Software without
--- restriction, including without limitation the rights to use, copy,
--- modify, merge, publish, distribute, sublicense, and/or sell copies
--- of the Software, and to permit persons to whom the Software is
--- furnished to do so, subject to the following conditions:
---
--- The above copyright notice and this permission notice shall be
--- included in all copies or substantial portions of the Software.
---
--- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
--- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
--- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
--- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
--- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
--- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
--- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
--- SOFTWARE.
---
--- This module implements the core functionality of a REPL.
--- repl() is the REPL.
--- quit() or exit() will terminate the REPL.
--- require("utils") or anything else you will want to use in the
--- REPL as a global, or they will not be visible.
--- Note: The REPL is NOT Unicode aware!
local repl_buffer = ""
local function gather_results(success, ...)
local n = select("#", ...)
return success, {n = n, ... }
end
local function detectcontinue(err)
-- Uses the compilation error to determine whether or not further input
-- is pending after the last line. That is, is this a fraction of a
-- statement.
-- Rather crude, but this seems to work.
return string.match(err, "'<eof>'$") or string.match(err, "<eof>$")
end
local function compilechunk(chunk)
-- If this is an expression, rather than a statement, we should
-- get a function, in f, to return the value of that expression.
local f, err = load("return " .. chunk, "REPL")
-- For statements (or fractions thereof).
if not f then
f, err = load(chunk, "REPL")
end
return f, err
end
local function displayresults(results)
-- @param results The results to display. The results are a table,
-- with the integer keys containing the results, and the "n" key
-- containing the highest integer key.
if results.n == 0 then return end
print(table.unpack(results, 1, results.n))
end
local function displayerror(err)
print(err)
end
local function handleline(line)
-- Evaluates a line of input, and displays return value(s).
local chunk = repl_buffer .. line
local f, err = compilechunk(chunk)
if f then
-- We have a (presumed) function. Try to call it, and display the
-- results, or error.
repl_buffer = ""
local success, results = gather_results(xpcall(f, function(...) return debug.traceback(...) end))
if success then
displayresults(results)
else
displayerror(results[1])
end
elseif detectcontinue(err) then
-- This is a (presumed) fraction of a statement?
repl_buffer = chunk .. "\n"
return 2
else
-- An error. Clear the buffer, so this does not keep happening.
repl_buffer = ""
displayerror(err)
end
return 1
end
local function prompt(level)
local prompt
if level == 1 then prompt=">>>" else prompt="..." end
io.write(prompt)
end
local function repl()
-- Run a REPL loop in a synchronous fashion.
print()
prompt(1)
for line in io.stdin:lines() do
if line == "quit()" then
break
end
if line == "exit()" then
break
end
local level = handleline(line)
prompt(level)
end
end
return {repl = repl}