(LOCAL) word, along with helper words for using it.
This commit is contained in:
parent
b92df463f1
commit
fa9daaebb0
|
@ -5,8 +5,8 @@ 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)
|
||||
function CoreHelpers.defineWord(dict: Dictionary, str: string, func: function(Environment): any..., imm: boolean, toFunc: function(Environment) | nil)
|
||||
local info = WordInfo:new(func, imm, toFunc)
|
||||
dict:define(str, info)
|
||||
end
|
||||
|
||||
|
@ -80,6 +80,14 @@ function CoreHelpers.skipWhitespace(state: Environment)
|
|||
end
|
||||
end
|
||||
|
||||
function CoreHelpers.skipSpaces(e: Environment)
|
||||
local chr = e.activeInputStream:curr()
|
||||
while chr == " " do
|
||||
e.activeInputStream:next()
|
||||
chr = e.activeInputStream:curr()
|
||||
end
|
||||
end
|
||||
|
||||
function CoreHelpers.popTwoOperands(state: Environment): any, any
|
||||
local stack = CoreHelpers.getActiveDataStack(state)
|
||||
local b: any = stack:pop()
|
||||
|
@ -108,9 +116,15 @@ function CoreHelpers.ret(env: Environment)
|
|||
env.instructionPointer = retAddr
|
||||
end
|
||||
|
||||
function CoreHelpers.makeCall(body: {function(Environment)}): function(Environment)
|
||||
function CoreHelpers.makeCall(body: {function(Environment)}, localCount: integer | nil): function(Environment)
|
||||
if localCount == nil then
|
||||
localCount = 0
|
||||
end
|
||||
return function(e: Environment)
|
||||
e.returnStack:push(e.instructionPointer)
|
||||
for i = localCount as number, 1, -1 do
|
||||
e.returnStack:push(-1234)
|
||||
end
|
||||
e.instructionPointer = Pointer:new(body, 0)
|
||||
end
|
||||
end
|
||||
|
@ -164,8 +178,12 @@ function CoreHelpers.recNumber(env: Environment)
|
|||
end
|
||||
|
||||
function CoreHelpers.searchDictionaries(e: Environment, token: string): WordInfo, Dictionary
|
||||
local wordinfo = e.locals:lookup(token)
|
||||
if wordinfo then
|
||||
return wordinfo
|
||||
end
|
||||
for _, dictionary in ipairs(e.dictionaries) do
|
||||
local wordinfo = dictionary:lookup(token)
|
||||
wordinfo = dictionary:lookup(token)
|
||||
if wordinfo then
|
||||
return wordinfo
|
||||
end
|
||||
|
@ -189,8 +207,13 @@ end
|
|||
|
||||
|
||||
function CoreHelpers.interpreters_outer(env: Environment)
|
||||
|
||||
local dataStack = env.activeDataStack
|
||||
if not env.toMode then
|
||||
CoreHelpers.skipWhitespace(env)
|
||||
else
|
||||
CoreHelpers.skipSpaces(env)
|
||||
end
|
||||
local token: string | nil = CoreHelpers.parseToken(env)
|
||||
if not token then
|
||||
env.running = false
|
||||
|
@ -227,7 +250,12 @@ function CoreHelpers.recWord(env: Environment)
|
|||
local wordinfo = CoreHelpers.searchDictionaries(env, token)
|
||||
if wordinfo then
|
||||
-- XT
|
||||
if not env.toMode then
|
||||
dataStack:push((wordinfo as WordInfo).func)
|
||||
else
|
||||
dataStack:push((wordinfo as WordInfo).toFunc)
|
||||
env.toMode = false
|
||||
end
|
||||
|
||||
-- interpret
|
||||
dataStack:push(CoreHelpers.execute)
|
||||
|
|
71
CoreWords.tl
71
CoreWords.tl
|
@ -166,6 +166,7 @@ end
|
|||
|
||||
local function colon(e: Environment)
|
||||
skipWhitespace(e)
|
||||
e.locals = Dictionary:new()
|
||||
local name: string | nil = parseToken(e)
|
||||
if not name then
|
||||
e.running = false
|
||||
|
@ -176,14 +177,27 @@ local function colon(e: Environment)
|
|||
end
|
||||
|
||||
local function semicolon(e: Environment)
|
||||
local localCount = e.locals.wordCount
|
||||
local cleanup_locals = function(e: Environment)
|
||||
for _ = localCount, 1, -1 do
|
||||
e.returnStack:pop()
|
||||
end
|
||||
end
|
||||
table.insert(e.currentDefinition as {function(Environment)}, cleanup_locals)
|
||||
table.insert(e.currentDefinition as {function(Environment)}, helpers.ret)
|
||||
local instrs = e.currentDefinition
|
||||
local call = helpers.makeCall(instrs as {function(Environment)})
|
||||
|
||||
local call = helpers.makeCall(instrs as {function(Environment)}, e.locals.wordCount)
|
||||
local dict = e.dictionaries[1]
|
||||
defineWord(dict, e.currentDefinitionName, call, false)
|
||||
e.mostRecentDefinition = e.currentDefinitionName
|
||||
e.currentDefinitionName = nil
|
||||
e.currentDefinition = {}
|
||||
-- clear locals
|
||||
e.locals = Dictionary:new()
|
||||
e.localBuffer = {}
|
||||
|
||||
|
||||
exitCompileMode(e)
|
||||
end
|
||||
local function toCompileStack(e: Environment)
|
||||
|
@ -339,6 +353,51 @@ local function stringLiteral(e: Environment)
|
|||
e.activeDataStack:push(str as string)
|
||||
end
|
||||
|
||||
local function forthTo(e: Environment)
|
||||
e.toMode = true
|
||||
end
|
||||
|
||||
local function forth_local_(e: Environment)
|
||||
local localName = e.activeDataStack:pop() as string
|
||||
if localName == "" then
|
||||
-- TODO: figure out what to do when you receive an "end of locals"
|
||||
local frame = #e.localBuffer
|
||||
for _, f in ipairs(e.localBuffer) do
|
||||
f(frame, e)
|
||||
end
|
||||
|
||||
else
|
||||
-- local offset = e.locals.wordCount
|
||||
|
||||
|
||||
local index = #e.localBuffer + 1
|
||||
|
||||
local postponedLocal = function(frame: integer, e: Environment)
|
||||
local localAddress = e.returnStack.top - frame + index
|
||||
local localFunction = function(e: Environment)
|
||||
local top = e.returnStack.top
|
||||
e.activeDataStack:push(e.returnStack.contents[top - frame + index])
|
||||
end
|
||||
local localFunctionTo = function(e: Environment)
|
||||
local top = e.returnStack.top
|
||||
local newValue = e.activeDataStack:pop()
|
||||
e.returnStack.contents[top - frame + index] = newValue
|
||||
end
|
||||
defineWord(e.locals, localName, localFunction, false, localFunctionTo)
|
||||
end
|
||||
table.insert(e.localBuffer, postponedLocal)
|
||||
end
|
||||
end
|
||||
|
||||
local function parseName(e: Environment)
|
||||
helpers.skipSpaces(e)
|
||||
e.activeDataStack:push(helpers.parseToken(e))
|
||||
end
|
||||
|
||||
local function emptys(e: Environment)
|
||||
e.activeDataStack:push("")
|
||||
end
|
||||
|
||||
local CoreWords = Dictionary:new()
|
||||
local addInfo = WordInfo:new(add, false)
|
||||
local subInfo = WordInfo:new(sub, false)
|
||||
|
@ -363,7 +422,7 @@ defineWord(CoreWords, "[", exitCompileMode, true)
|
|||
defineWord(CoreWords, "]", enterCompileMode, false)
|
||||
defineWord(CoreWords, "COMPILE,", compile, true)
|
||||
defineWord(CoreWords, "LITERAL", literal, true)
|
||||
defineWord(CoreWords, ":", colon, true)
|
||||
defineWord(CoreWords, ":", colon, false)
|
||||
defineWord(CoreWords, ";", semicolon, true)
|
||||
defineWord(CoreWords, ">C",toCompileStack, false)
|
||||
defineWord(CoreWords, "C>", fromCompileStack, false)
|
||||
|
@ -378,13 +437,19 @@ defineWord(CoreWords, "WHILE", forthWhile, true)
|
|||
defineWord(CoreWords, "REPEAT", forthRepeat, true)
|
||||
defineWord(CoreWords, "AGAIN", forthAgain, true)
|
||||
|
||||
defineWord(CoreWords, "TO", forthTo, true)
|
||||
defineWord(CoreWords, "(LOCAL)", forth_local_, true)
|
||||
defineWord(CoreWords, "PARSE-NAME", parseName, true)
|
||||
defineWord(CoreWords, "EMPTYS", emptys, true)
|
||||
defineWord(CoreWords, "\"\"", emptys, false)
|
||||
|
||||
defineWord(CoreWords,"<", cmplt, false)
|
||||
defineWord(CoreWords,"<=", cmplte, false)
|
||||
defineWord(CoreWords,"=", cmpe, false)
|
||||
defineWord(CoreWords,">=", cmpgte, false)
|
||||
defineWord(CoreWords,">", cmpgt, false)
|
||||
defineWord(CoreWords,"<>", cmpne, false)
|
||||
defineWord(CoreWords,"S\"", stringLiteral, false)
|
||||
defineWord(CoreWords,"S\"", stringLiteral, true)
|
||||
|
||||
|
||||
CoreWords:define("+", addInfo)
|
||||
|
|
|
@ -3,8 +3,8 @@ local InputStream = require("InputStream")
|
|||
|
||||
local type DataStructures = record
|
||||
record Stack
|
||||
contents: {any}
|
||||
top: number
|
||||
contents: {integer:any}
|
||||
top: integer
|
||||
push: function(Stack, any)
|
||||
pop: function(Stack)
|
||||
|
||||
|
@ -13,10 +13,11 @@ local type DataStructures = record
|
|||
|
||||
record Dictionary
|
||||
contents: {string: WordInfo}
|
||||
|
||||
wordCount: integer
|
||||
define: function(Dictionary, string, WordInfo)
|
||||
end
|
||||
record WordInfo
|
||||
toFunc: function(Environment)
|
||||
func: function(Environment)
|
||||
immediate: boolean
|
||||
new: function(WordInfo, function(Environment), boolean): WordInfo
|
||||
|
@ -49,6 +50,9 @@ local type DataStructures = record
|
|||
currentDefinitionName: string | nil
|
||||
currentDefinition: {function(Environment)}
|
||||
mostRecentDefinition: string
|
||||
toMode: boolean
|
||||
locals: Dictionary
|
||||
localBuffer: {function(integer, Environment)}
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -56,37 +60,11 @@ end
|
|||
local Stack, Environment, Dictionary, WordInfo = DataStructures.Stack, DataStructures.Environment, DataStructures.Dictionary, DataStructures.WordInfo
|
||||
local Pointer = DataStructures.Pointer
|
||||
local wordi_mt = {__index = WordInfo}
|
||||
function WordInfo:new(funct: function(Environment, ...: any), imm: boolean): WordInfo
|
||||
return setmetatable({func = funct, immediate = imm} as WordInfo, wordi_mt)
|
||||
function WordInfo:new(funct: function(Environment, ...: any), imm: boolean, toFunct: function(Environment) | nil): WordInfo
|
||||
return setmetatable({func = funct, immediate = imm, toFunc = toFunct} as WordInfo, wordi_mt)
|
||||
end
|
||||
|
||||
|
||||
local state_mt = {__index = Environment}
|
||||
function Environment:new(input: InputStream, dict: {Dictionary} ): Environment
|
||||
local dicts = dict or {}
|
||||
|
||||
return setmetatable(
|
||||
{
|
||||
activeDataStack= Stack:new(),
|
||||
compilerStack = Stack:new(),
|
||||
returnStack = Stack:new(),
|
||||
dictionaries = dicts,
|
||||
activeInputStream = input,
|
||||
running = true,
|
||||
recognizers = {},
|
||||
compileState = false,
|
||||
currentDefinition = {}
|
||||
} as Environment,
|
||||
state_mt)
|
||||
end
|
||||
|
||||
function Environment:addDataStack(data: Stack)
|
||||
table.insert(self.dataStacks, data)
|
||||
end
|
||||
|
||||
function Environment:changeCompilerStack(compilerStack: Stack)
|
||||
self.compilerStack = compilerStack
|
||||
end
|
||||
--function Environment:changeActiveDataStack(stackIndex: number)
|
||||
-- assert(stackIndex <= #self.dataStacks and stackIndex > 0)
|
||||
-- self.activeDataStack = self.dataStacks[stackIndex]
|
||||
|
@ -94,7 +72,6 @@ end
|
|||
|
||||
|
||||
|
||||
|
||||
function Stack:push(val: any)
|
||||
self.top = self.top + 1
|
||||
table.insert(self.contents,val)
|
||||
|
@ -122,13 +99,42 @@ function Dictionary:lookup(word: string): WordInfo | nil
|
|||
end
|
||||
|
||||
function Dictionary:define(word: string, info: WordInfo)
|
||||
if not self.contents[word] then self.wordCount = self.wordCount + 1 end
|
||||
self.contents[word] = info
|
||||
end
|
||||
local dict_mt = {__index = Dictionary}
|
||||
function Dictionary:new(): Dictionary
|
||||
return setmetatable({contents = {}} as Dictionary, dict_mt)
|
||||
return setmetatable({contents = {}, wordCount = 0} as Dictionary, dict_mt)
|
||||
end
|
||||
|
||||
local state_mt = {__index = Environment}
|
||||
function Environment:new(input: InputStream, dict: {Dictionary} ): Environment
|
||||
local dicts = dict or {}
|
||||
|
||||
return setmetatable(
|
||||
{
|
||||
activeDataStack= Stack:new(),
|
||||
compilerStack = Stack:new(),
|
||||
returnStack = Stack:new(),
|
||||
dictionaries = dicts,
|
||||
activeInputStream = input,
|
||||
running = true,
|
||||
recognizers = {},
|
||||
compileState = false,
|
||||
currentDefinition = {},
|
||||
locals = Dictionary:new(),
|
||||
localBuffer = {}
|
||||
} as Environment,
|
||||
state_mt)
|
||||
end
|
||||
|
||||
function Environment:addDataStack(data: Stack)
|
||||
table.insert(self.dataStacks, data)
|
||||
end
|
||||
|
||||
function Environment:changeCompilerStack(compilerStack: Stack)
|
||||
self.compilerStack = compilerStack
|
||||
end
|
||||
function Pointer:deref(): any
|
||||
return self.referant[self.index]
|
||||
end
|
||||
|
|
|
@ -138,6 +138,13 @@ describe("Dictionary tests", function()
|
|||
dict:define("TEST",wi)
|
||||
assert.are.same(dict:lookup("TEST"),wi)
|
||||
end)
|
||||
it("keeps track of the number of words in the dictionary", function()
|
||||
local env = Environment:new()
|
||||
local dict = Dictionary:new()
|
||||
local wi = WordInfo:new(function(env) end, false)
|
||||
dict:define("TEST", wi)
|
||||
assert.are.equal(dict.wordCount, 1)
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue