Skip to content

Commit

Permalink
Move tests into source directories (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
DustTheory authored Nov 9, 2023
1 parent 6d84929 commit 72d7c4c
Show file tree
Hide file tree
Showing 73 changed files with 642 additions and 750 deletions.
8 changes: 4 additions & 4 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ func (ie *InfixExpression) String() string {
return out.String()
}

func (b *Boolean) expressionNode() {}
func (b *Boolean) TokenLiteral() string { return b.Token.Literal }
func (b *Boolean) TokenValue() token.Token { return b.Token }
func (b *Boolean) String() string { return b.Token.Literal }
func (b *BooleanLiteral) expressionNode() {}
func (b *BooleanLiteral) TokenLiteral() string { return b.Token.Literal }
func (b *BooleanLiteral) TokenValue() token.Token { return b.Token }
func (b *BooleanLiteral) String() string { return b.Token.Literal }

func (ie *IfExpression) expressionNode() {}
func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
Expand Down
2 changes: 1 addition & 1 deletion ast/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ type InfixExpression struct {
Right Expression
}

type Boolean struct {
type BooleanLiteral struct {
Token token.Token
Value bool
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
10 changes: 10 additions & 0 deletions evaluator/eval_boolean_literal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package evaluator

import (
"github.com/0xM-D/interpreter/ast"
"github.com/0xM-D/interpreter/object"
)

func evalBooleanLiteral(node *ast.BooleanLiteral) object.Object {
return nativeBoolToBooleanObject(node.Value)
}
13 changes: 13 additions & 0 deletions evaluator/eval_boolean_literal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package evaluator

import "testing"

func TestBooleanTrueLiteral(t *testing.T) {
evaluated := testEval("true")
testBooleanObject(t, evaluated, true)
}

func TestBooleanFalseLiteral(t *testing.T) {
evaluated := testEval("false")
testBooleanObject(t, evaluated, false)
}
27 changes: 27 additions & 0 deletions evaluator/eval_call_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,30 @@ func evalCallExpression(node *ast.CallExpression, env *object.Environment) objec

return applyFunction(function, args)
}

func applyFunction(fn object.Object, args []object.Object) object.Object {
switch {
case object.IsFunction(fn):
function := object.UnwrapReferenceObject(fn).(*object.Function)

if len(function.ParameterTypes) != len(args) {
return newError("Incorrect parameter count for %s fun. expected=%d, got=%d", function.Type().Signature(), len(function.ParameterTypes), len(args))
}

extendedEnv := extendFunctionEnv(function, args)
evaluated := Eval(function.Body, extendedEnv)
return unwrapReturnValue(evaluated)
case object.IsBuiltinFunction(fn):
function := object.UnwrapReferenceObject(fn).(object.BuiltinFunction)

if len(function.ParameterTypes) != len(args) {
return newError("Incorrect parameter count for %s fun. expected=%d, got=%d", function.Type().Signature(), len(function.ParameterTypes), len(args))
}
params := []object.Object{}
params = append(params, function.BoundParams...)
params = append(params, args...)
return function.Function(params...)
default:
return newError("object is not a function: %s", fn.Inspect())
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
107 changes: 107 additions & 0 deletions evaluator/eval_declaration_statement_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package evaluator

import (
"math/big"
"testing"

"github.com/0xM-D/interpreter/object"
)

func TestAssignmentDeclaration(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"a := 5; a;", 5},
{"a := 5 * 5; a;", 25},
{"a := 5; let b = a; b;", 5},
{"a := 5; let b = a; let c = a + b + 5; c;", 15},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), big.NewInt(tt.expected))
}
}

func TestAsignmentExpression(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{"let a = 5; a = 3;", big.NewInt(3)},
{"a := 5 * 5; a += 20;", big.NewInt(45)},
{"a := 3; b := a; a += b", big.NewInt(6)},
{"a := 5; a -= 1", big.NewInt(4)},
{"a := 5; a *= 2", big.NewInt(10)},
{"a := 50; a /= 5", big.NewInt(10)},
{`a := "a"; a += "bc"`, "abc"},
}
for _, tt := range tests {
switch expected := tt.expected.(type) {
case *big.Int:
testIntegerObject(t, testEval(tt.input), expected)
case string:
testStringObject(t, testEval(tt.input), expected)
case bool:
testBooleanObject(t, testEval(tt.input), expected)
case []string:
testArrayObject(t, testEval(tt.input), expected)
}
}
}

func TestTypedDeclarationStatement(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{"int64 a = 5; a;", big.NewInt(5)},
{"string a = \"testmmm\"; a;", "testmmm"},
{"const []int a = new []int{1, 2, 3, 4}; let b = a; b;", []string{"1", "2", "3", "4"}},
{"bool a = true; let b = !a; b;", false},
{"const function(int64, int64)->int64 sum = fn(a: int64, b: int64) -> int64 { return a + b; }; sum", ExpectedFunction{
"fn(a, b) {" + "\n" +
"return (a + b);" + "\n" +
"}",
object.FunctionObjectType{
ParameterTypes: []object.ObjectType{object.Int64Kind, object.Int64Kind},
ReturnValueType: object.Int64Kind,
},
}},
{"function()->void sum = fn() -> void {}; sum", ExpectedFunction{
"fn() {\n\n}",
object.FunctionObjectType{
ParameterTypes: []object.ObjectType{},
ReturnValueType: object.VoidKind,
},
}},
}
for _, tt := range tests {
switch expected := tt.expected.(type) {
case *big.Int:
testIntegerObject(t, testEval(tt.input), expected)
case string:
testStringObject(t, testEval(tt.input), expected)
case bool:
testBooleanObject(t, testEval(tt.input), expected)
case []string:
testArrayObject(t, testEval(tt.input), expected)
case ExpectedFunction:
testFunctionObject(t, testEval(tt.input), expected)
}
}
}

func TestLetStatements(t *testing.T) {
tests := []struct {
input string
expected *big.Int
}{
{"let a = 5; a;", big.NewInt(5)},
{"let a = 5 * 5; a;", big.NewInt(25)},
{"let a = 5; let b = a; b;", big.NewInt(5)},
{"let a = 5; let b = a; let c = a + b + 5; c;", big.NewInt(15)},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), tt.expected)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import "testing"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package evaluator_tests
package evaluator

import (
"testing"

"github.com/0xM-D/interpreter/object"
)

func TestFunctionObject(t *testing.T) {
func TestFunctionLiteral(t *testing.T) {
input := "fn(x:int64)->int64 { x + 2; };"

evaluated := testEval(input)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
2 changes: 1 addition & 1 deletion evaluator/eval_index_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func evalIndexExpression(node *ast.IndexExpression, env *object.Environment) obj
func evalArrayIndexExpression(array, index object.Object) object.Object {
arrayObject := array.(*object.Array)

idx := typeCast(index, object.Int64Kind, true).(*object.Number).GetInt64()
idx := typeCast(index, object.Int64Kind, EXPLICIT_CAST).(*object.Number).GetInt64()
max := int64(len(arrayObject.Elements) - 1)

if idx < 0 || idx > max {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
88 changes: 88 additions & 0 deletions evaluator/eval_infix_expression_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package evaluator

import (
"math/big"
"testing"

"github.com/0xM-D/interpreter/object"
)

func TestStringConcatenation(t *testing.T) {
input := `"Hello" + " " + "World!"`
evaluated := testEval(input)
str, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("object is not String. got=%T (%+v)", evaluated, evaluated)
}
if str.Value != "Hello World!" {
t.Errorf("String has wrong value. got=%q", str.Value)
}
}

func TestBooleanInfixExpression(t *testing.T) {
tests := []struct {
input string

expected bool
}{
{"1 < 2", true},
{"1 > 2", false},
{"1 < 1", false},
{"1 > 1", false},
{"1 == 1", true},
{"1 != 1", false},
{"1 == 2", false},
{"1 != 2", true},
{"true == true", true},
{"false == false", true},
{"true == false", false},
{"true != false", true},
{"false != true", true},
{"(1 < 2) == true", true},
{"(1 < 2) == false", false},
{"(1 > 2) == true", false},
{"(1 > 2) == false", true},
{"true && true", true},
{"false && false", false},
{"false && true", false},
{"true || true", true},
{"false || false", false},
{"false || true", true},
{"(1 < 2) && (2 < 3)", true},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testBooleanObject(t, evaluated, tt.expected)
}
}

func TestFloatInfixExpression(t *testing.T) {

tests := []struct {
input string
expected interface{}
}{
{"5.0", 5.0},
{"-6.0", -6.0},
{"1.1f", float32(1.1)},
{"-5f", float32(-5.0)},
{"-10.22233344f", -float32(10.22233344)},
{"2.0 + 2", 4.0},
{"2.0f * 3", float32(6.0)},
{"5.0 + 5.0f + .5 + 5 - 10", 5.5},
{"2.0 * 2f * 2.0f * 2 * 2", 32.0},
{"-50 + 100 + -50", big.NewInt(0)},
{"5f * 2 + 10f", float32(20)},
{"5 + 2f * 10", float32(25)},
{"20f + 2.0 * -10f", 0.0},
{"51 / 2 * 2f + 10f", float32(60)},
{"2 * (5f + 10.0)", 30.0},
{"3f * 3f * 3f + 10", float32(37.0)},
{"3 * (3f * 3) + 10", float32(37.0)},
{"(5.0f + 10 * 2 + 11f / 3) * 2 + -10", float32(47.333333333333336)},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testNumber(t, evaluated, tt.expected)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand All @@ -7,6 +7,27 @@ import (
"github.com/0xM-D/interpreter/object"
)

func TestArrayLiterals(t *testing.T) {
input := "new []int{1, 2 * 2, 3 + 3}"

evaluated := testEval(input)
result, ok := evaluated.(*object.Array)

if !ok {
t.Fatalf("object is not Array. got=%T (%+v)", evaluated, evaluated)
}

if len(result.Elements) != 3 {
t.Fatalf("array has wrong num of elements. got=%d",
len(result.Elements))
}

testIntegerObject(t, result.Elements[0], big.NewInt(1))
testIntegerObject(t, result.Elements[1], big.NewInt(4))
testIntegerObject(t, result.Elements[2], big.NewInt(6))

}

func TestHashLiterals(t *testing.T) {
input := `let two = "two";
new map{string -> int }{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import "testing"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package evaluator_tests
package evaluator

import (
"math/big"
Expand Down
10 changes: 10 additions & 0 deletions evaluator/eval_string_literal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package evaluator

import (
"github.com/0xM-D/interpreter/ast"
"github.com/0xM-D/interpreter/object"
)

func evalStringLiteral(node *ast.StringLiteral) object.Object {
return &object.String{Value: node.Value}
}
Loading

0 comments on commit 72d7c4c

Please sign in to comment.