Add arithmetic tests for the Forth interpreter.

This commit is contained in:
Starfflame 2021-05-23 06:59:36 -05:00
parent 59b7c5a028
commit 09e42c69d5
8 changed files with 126 additions and 33 deletions

View File

@ -11,7 +11,7 @@ function CoreHelpers.defineWord(dict: Dictionary, str: string, func: function(En
end
function CoreHelpers.standardInputRefill(): string
local input = io.read().."\n\n"
local input = io.read().."\n"
return input
end
@ -73,7 +73,8 @@ end
function CoreHelpers.skipWhitespace(state: Environment)
local chr = state.activeInputStream:curr()
while (CoreHelpers.isWhitespace(chr)) do
chr = state.activeInputStream:next()
state.activeInputStream:next()
chr = state.activeInputStream:curr()
end
end
@ -85,11 +86,12 @@ function CoreHelpers.popTwoOperands(state: Environment): any, any
end
function CoreHelpers.parseToken(state: Environment): string
local chr = ""
local token = ""
while(not CoreHelpers.isWhitespace(chr)) do
token = token..chr
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

View File

@ -78,7 +78,7 @@ end
-- I/O operations
local function dot(state: Environment)
local out = state.activeDataStack:pop()
print(out)
io.write(out as string.."\n")
end
local function twoDup(state: Environment)
over(state)

View File

@ -43,10 +43,11 @@ local type DataStructures = record
addDataStack: function(Environment, Stack)
changeCompilerStack: function(Environment, Stack)
changeActiveDataStack: function(Environment, number)
recognizers: {function(Environment)}
instructionPointer: Pointer
running: boolean
end
end
local Stack, Environment, Dictionary, WordInfo = DataStructures.Stack, DataStructures.Environment, DataStructures.Dictionary, DataStructures.WordInfo
@ -58,12 +59,17 @@ end
local state_mt = {__index = Environment}
function Environment:new(): Environment
function Environment:new(input: InputStream, dict: {Dictionary} ): Environment
local dicts = dict or {}
return setmetatable(
{
dataStacks = {},
activeDataStack= Stack:new(),
compilerStack = Stack:new(),
dictionaries = {}
returnStack = Stack:new(),
dictionaries = dicts,
activeInputStream = input,
running = true
} as Environment,
state_mt)
end
@ -79,7 +85,7 @@ end
-- assert(stackIndex <= #self.dataStacks and stackIndex > 0)
-- self.activeDataStack = self.dataStacks[stackIndex]
--end

View File

@ -2,14 +2,19 @@ local istream = require("InputStream")
local helpers = require("CoreHelpers")
local interpreters = require("Interpreters")
local standardInputRefill = helpers.standardInputRefill
local CoreWords = require("CoreWords")
local oneReadInputStream = helpers.oneReadInputStream
local fileStream = helpers.fileStream
-- local fileStream = helpers.fileStream
local Environment = require("DataStructures").Environment
--interpreters.start(fileStream("codetest.txt"))
local core_dicts = {CoreWords}
--local env = Environment:new(istream:new(standardInputRefill), core_dicts)
local env = Environment:new(oneReadInputStream("14 11 + ."), core_dicts)
interpreters.start(env)
interpreters.start(istream:new(standardInputRefill))

View File

@ -20,7 +20,6 @@ function InputStream:_manageBuffer()
else
length = -1
end
print("self.str = ",self.str, self.offset,length)
if not self.str then
self.str = self.refill()
self.offset = 1
@ -55,7 +54,6 @@ end
-- setters/getters
function InputStream:__setRefill(func: function(): string)
self.refill = func
print("setrefill")
self:_manageBuffer()
end
@ -71,7 +69,6 @@ function InputStream:curr(): string | nil
end
function InputStream:next(): string | nil
print("next")
if self.offset > #self.str then
self:_manageBuffer()
end

View File

@ -10,27 +10,26 @@ local type Interpreters = record
outer: function(Environment)
end
function Interpreters.start(input: istream)
local machineEnvironment = Environment:new()
machineEnvironment.activeInputStream = input
machineEnvironment.activeDataStack = Stack:new()
machineEnvironment.returnStack = Stack:new()
table.insert(machineEnvironment.dictionaries, CoreWords)
function Interpreters.start(env: Environment)
table.insert(env.dictionaries, CoreWords)
local interpreterInstructions = {}
table.insert(interpreterInstructions, Interpreters.outer)
table.insert(interpreterInstructions, helpers.reset)
local startPointer = Pointer:new()
startPointer.referant = interpreterInstructions
machineEnvironment.instructionPointer = startPointer
Interpreters.inner(machineEnvironment)
env.instructionPointer = startPointer
Interpreters.inner(env)
end
function Interpreters.outer(env: Environment)
skipWhitespace(env)
local token: string = parseToken(env)
local token: string | nil = parseToken(env)
if not token then
env.running = false
return
end
if isNumber(token) then
env.activeDataStack:push(tonumber(token))
else
@ -47,7 +46,7 @@ function Interpreters.outer(env: Environment)
end
function Interpreters.inner(env: Environment)
while(true) do
while(env.running) do
env.instructionPointer:deref() as function(Environment)(env)
env.instructionPointer:inc()
end

View File

@ -4,4 +4,4 @@
10 DUP * .
78 1 - 5 * .
11 1 - .

View File

@ -2,7 +2,8 @@ local istream = require("InputStream")
local ds = require("DataStructures")
local Stack, Dictionary, WordInfo, Environment = ds.Stack, ds.Dictionary, ds.WordInfo, ds.Environment
local CoreHelpers = require("CoreHelpers")
local CoreWords = require("CoreWords")
local interpreters = require("Interpreters")
function pushThree(s)
s:push(1)
s:push(2)
@ -131,4 +132,87 @@ describe("Dictionary tests", function()
end)
function buildEnvironment(testString)
local testEnv = Environment:new(CoreHelpers.oneReadInputStream(testString), {CoreWords})
return testEnv
end
local twoRandom = function() return math.random(100000), math.random(100000) end
describe("Interpreter tests", function()
describe("Arithmetic tests", function()
it("can add two numbers, and leave the sum on the stack", function()
for i=1, 1000 do
local a, b = twoRandom()
local expected_sum = a + b
local testString = a.." "..b.." +"
local testEnv = buildEnvironment(testString)
interpreters.start(testEnv)
assert.are.same(testEnv.activeDataStack.contents[1], expected_sum)
end
end)
it("can subtract two numbers, and leave the difference on the stack", function()
for i=1, 1000 do
local a, b = twoRandom()
local expected_diff = a -b
local testString = a.." "..b.." -"
local testEnv = buildEnvironment(testString)
interpreters.start(testEnv)
assert.are.same(testEnv.activeDataStack.contents[1], expected_diff)
end
end)
it("can multiply two numbers, leaving product on the stack", function()
for i = 1, 1000 do
local a, b = twoRandom()
local expected_prod = a*b
local testString = a.." "..b.." *"
local testEnv = buildEnvironment(testString)
interpreters.start(testEnv)
assert.are.same(testEnv.activeDataStack.contents[1], expected_prod)
end
end)
it("can divide two numbers, leaving the quotient on the stack", function()
for i = 1, 1000 do
local a, b = twoRandom()
local expected_quo = a/b
local testString = a.." "..b.." /"
local testEnv = buildEnvironment(testString)
interpreters.start(testEnv)
assert.are.same(testEnv.activeDataStack.contents[1], expected_quo)
end
end)
it("can evaluate a arithmetic expression with multiple operations", function()
for i = 1, 1000 do
operands = {math.random(100000), math.random(100000), math.random(100000), math.random(100000)}
local operations = {math.random(4), math.random(4), math.random(4)}
local testString = ""..operands[1]
local expectedResult = operands[1]
for j, op in ipairs(operations) do
if j == 1 then
testString = testString.." "..operands[j + 1].." +"
expectedResult = expectedResult + operands[j+1]
elseif j == 2 then
testString = testString.." "..operands[j + 1].." -"
expectedResult = expectedResult - operands[j+1]
elseif j == 3 then
testString = testString.." "..operands[j + 1].." *"
expectedResult = expectedResult * operands[j+1]
else
testString = testString.." "..operands[j + 1].." /"
expectedResult = expectedResult / operands[j+1]
end
end
local testEnv = buildEnvironment(testString)
interpreters.start(testEnv)
assert.are.same(expectedResult,testEnv.activeDataStack.contents[1])
end
end)
end)
end)