forth-stuff/CoreWords.tl

214 lines
5.6 KiB
Plaintext

local ds = require("DataStructures")
local Dictionary, Stack, WordInfo, Environment = ds.Dictionary, ds.Stack, ds.WordInfo, ds.Environment
local helpers = require("CoreHelpers")
local areNumbers, getActiveDataStack, isNumber, isWhitespace= helpers.areNumbers, helpers.getActiveDataStack, helpers.isNumber, helpers.isWhitespace
local skipWhitespace, parseToken = helpers.skipWhitespace, helpers.parseToken
local popTwoOperands = helpers.popTwoOperands
local defineWord = helpers.defineWord
local ret = helpers.ret
local makeCall = helpers.makeCall
-- Mathematical operations
local function add(state: Environment)
local a, b = popTwoOperands(state)
if areNumbers(a,b) then
local c = (a as number) + (b as number)
getActiveDataStack(state):push(c)
else
error("invalid operands for add operation!")
end
end
local function sub(state: Environment)
local a, b = popTwoOperands(state)
if areNumbers(a, b) then
local c = (a as number) - (b as number)
getActiveDataStack(state):push(c)
else
error("invalid operands for sub operation!")
end
end
local function mul(state: Environment)
local a, b = popTwoOperands(state)
if areNumbers(a, b) then
local c = (a as number) * (b as number)
getActiveDataStack(state):push(c)
else
error("invalid operands for mul operation!")
end
end
local function div(state: Environment)
local a, b = popTwoOperands(state)
if areNumbers(a, b) then
local c = (a as number) / (b as number)
getActiveDataStack(state):push(c)
else
error("invalid operands for div operation!")
end
end
local function dup(state: Environment)
local stack = getActiveDataStack(state)
local top = stack:pop()
stack:push(top)
stack:push(top)
end
local function swap(state: Environment)
local stack = getActiveDataStack(state)
local a, b = popTwoOperands(state)
stack:push(b)
stack:push(a)
end
local function rot(state: Environment)
local stack = getActiveDataStack(state)
local c, b, a= stack:pop(), stack:pop(), stack:pop()
stack:push(b)
stack:push(c)
stack:push(a)
end
local function drop(state: Environment)
local stack = getActiveDataStack(state)
stack:pop()
end
local function over(state: Environment)
local stack = getActiveDataStack(state)
local b, a = stack:pop(), stack:pop()
stack:push(a)
stack:push(b)
stack:push(a)
end
-- I/O operations
local function dot(state: Environment)
local out = state.activeDataStack:pop()
print(out)
end
local function twoDup(state: Environment)
over(state)
over(state)
end
local function twoSwap(state: Environment)
local stack = getActiveDataStack(state)
local d, c, b, a = stack:pop(), stack:pop(), stack:pop(), stack:pop()
stack:push(c)
stack:push(d)
stack:push(a)
stack:push(b)
end
local function twoOver(state: Environment)
local stack = getActiveDataStack(state)
local d, c, b, a = stack:pop(), stack:pop(), stack:pop(), stack:pop()
stack:push(a)
stack:push(b)
stack:push(c)
stack:push(d)
stack:push(a)
stack:push(b)
end
local function nip(state: Environment)
local stack = getActiveDataStack(state)
local b, _ = stack:pop(), stack:pop()
stack:push(b)
end
local function tuck(state: Environment)
swap(state)
over(state)
end
local function roll(state: Environment)
local stack = getActiveDataStack(state)
local u = stack:pop()
local bufferStack = Stack:new()
if u is number then
local v = u as number
while(v > 0) do
local item = stack:pop()
bufferStack:push(item)
v = v - 1
end
local newTop = stack:pop()
local x = (u as number)
while(x > 0) do
local item = bufferStack:pop()
stack:push(item)
x = x - 1
end
stack:push(newTop)
else
error("u is not a number")
end
end
local function getExecutionToken(state: Environment)
local stack = getActiveDataStack(state)
skipWhitespace(state)
local name: string = parseToken(state)
for _, dictionary in ipairs(state.dictionaries) do
local wordinfo = dictionary:lookup(name)
if wordinfo then
stack:push((wordinfo as WordInfo).func)
break
end
end
end
local function execute(state: Environment)
local stack = getActiveDataStack(state)
local func: function(Environment) = stack:pop() as function(Environment)
func(state)
end
local CoreWords = Dictionary:new()
local addInfo = WordInfo:new(add, false)
local subInfo = WordInfo:new(sub, false)
local mulInfo = WordInfo:new(mul, false)
local divInfo = WordInfo:new(div, false)
local dotInfo = WordInfo:new(dot, false)
local dupInfo = WordInfo:new(dup, false)
local swapInfo = WordInfo:new(swap, false)
local rotInfo = WordInfo:new(rot, false)
local dropInfo = WordInfo:new(drop, false)
local overInfo = WordInfo:new(over, false)
local twoDupInfo = WordInfo:new(twoDup, false)
local twoSwapInfo = WordInfo:new(twoSwap, false)
local twoOverInfo = WordInfo:new(twoOver, false)
local nipInfo = WordInfo:new(nip, false)
defineWord(CoreWords, "TUCK", tuck, false)
defineWord(CoreWords, "ROLL", roll, false)
defineWord(CoreWords, "'", getExecutionToken, false)
defineWord(CoreWords, "EXECUTE", execute, false)
CoreWords:define("+", addInfo)
CoreWords:define("-", subInfo)
CoreWords:define("*", mulInfo)
CoreWords:define("/", divInfo)
CoreWords:define(".", dotInfo)
CoreWords:define("DUP", dupInfo)
CoreWords:define("SWAP", swapInfo)
CoreWords:define("ROT", rotInfo)
CoreWords:define("DROP", dropInfo)
CoreWords:define("OVER", overInfo)
CoreWords:define("2DUP", twoDupInfo)
CoreWords:define("2SWAP", twoSwapInfo)
CoreWords:define("2OVER", twoOverInfo)
CoreWords:define("NIP", nipInfo)
local sqr = {dup, mul, ret}
local sqrf = makeCall(sqr)
defineWord(CoreWords, "SQR", sqrf, false)
return CoreWords