forth-stuff/CoreHelpers.tl

198 lines
4.9 KiB
Plaintext

local ds = require("DataStructures")
local Dictionary, Stack, WordInfo, Environment = ds.Dictionary, ds.Stack, ds.WordInfo, ds.Environment
local Pointer = ds.Pointer
local InputStream = require("InputStream")
local CoreHelpers = {}
function CoreHelpers.defineWord(dict: Dictionary, str: string, func: function(Environment, ...: any): any..., imm: boolean)
local info = WordInfo:new(func, imm)
dict:define(str, info)
end
function CoreHelpers.standardInputRefill(): string
local input = io.read().."\n"
return input
end
function CoreHelpers._oneReadRefill(str: string): function(): string
local alreadyRead: boolean = false
return function(): string
if not alreadyRead then
alreadyRead = true
return str
else
return ""
end
end
end
function CoreHelpers._fileRefill(fname: string): function(): string
local f = assert(io.open(fname, "r"))
return function(): string
local chunk = f:read(2^3)
if not chunk then chunk = "" end
return chunk
end
end
function CoreHelpers.fileStream(fname: string): InputStream
local istream = InputStream:new(CoreHelpers._fileRefill(fname))
return istream
end
function CoreHelpers.oneReadInputStream(str: string): InputStream
local iStream = InputStream:new(CoreHelpers._oneReadRefill(str))
return iStream
end
function CoreHelpers.areNumbers(a: any, b: any): boolean
return a is number and b is number
end
function CoreHelpers.getActiveDataStack(state: Environment): Stack
return state.activeDataStack
end
function CoreHelpers.isNumber(token: string): boolean
if tonumber(token) ~= nil then
return true
else
return false
end
end
function CoreHelpers.isWhitespace(chr: string): boolean
return (chr == " " or
chr == "\t" or
chr == "\r" or
chr == "\n" or
chr == "\v" or
chr == "\f")
end
function CoreHelpers.skipWhitespace(state: Environment)
local chr = state.activeInputStream:curr()
while (CoreHelpers.isWhitespace(chr)) do
state.activeInputStream:next()
chr = state.activeInputStream:curr()
end
end
function CoreHelpers.popTwoOperands(state: Environment): any, any
local stack = CoreHelpers.getActiveDataStack(state)
local b: any = stack:pop()
local a: any = stack:pop()
return a, b
end
function CoreHelpers.parseToken(state: Environment): string | nil
local token: string | nil = ""
local chr: string | nil = ""
if not state.activeInputStream:curr() then return nil end
while(not CoreHelpers.isWhitespace(chr) and chr ~= nil) do
token = token..(chr as string)
chr = state.activeInputStream:next()
end
return token
end
function CoreHelpers.reset(env: Environment)
env.instructionPointer.index = 0 -- will get incremented after this instruction
end
function CoreHelpers.ret(env: Environment)
local retAddr = env.returnStack:pop() as Pointer
env.instructionPointer = retAddr
end
function CoreHelpers.makeCall(body: {function(Environment)}): function(Environment)
return function(e: Environment)
e.returnStack:push(e.instructionPointer)
e.instructionPointer = Pointer:new(body, 0)
end
end
function CoreHelpers.compile(env: Environment)
local stack = env.activeDataStack
local f = stack:pop() as function(Environment)
table.insert(env.currentDefinition, f)
end
function CoreHelpers.literal(env: Environment)
local stack = env.activeDataStack
local val = stack:pop()
local f = function(e: Environment)
local s = e.activeDataStack
s:push(val)
end
table.insert(env.currentDefinition, f)
end
function CoreHelpers.noop(_: Environment)
return
end
function CoreHelpers.postpone(e: Environment)
CoreHelpers.noop(e)
end
function CoreHelpers.execute(env: Environment)
local stack = CoreHelpers.getActiveDataStack(env)
local func: function(Environment) = stack:pop() as function(Environment)
func(env)
end
function CoreHelpers.recNumber(env: Environment)
local dataStack = CoreHelpers.getActiveDataStack(env)
local token = dataStack:pop() as string
if CoreHelpers.isNumber(token) then
-- number
dataStack:push(tonumber(token))
-- interpret
dataStack:push(CoreHelpers.noop)
-- compile
dataStack:push(CoreHelpers.literal)
-- immediate
dataStack:push(CoreHelpers.literal)
-- return success
dataStack:push(true)
return
end
dataStack:push(token)
dataStack:push(false)
end
function CoreHelpers.recWord(env: Environment)
local dataStack = CoreHelpers.getActiveDataStack(env)
local token = dataStack:pop() as string
for _, dictionary in ipairs(env.dictionaries) do
local wordinfo = dictionary:lookup(token)
if wordinfo then
-- XT
dataStack:push((wordinfo as WordInfo).func)
-- interpret
dataStack:push(CoreHelpers.execute)
-- compile
if (wordinfo as WordInfo).immediate then
dataStack:push(CoreHelpers.execute)
else
dataStack:push(CoreHelpers.compile)
end
-- immediate
dataStack:push(CoreHelpers.postpone)
-- return success
dataStack:push(true)
return
end
end
dataStack:push(token)
dataStack:push(false)
end
function CoreHelpers.ack(e: Environment)
io.write("ok\n")
end
return CoreHelpers