(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 InputStream = require("InputStream")
|
||||||
local CoreHelpers = {}
|
local CoreHelpers = {}
|
||||||
|
|
||||||
function CoreHelpers.defineWord(dict: Dictionary, str: string, func: function(Environment, ...: any): any..., imm: boolean)
|
function CoreHelpers.defineWord(dict: Dictionary, str: string, func: function(Environment): any..., imm: boolean, toFunc: function(Environment) | nil)
|
||||||
local info = WordInfo:new(func, imm)
|
local info = WordInfo:new(func, imm, toFunc)
|
||||||
dict:define(str, info)
|
dict:define(str, info)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,6 +80,14 @@ function CoreHelpers.skipWhitespace(state: Environment)
|
||||||
end
|
end
|
||||||
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
|
function CoreHelpers.popTwoOperands(state: Environment): any, any
|
||||||
local stack = CoreHelpers.getActiveDataStack(state)
|
local stack = CoreHelpers.getActiveDataStack(state)
|
||||||
local b: any = stack:pop()
|
local b: any = stack:pop()
|
||||||
|
@ -108,9 +116,15 @@ function CoreHelpers.ret(env: Environment)
|
||||||
env.instructionPointer = retAddr
|
env.instructionPointer = retAddr
|
||||||
end
|
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)
|
return function(e: Environment)
|
||||||
e.returnStack:push(e.instructionPointer)
|
e.returnStack:push(e.instructionPointer)
|
||||||
|
for i = localCount as number, 1, -1 do
|
||||||
|
e.returnStack:push(-1234)
|
||||||
|
end
|
||||||
e.instructionPointer = Pointer:new(body, 0)
|
e.instructionPointer = Pointer:new(body, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -164,8 +178,12 @@ function CoreHelpers.recNumber(env: Environment)
|
||||||
end
|
end
|
||||||
|
|
||||||
function CoreHelpers.searchDictionaries(e: Environment, token: string): WordInfo, Dictionary
|
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
|
for _, dictionary in ipairs(e.dictionaries) do
|
||||||
local wordinfo = dictionary:lookup(token)
|
wordinfo = dictionary:lookup(token)
|
||||||
if wordinfo then
|
if wordinfo then
|
||||||
return wordinfo
|
return wordinfo
|
||||||
end
|
end
|
||||||
|
@ -189,8 +207,13 @@ end
|
||||||
|
|
||||||
|
|
||||||
function CoreHelpers.interpreters_outer(env: Environment)
|
function CoreHelpers.interpreters_outer(env: Environment)
|
||||||
|
|
||||||
local dataStack = env.activeDataStack
|
local dataStack = env.activeDataStack
|
||||||
|
if not env.toMode then
|
||||||
CoreHelpers.skipWhitespace(env)
|
CoreHelpers.skipWhitespace(env)
|
||||||
|
else
|
||||||
|
CoreHelpers.skipSpaces(env)
|
||||||
|
end
|
||||||
local token: string | nil = CoreHelpers.parseToken(env)
|
local token: string | nil = CoreHelpers.parseToken(env)
|
||||||
if not token then
|
if not token then
|
||||||
env.running = false
|
env.running = false
|
||||||
|
@ -227,7 +250,12 @@ function CoreHelpers.recWord(env: Environment)
|
||||||
local wordinfo = CoreHelpers.searchDictionaries(env, token)
|
local wordinfo = CoreHelpers.searchDictionaries(env, token)
|
||||||
if wordinfo then
|
if wordinfo then
|
||||||
-- XT
|
-- XT
|
||||||
|
if not env.toMode then
|
||||||
dataStack:push((wordinfo as WordInfo).func)
|
dataStack:push((wordinfo as WordInfo).func)
|
||||||
|
else
|
||||||
|
dataStack:push((wordinfo as WordInfo).toFunc)
|
||||||
|
env.toMode = false
|
||||||
|
end
|
||||||
|
|
||||||
-- interpret
|
-- interpret
|
||||||
dataStack:push(CoreHelpers.execute)
|
dataStack:push(CoreHelpers.execute)
|
||||||
|
|
71
CoreWords.tl
71
CoreWords.tl
|
@ -166,6 +166,7 @@ end
|
||||||
|
|
||||||
local function colon(e: Environment)
|
local function colon(e: Environment)
|
||||||
skipWhitespace(e)
|
skipWhitespace(e)
|
||||||
|
e.locals = Dictionary:new()
|
||||||
local name: string | nil = parseToken(e)
|
local name: string | nil = parseToken(e)
|
||||||
if not name then
|
if not name then
|
||||||
e.running = false
|
e.running = false
|
||||||
|
@ -176,14 +177,27 @@ local function colon(e: Environment)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function semicolon(e: Environment)
|
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)
|
table.insert(e.currentDefinition as {function(Environment)}, helpers.ret)
|
||||||
local instrs = e.currentDefinition
|
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]
|
local dict = e.dictionaries[1]
|
||||||
defineWord(dict, e.currentDefinitionName, call, false)
|
defineWord(dict, e.currentDefinitionName, call, false)
|
||||||
e.mostRecentDefinition = e.currentDefinitionName
|
e.mostRecentDefinition = e.currentDefinitionName
|
||||||
e.currentDefinitionName = nil
|
e.currentDefinitionName = nil
|
||||||
e.currentDefinition = {}
|
e.currentDefinition = {}
|
||||||
|
-- clear locals
|
||||||
|
e.locals = Dictionary:new()
|
||||||
|
e.localBuffer = {}
|
||||||
|
|
||||||
|
|
||||||
exitCompileMode(e)
|
exitCompileMode(e)
|
||||||
end
|
end
|
||||||
local function toCompileStack(e: Environment)
|
local function toCompileStack(e: Environment)
|
||||||
|
@ -339,6 +353,51 @@ local function stringLiteral(e: Environment)
|
||||||
e.activeDataStack:push(str as string)
|
e.activeDataStack:push(str as string)
|
||||||
end
|
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 CoreWords = Dictionary:new()
|
||||||
local addInfo = WordInfo:new(add, false)
|
local addInfo = WordInfo:new(add, false)
|
||||||
local subInfo = WordInfo:new(sub, false)
|
local subInfo = WordInfo:new(sub, false)
|
||||||
|
@ -363,7 +422,7 @@ defineWord(CoreWords, "[", exitCompileMode, true)
|
||||||
defineWord(CoreWords, "]", enterCompileMode, false)
|
defineWord(CoreWords, "]", enterCompileMode, false)
|
||||||
defineWord(CoreWords, "COMPILE,", compile, true)
|
defineWord(CoreWords, "COMPILE,", compile, true)
|
||||||
defineWord(CoreWords, "LITERAL", literal, true)
|
defineWord(CoreWords, "LITERAL", literal, true)
|
||||||
defineWord(CoreWords, ":", colon, true)
|
defineWord(CoreWords, ":", colon, false)
|
||||||
defineWord(CoreWords, ";", semicolon, true)
|
defineWord(CoreWords, ";", semicolon, true)
|
||||||
defineWord(CoreWords, ">C",toCompileStack, false)
|
defineWord(CoreWords, ">C",toCompileStack, false)
|
||||||
defineWord(CoreWords, "C>", fromCompileStack, false)
|
defineWord(CoreWords, "C>", fromCompileStack, false)
|
||||||
|
@ -378,13 +437,19 @@ defineWord(CoreWords, "WHILE", forthWhile, true)
|
||||||
defineWord(CoreWords, "REPEAT", forthRepeat, true)
|
defineWord(CoreWords, "REPEAT", forthRepeat, true)
|
||||||
defineWord(CoreWords, "AGAIN", forthAgain, 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,"<", cmplt, false)
|
||||||
defineWord(CoreWords,"<=", cmplte, false)
|
defineWord(CoreWords,"<=", cmplte, false)
|
||||||
defineWord(CoreWords,"=", cmpe, false)
|
defineWord(CoreWords,"=", cmpe, false)
|
||||||
defineWord(CoreWords,">=", cmpgte, false)
|
defineWord(CoreWords,">=", cmpgte, false)
|
||||||
defineWord(CoreWords,">", cmpgt, false)
|
defineWord(CoreWords,">", cmpgt, false)
|
||||||
defineWord(CoreWords,"<>", cmpne, false)
|
defineWord(CoreWords,"<>", cmpne, false)
|
||||||
defineWord(CoreWords,"S\"", stringLiteral, false)
|
defineWord(CoreWords,"S\"", stringLiteral, true)
|
||||||
|
|
||||||
|
|
||||||
CoreWords:define("+", addInfo)
|
CoreWords:define("+", addInfo)
|
||||||
|
|
|
@ -3,8 +3,8 @@ local InputStream = require("InputStream")
|
||||||
|
|
||||||
local type DataStructures = record
|
local type DataStructures = record
|
||||||
record Stack
|
record Stack
|
||||||
contents: {any}
|
contents: {integer:any}
|
||||||
top: number
|
top: integer
|
||||||
push: function(Stack, any)
|
push: function(Stack, any)
|
||||||
pop: function(Stack)
|
pop: function(Stack)
|
||||||
|
|
||||||
|
@ -13,10 +13,11 @@ local type DataStructures = record
|
||||||
|
|
||||||
record Dictionary
|
record Dictionary
|
||||||
contents: {string: WordInfo}
|
contents: {string: WordInfo}
|
||||||
|
wordCount: integer
|
||||||
define: function(Dictionary, string, WordInfo)
|
define: function(Dictionary, string, WordInfo)
|
||||||
end
|
end
|
||||||
record WordInfo
|
record WordInfo
|
||||||
|
toFunc: function(Environment)
|
||||||
func: function(Environment)
|
func: function(Environment)
|
||||||
immediate: boolean
|
immediate: boolean
|
||||||
new: function(WordInfo, function(Environment), boolean): WordInfo
|
new: function(WordInfo, function(Environment), boolean): WordInfo
|
||||||
|
@ -49,6 +50,9 @@ local type DataStructures = record
|
||||||
currentDefinitionName: string | nil
|
currentDefinitionName: string | nil
|
||||||
currentDefinition: {function(Environment)}
|
currentDefinition: {function(Environment)}
|
||||||
mostRecentDefinition: string
|
mostRecentDefinition: string
|
||||||
|
toMode: boolean
|
||||||
|
locals: Dictionary
|
||||||
|
localBuffer: {function(integer, Environment)}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -56,37 +60,11 @@ end
|
||||||
local Stack, Environment, Dictionary, WordInfo = DataStructures.Stack, DataStructures.Environment, DataStructures.Dictionary, DataStructures.WordInfo
|
local Stack, Environment, Dictionary, WordInfo = DataStructures.Stack, DataStructures.Environment, DataStructures.Dictionary, DataStructures.WordInfo
|
||||||
local Pointer = DataStructures.Pointer
|
local Pointer = DataStructures.Pointer
|
||||||
local wordi_mt = {__index = WordInfo}
|
local wordi_mt = {__index = WordInfo}
|
||||||
function WordInfo:new(funct: function(Environment, ...: any), imm: boolean): WordInfo
|
function WordInfo:new(funct: function(Environment, ...: any), imm: boolean, toFunct: function(Environment) | nil): WordInfo
|
||||||
return setmetatable({func = funct, immediate = imm} as WordInfo, wordi_mt)
|
return setmetatable({func = funct, immediate = imm, toFunc = toFunct} as WordInfo, wordi_mt)
|
||||||
end
|
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)
|
--function Environment:changeActiveDataStack(stackIndex: number)
|
||||||
-- assert(stackIndex <= #self.dataStacks and stackIndex > 0)
|
-- assert(stackIndex <= #self.dataStacks and stackIndex > 0)
|
||||||
-- self.activeDataStack = self.dataStacks[stackIndex]
|
-- self.activeDataStack = self.dataStacks[stackIndex]
|
||||||
|
@ -94,7 +72,6 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Stack:push(val: any)
|
function Stack:push(val: any)
|
||||||
self.top = self.top + 1
|
self.top = self.top + 1
|
||||||
table.insert(self.contents,val)
|
table.insert(self.contents,val)
|
||||||
|
@ -122,13 +99,42 @@ function Dictionary:lookup(word: string): WordInfo | nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dictionary:define(word: string, info: WordInfo)
|
function Dictionary:define(word: string, info: WordInfo)
|
||||||
|
if not self.contents[word] then self.wordCount = self.wordCount + 1 end
|
||||||
self.contents[word] = info
|
self.contents[word] = info
|
||||||
end
|
end
|
||||||
local dict_mt = {__index = Dictionary}
|
local dict_mt = {__index = Dictionary}
|
||||||
function Dictionary:new(): Dictionary
|
function Dictionary:new(): Dictionary
|
||||||
return setmetatable({contents = {}} as Dictionary, dict_mt)
|
return setmetatable({contents = {}, wordCount = 0} as Dictionary, dict_mt)
|
||||||
end
|
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
|
function Pointer:deref(): any
|
||||||
return self.referant[self.index]
|
return self.referant[self.index]
|
||||||
end
|
end
|
||||||
|
|
|
@ -138,6 +138,13 @@ describe("Dictionary tests", function()
|
||||||
dict:define("TEST",wi)
|
dict:define("TEST",wi)
|
||||||
assert.are.same(dict:lookup("TEST"),wi)
|
assert.are.same(dict:lookup("TEST"),wi)
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue