|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://angg.twu.net/SRF/srfx-interpreter.lua.html
-- http://angg.twu.net/SRF/srfx-interpreter.lua
-- (find-angg "SRF/srfx-interpreter.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- (defun es () (interactive) (find-angg "SRF/srfx.lua"))
-- (defun ei () (interactive) (find-angg "SRF/srfx-interpreter.lua"))
-- «.interpreter_auxiliary» (to "interpreter_auxiliary")
-- «.interpreter_primitives» (to "interpreter_primitives")
-- «.interpreter_preamble» (to "interpreter_preamble")
-- «.interpreter__index» (to "interpreter__index")
-- «.tests» (to "tests")
dofile "srfx-basics.lua"
-- «interpreter_auxiliary» (to ".interpreter_auxiliary")
interpreter_auxiliary = { -- functions used by a subset of primitives
loop = function(terp, push_index)
local n, s = terp:pop(), terp:pop()
for i = 0, n-1 do
if push_index then terp:push(i) end
local status, err = pcall(terp.dophrase, terp, s)
if not status then -- break or rethrow
if err == 'break' then break else error(err, 0) end
end
end
end,
}
-- «interpreter_primitives» (to ".interpreter_primitives")
interpreter_primitives = { -- o: an interpreter object
['*'] = function(o) o:push(o:pop() * o:pop()) end,
['**'] = function(o) o.stack:swap(); o:push(o:pop() ^ o:pop()) end,
['+'] = function(o) o:push(o:pop() + o:pop()) end,
['-'] = function(o) o.stack:swap(); o:push(o:pop() - o:pop()) end,
['/'] = function(o) o.stack:swap(); o:push(o:pop() / o:pop()) end,
['//'] = function(o) o.stack:swap(); o:push(o:pop() % o:pop()) end,
['.'] = function(o) print(o:pop()) end,
['.s'] = function(o) print(o.stack) end,
['.vocab'] = function(o)
local all, max = {}, 0
for word, _ in pairs(o.vocab) do
max=math.max(max, #word)
table.insert(all, word)
end
local fmt = string.format('%%-%ds %%s', max+1)
for _, word in ipairs(sorted(all)) do
print(string.format(fmt, word, trim(o.vocab[word])))
end
end,
['<'] = function(o) o:push(fromBool(o:pop() > o:pop())) end,
['<='] = function(o) o:push(fromBool(o:pop() >= o:pop())) end,
['<>'] = function(o) o:push(fromBool(o:pop() ~= o:pop())) end,
['='] = function(o) o:push(fromBool(o:pop() == o:pop())) end,
['>'] = function(o) o:push(fromBool(o:pop() < o:pop())) end,
['>='] = function(o) o:push(fromBool(o:pop() <= o:pop())) end,
['and'] = function(o)
o:push(fromBool(toBool(o:pop()) and toBool(o:pop())))
end,
['break'] = function(o) throw.brk() end,
['clear'] = function(o) o.vocab[o:pop()]=nil end,
['concat'] = function(o) o.stack:swap(); o:push(o:pop() .. o:pop()) end,
['defined?'] = function(o) o:push(fromBool(o.vocab[o:pop()] ~= nil)) end,
['do'] = function(o) o:dophrase(o:pop()) end,
['drop'] = function(o) o.stack:pop() end,
['dup'] = function(o) o.stack:dup() end,
['either'] = function(o)
if not toBool(o:pop()) then o.stack:swap() end
o:pop()
end,
['fetch'] = function(o) o:push(o.vocab[o:pop()] or '') end,
['host'] = function(o)
local env = copyTable(_ENV or _G); env.self = o
local fn, err = loadstr(o.stack:pop(), env)
if not fn then throw.host(err) end
fn()
end,
['not'] = function(o) o:push(fromBool(not toBool(o:pop()))) end,
['or'] = function(o)
o:push(fromBool(toBool(o:pop()) or toBool(o:pop())))
end,
['over'] = function(o) o.stack:over() end,
['quote'] = function(o) o:push(quote(o:pop())) end,
['repeat'] = function(o) o.aux.loop(o) end,
['repeat#'] = function(o) o.aux.loop(o, true) end,
['reverse'] = function(o) o:push(string.reverse(o:pop())) end,
['rot'] = function(o) o.stack:rot() end,
['sentence'] = function(o) o:push(o.line); o.line = '' end,
['store'] = function(o) o.vocab[o:pop()]=o:pop() end,
['swap'] = function(o) o.stack:swap() end,
['trim'] = function(o) o:push(trim(o:pop())) end,
['version'] = function(o) o:push(_VERSION) end,
['word'] = function(o)
local token = nextToken(o.line)
o.line = token.rest
o:push(token.word)
end,
['words'] = function(o)
local all, seen = {}, {}
for _, dict in ipairs({o.prims, o.vocab}) do
for word, _ in pairs(dict) do
if not seen[word] then
seen[word]=true
table.insert(all, word)
end
end
end
print(table.concat(sorted(all), ' '))
end,
}
-- «interpreter_preamble» (to ".interpreter_preamble")
--
interpreter_preamble = [[
'word sentence swap store' ':' store
: if either do
: when '' swap if
: unless not when
: until 'break' swap when
: while 'break' swap unless
: nip swap drop
: tuck swap over
: shell 'os.execute(self:pop())' host
: value swap quote swap store
: drops 'drop' swap repeat
: inc 1 +
: dec 1 -
]]
-- «interpreter__index» (to ".interpreter__index")
--
interpreter__index = {
doword = function(terp, word, kind)
if kind == 'literal' then terp.stack:push(word)
elseif terp.vocab[word] then terp:dophrase(terp.vocab[word])
elseif terp.prims[word] then terp.prims[word](terp)
else throw.unknown(word) end
end,
dophrase = function(terp, phrase, top)
while string.match(phrase, '%S') do
local token = nextToken(phrase); phrase = token.rest
if top then terp.line = phrase end
terp:doword(token.word, token.kind)
if top then phrase = terp.line end
end
end,
doline = function(terp, line) -- the toplevel
local status, err = pcall(terp.dophrase, terp, line, 1)
if not status then
print('[' .. err .. ']')
if terp.stack:depth() > 0 then
print('stack was: ' .. terp.stack:image())
end
terp.stack:reset()
end
end,
pop = function(terp) return terp.stack:pop() end,
push = function(terp, v) return terp.stack:push(v) end,
}
-- ___ _ _
-- |_ _|_ __ | |_ ___ _ __ _ __ _ __ ___| |_ ___ _ __
-- | || '_ \| __/ _ \ '__| '_ \| '__/ _ \ __/ _ \ '__|
-- | || | | | || __/ | | |_) | | | __/ || __/ |
-- |___|_| |_|\__\___|_| | .__/|_| \___|\__\___|_|
-- |_|
--
Interpreter = Class {
type = "Interpreter",
new = function (T) return Interpreter(T or {}) end,
newindep = function ()
return Interpreter.new { vocab = {}, stack = Stack.new() }
end,
__index = over(interpreter__index) {
aux = interpreter_auxiliary,
prims = interpreter_primitives,
stack = Stack.new(),
vocab = {},
dolines = function (t, bigstr)
for _,line in ipairs(splitlines(bigstr)) do
t:doline(line)
end
return t
end,
dopreamble = function (t)
t:dolines(interpreter_preamble)
return t
end,
repl = function (t)
t.STOP = nil
while not(t.STOP) do
local line = io.read()
t:doline(line)
end
end,
},
}
-- «tests» (to ".tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "srfx-interpreter.lua"
terp = Interpreter.new():dopreamble()
PPV(terp.vocab)
= terp.vocab.square
interpreter_primitives['setprim0'] =
function(o)
local body, name = o.stack:pop(), o.stack:pop()
local f = expr("function(o) "..body.."\n end")
interpreter_primitives[name] = f
end
terp:repl()
'hello' 'world'
10 20
.s
: square dup *
5 square .
"\n" .
'print("a\nb")' host
'push42' 'o.stack:push(42)' setprim0
push42 .
: prim: word sentence setprim0
prim: push43 o.stack:push(43)
push43 .
'terp.STOP = 1' host
= terp.vocab.square
--]]
-- Local Variables:
-- coding: utf-8-unix
-- End: