|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://angg.twu.net/SRF/srfx.lua.html
-- http://angg.twu.net/SRF/srfx.lua
-- (find-angg "SRF/srfx.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2021aug24
-- Based on Marc's srf.lua.
--
-- (defun e () (interactive) (find-angg "SRF/srfx.lua"))
-- (defun e1 () (interactive) (find-angg "SRF/srfx-interpreter.lua"))
-- (defun eb () (interactive) (find-angg "SRF/srfx-basics.lua"))
-- (defun e0 () (interactive) (find-srffile "ports/lua/srfish.lua"))
-- (defun ee () (interactive) (find-es "srf"))
--
-- «.throw» (to "throw")
-- «.loadstr» (to "loadstr")
-- «.Stack» (to "Stack")
-- «.tokenisation» (to "tokenisation")
-- «.interpreter» (to "interpreter")
-- «.entry» (to "entry")
-- «throw» (to ".throw")
--
Throw = Class {
type = "Throw",
__index = {
bool = function(_) error('logical value must be 0 or 1', 0) end,
brk = function() error('break', 0) end, -- todo
host = function(err) error('host interpretation failed: ' .. err, 0) end,
underflow = function() error('stack underflow', 0) end,
unknown = function(w) error('unknown word: ' .. w, 0) end,
},
}
throw = Throw {}
-- «loadstr» (to ".loadstr")
loadstr = -- load with environment
setfenv and function(s, env)
local fn, err = loadstring(s)
if fn then setfenv(fn, env) end
return fn, err
end
or function(s, env) return load(s, nil, nil, env) end
toBool = function(i)
if i == 0 then return false
elseif i == 1 then return true
else throw.bool(i) end
end
fromBool = function(b) return b and 1 or 0 end
copyTable = function(tbl)
local t = {}
for k, v in pairs(tbl) do t[k]=v end
return t
end
-- sorted = function(list)
-- local l = copyTable(list)
-- table.sort(l)
-- return l
-- end
trim = function(s)
return string.gsub(string.gsub(s, '^%s*', ''), '%s*$', '')
end
image = function(v)
if v == nil then return '(nil)'
elseif tonumber(v) then return v
else return quote(v) end
end
quote = function(s)
return "'" .. string.gsub(s, "'", "''") .. "'"
end
-- «Stack» (to ".Stack")
--
Stack = Class {
type = "Stack",
new = function () return Stack {} end,
__tostring = function(s) return s:image() end,
--
__index = { -- s: a stack object
depth = function(s) return #s end,
dup = function(s) s:push(s:peek(#s)) end,
over = function(s) s:push(s:peek(#s-1)) end,
push = table.insert,
peek = function(s, n)
if n <= 0 then throw.underflow() end
return s[n]
end,
pop = function(s)
local v = table.remove(s)
if v == nil then throw.underflow() end
return v
end,
reset = function(s) for i, v in ipairs(s) do s[i] = nil end end,
rot = function(s)
if #s < 3 then throw.underflow() end
s[#s], s[#s-1], s[#s-2] = s[#s-2], s[#s], s[#s-1]
end,
swap = function(s) s[#s], s[#s-1] = s:peek(#s-1), s:peek(#s) end,
image = function(s)
local img = '<' .. #s .. '> '
for _, v in ipairs(s) do img = img .. image(v) .. ' ' end
return img
end,
},
}
stack = Stack.new()
-- «tokenisation» (to ".tokenisation")
--
nextToken = function(phrase)
local stripped = string.gsub(phrase, '^%s+', '')
local first = string.sub(stripped, 0, 1)
if first == "'" or first == '"' then return parseString(first, stripped)
else return parseWord(stripped) end
end
parseString = function(quote, phrase)
local pattern = string.format('%s([^%s]*)%s(.*)', quote, quote, quote)
local i, word, w = 0, '', ''
while string.sub(phrase, 0, 1) == quote do
w, phrase = string.match(phrase, pattern)
if i > 0 then w = quote .. w end
word = word .. w
i = i + 1
end
return {kind='literal', word=word, rest=phrase}
end
parseWord = function(line)
local word, rest = string.match(line, "(%S+)(.*)")
local n = tonumber(word) -- todo: srf recognises binary, hex and octal
if n == nil then return {kind='term', word=word, rest=rest}
else return {kind='literal', word=n, rest=rest} end
end
-- «interpreter» (to ".interpreter")
-- (find-angg "SRF/srfx-interpreter.lua")
dofile "srfx-interpreter.lua"
-- (find-lua51manual "#pdf-setmetatable")
make_interpreter = function ()
return {
vocab = {},
stack = Stack.new(),
-- prims = interpreter.primitives,
-- aux = interpreter.auxiliary,
prims = interpreter_primitives,
aux = interpreter_auxiliary,
}
end
interpreter = {
new = function()
local mt = { __index = interpreter__index }
local t = setmetatable(make_interpreter(), mt)
-- local t = setmetatable(make_interpreter(), interpreter)
-- interpret the preamble (final line must end in a newline)
for line in string.gmatch(interpreter.preamble, "(.-)\n") do
t:doline(line)
end
return t
end,
auxiliary = interpreter_auxiliary, -- functions used by a subset of primitives
primitives = interpreter_primitives,
preamble = interpreter_preamble,
__index = interpreter__index,
}
-- «entry» (to ".entry")
terp = interpreter.new()
repl = function()
for line in io.lines() do
terp:doline(line)
end
end
-- arg = arg or {}
--
-- if arg[1]
-- then terp:doline(arg[1])
-- else repl()
-- end
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "srfx.lua"
PPV(terp.prims)
PPV(terp.vocab)
PPV(myterp.vocab)
myterp:dopreamble()
PPV(myterp.vocab)
myterp:repl()
'hello' 'world'
10 20
.s
: square dup *
5 square .
'myterp.STOP = 1' host
see 2swap
'2swap' expand .
'print "HELLO"' host
'PPV(interpreter_primitives)' host
'os.exit()' host
repl()
--]]
--[[
* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
./srfish.lua ''
./srfish.lua '1 2 + .'
./srfish.lua
'print "HELLO"' host
'os.exit()' host
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
arg = {""}
dofile "srfish.lua"
terp:doline '1 2 + .'
--]]
-- Local Variables:
-- coding: utf-8-unix
-- End: