Extra Features
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package evaluator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"monkey/lexer"
|
||||
"monkey/object"
|
||||
"monkey/parser"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -338,22 +341,25 @@ func TestBuiltinFunctions(t *testing.T) {
|
||||
{`len("")`, 0},
|
||||
{`len("four")`, 4},
|
||||
{`len("hello world")`, 11},
|
||||
{`len(1)`, "argument to `len` not supported, got INTEGER"},
|
||||
{`len("one", "two")`, "wrong number of arguments. got=2, want=1"},
|
||||
{`len(1)`, errors.New("argument to `len` not supported, got INTEGER")},
|
||||
{`len("one", "two")`, errors.New("wrong number of arguments. got=2, want=1")},
|
||||
{`len("∑")`, 1},
|
||||
{`len([1, 2, 3])`, 3},
|
||||
{`len([])`, 0},
|
||||
{`first([1, 2, 3])`, 1},
|
||||
{`first([])`, nil},
|
||||
{`first(1)`, "argument to `first` must be ARRAY, got INTEGER"},
|
||||
{`first(1)`, errors.New("argument to `first` must be ARRAY, got INTEGER")},
|
||||
{`last([1, 2, 3])`, 3},
|
||||
{`last([])`, nil},
|
||||
{`last(1)`, "argument to `last` must be ARRAY, got INTEGER"},
|
||||
{`last(1)`, errors.New("argument to `last` must be ARRAY, got INTEGER")},
|
||||
{`rest([1, 2, 3])`, []int{2, 3}},
|
||||
{`rest([])`, nil},
|
||||
{`push([], 1)`, []int{1}},
|
||||
{`push(1, 1)`, "argument to `push` must be ARRAY, got INTEGER"},
|
||||
{`puts("Hello World")`, nil},
|
||||
{`push(1, 1)`, errors.New("argument to `push` must be ARRAY, got INTEGER")},
|
||||
{`print("Hello World")`, nil},
|
||||
{`input()`, ""},
|
||||
{`pop([])`, errors.New("cannot pop from an empty array")},
|
||||
{`pop([1])`, 1},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -363,13 +369,15 @@ func TestBuiltinFunctions(t *testing.T) {
|
||||
case int:
|
||||
testIntegerObject(t, evaluated, int64(expected))
|
||||
case string:
|
||||
testStringObject(t, evaluated, expected)
|
||||
case error:
|
||||
errObj, ok := evaluated.(*object.Error)
|
||||
if !ok {
|
||||
t.Errorf("object is not Error. got=%T (%+v)",
|
||||
evaluated, evaluated)
|
||||
continue
|
||||
}
|
||||
if errObj.Message != expected {
|
||||
if errObj.Message != expected.Error() {
|
||||
t.Errorf("wrong error message. expected=%q, got=%q",
|
||||
expected, errObj.Message)
|
||||
}
|
||||
@@ -541,6 +549,31 @@ func TestHashIndexExpressions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhileExpressions(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected interface{}
|
||||
}{
|
||||
{"while (false) { }", nil},
|
||||
{"let n = 0; while (n < 10) { let n = n + 1 }; n", 10},
|
||||
{"let n = 10; while (n > 0) { let n = n - 1 }; n", 0},
|
||||
// FIXME: let is an expression statement and bind new values
|
||||
// there is currently no assignment expressions :/
|
||||
{"let n = 0; while (n < 10) { let n = n + 1 }", nil},
|
||||
{"let n = 10; while (n > 0) { let n = n - 1 }", nil},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
evaluated := testEval(tt.input)
|
||||
integer, ok := tt.expected.(int)
|
||||
if ok {
|
||||
testIntegerObject(t, evaluated, int64(integer))
|
||||
} else {
|
||||
testNullObject(t, evaluated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testEval(input string) object.Object {
|
||||
l := lexer.New(input)
|
||||
p := parser.New(l)
|
||||
@@ -585,3 +618,32 @@ func testNullObject(t *testing.T, obj object.Object) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func testStringObject(t *testing.T, obj object.Object, expected string) bool {
|
||||
result, ok := obj.(*object.String)
|
||||
if !ok {
|
||||
t.Errorf("object is not String. got=%T (%+v)", obj, obj)
|
||||
return false
|
||||
}
|
||||
if result.Value != expected {
|
||||
t.Errorf("object has wrong value. got=%s, want=%s",
|
||||
result.Value, expected)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestExamples(t *testing.T) {
|
||||
matches, err := filepath.Glob("../examples/*.monkey")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for _, match := range matches {
|
||||
b, err := os.ReadFile(match)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
testEval(string(b))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user