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: