Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

29 Add new integer types #59

Merged
merged 8 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion ast/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ast

import (
"math/big"

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

Expand Down Expand Up @@ -58,7 +60,7 @@ type Identifier struct {

type IntegerLiteral struct {
Token token.Token
Value int64
Value big.Int
}

type Float32Literal struct {
Expand Down
359 changes: 205 additions & 154 deletions evaluator/eval_infix_expression.go

Large diffs are not rendered by default.

28 changes: 9 additions & 19 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package evaluator

import (
"math"

"github.com/0xM-D/interpreter/ast"
"github.com/0xM-D/interpreter/object"
)
Expand All @@ -12,11 +14,11 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
case *ast.ExpressionStatement:
return Eval(node.Expression, env)
case *ast.IntegerLiteral:
return &object.Number[int64]{Value: node.Value}
return evalIntegerLiteral(node, env)
case *ast.Float32Literal:
return &object.Number[float32]{Value: node.Value}
return &object.Number{Value: uint64(math.Float32bits(node.Value)), Kind: object.Float32Kind}
case *ast.Float64Literal:
return &object.Number[float64]{Value: node.Value}
return &object.Number{Value: math.Float64bits(node.Value), Kind: object.Float64Kind}
case *ast.Boolean:
return nativeBoolToBooleanObject(node.Value)
case *ast.PrefixExpression:
Expand All @@ -38,10 +40,7 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
}
return &object.ReturnValue{Value: val, ReturnValueObjectType: object.ReturnValueObjectType{ReturnType: val.Type()}}
case *ast.LetStatement:
error := declareVariable(&(*node).DeclarationStatement, nil, env)
if error != nil {
return error
}
return evalDeclarationStatement(&(*node).DeclarationStatement, env)
case *ast.Identifier:
return evalIdentifier(node, env)
case *ast.FunctionLiteral:
Expand Down Expand Up @@ -79,20 +78,11 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
}
return evalAccessExpression(object.UnwrapReferenceObject(left), right.Value, env)
case *ast.TypedDeclarationStatement:
error := evalDeclarationStatement(&(*node).DeclarationStatement, env)
if error != nil {
return error
}
return evalDeclarationStatement(&(*node).DeclarationStatement, env)
case *ast.AssignmentDeclarationStatement:
error := evalDeclarationStatement(&(*node).DeclarationStatement, env)
if error != nil {
return error
}
return evalDeclarationStatement(&(*node).DeclarationStatement, env)
case *ast.ForStatement:
error := evalForStatement(node, env)
if error != nil {
return error
}
return evalForStatement(node, env)
case *ast.TernaryExpression:
return evalTernaryExpression(node, env)
case *ast.TypeCastExpression:
Expand Down
7 changes: 4 additions & 3 deletions evaluator/tests/array_literals_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator_tests

import (
"math/big"
"testing"

"github.com/0xM-D/interpreter/object"
Expand All @@ -21,8 +22,8 @@ func TestArrayLiterals(t *testing.T) {
len(result.Elements))
}

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

}
7 changes: 5 additions & 2 deletions evaluator/tests/assignment_declaration_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package evaluator_tests

import "testing"
import (
"math/big"
"testing"
)

func TestAssignmentDeclaration(t *testing.T) {
tests := []struct {
Expand All @@ -13,6 +16,6 @@ func TestAssignmentDeclaration(t *testing.T) {
{"a := 5; let b = a; let c = a + b + 5; c;", 15},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), tt.expected)
testIntegerObject(t, testEval(tt.input), big.NewInt(tt.expected))
}
}
21 changes: 11 additions & 10 deletions evaluator/tests/assignment_expression_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
package evaluator_tests

import "testing"
import (
"math/big"
"testing"
)

func TestAsignmentExpression(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{"let a = 5; a = 3;", 3},
{"a := 5 * 5; a += 20;", 45},
{"a := 3; b := a; a += b", 6},
{"a := 5; a -= 1", 4},
{"a := 5; a *= 2", 10},
{"a := 50; a /= 5", 10},
{"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 int:
testIntegerObject(t, testEval(tt.input), int64(expected))
case int64:
case *big.Int:
testIntegerObject(t, testEval(tt.input), expected)
case string:
testStringObject(t, testEval(tt.input), expected)
Expand Down
20 changes: 10 additions & 10 deletions evaluator/tests/error_handling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ func TestErrorHandling(t *testing.T) {
}{
{
"5 + true;",
"operator + not defined on types int and bool",
"operator + not defined on types int64 and bool",
},
{
"5 + true; 5;",
"operator + not defined on types int and bool",
"operator + not defined on types int64 and bool",
},
{
"-true",
"unknown operator: -bool",
"Operator - not defined on type bool",
},
{
"true + false;",
Expand Down Expand Up @@ -56,7 +56,7 @@ func TestErrorHandling(t *testing.T) {
},
{
`int a = "fasdf"`,
"Expression of type string cannot be assigned to int",
"Expression of type string cannot be assigned to int64",
},
{
`a := "fasdf"; bool c = a;`,
Expand All @@ -71,7 +71,7 @@ func TestErrorHandling(t *testing.T) {
"Cannot assign to const variable",
},
{
`const int a = 3; a = 5*6;`,
`const int32 a = 3; a = 5*6;`,
"Cannot assign to const variable",
},
{
Expand All @@ -80,27 +80,27 @@ func TestErrorHandling(t *testing.T) {
},
{
`a := 3; a += "test"`,
"operator += not defined on types int and string",
"operator += not defined on types int64 and string",
},
{
`bool a = true; a += true`,
"operator += not defined on types bool and bool",
},
{
`const int a = 3; a += 1`,
`const int64 a = 3; a += 1`,
"Cannot assign to const variable",
},
{
`fun := fn()->void {}; fun(1)`,
"Incorrect parameter count for function() -> void fun. expected=0, got=1",
},
{
`fun := fn(a: int, b: int)->int { return a + b; }; fun()`,
"Incorrect parameter count for function(int, int) -> int fun. expected=2, got=0",
`fun := fn(a: int64, b: int64)->int64 { return a + b; }; fun()`,
"Incorrect parameter count for function(int64, int64) -> int64 fun. expected=2, got=0",
},
{
`new []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.deleteee(1, 3)`,
"Member deleteee does not exist on int[]",
"Member deleteee does not exist on []int64",
},
}
for _, tt := range tests {
Expand Down
6 changes: 5 additions & 1 deletion evaluator/tests/eval_float_exp_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator_tests

import (
"math/big"
"testing"
)

Expand All @@ -11,12 +12,15 @@ func TestEvalFloatExpression(t *testing.T) {
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", 0},
{"-50 + 100 + -50", big.NewInt(0)},
{"5f * 2 + 10f", float32(20)},
{"5 + 2f * 10", float32(25)},
{"20f + 2.0 * -10f", 0.0},
Expand Down
71 changes: 36 additions & 35 deletions evaluator/tests/eval_integer_exp_test.go
Original file line number Diff line number Diff line change
@@ -1,48 +1,49 @@
package evaluator_tests

import (
"math/big"
"testing"
)

func TestEvalIntegerExpression(t *testing.T) {
tests := []struct {
input string
expected int64
expected *big.Int
}{
{"5", 5},
{"10", 10},
{"-5", -5},
{"-10", -10},
{"5 + 5 + 5 + 5 - 10", 10},
{"2 * 2 * 2 * 2 * 2", 32},
{"-50 + 100 + -50", 0},
{"5 * 2 + 10", 20},
{"5 + 2 * 10", 25},
{"20 + 2 * -10", 0},
{"50 / 2 * 2 + 10", 60},
{"2 * (5 + 10)", 30},
{"3 * 3 * 3 + 10", 37},
{"3 * (3 * 3) + 10", 37},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
{"1 << 1", 2},
{"1 << 62", 1 << 62},
{"1 << 63 >> 1", -(1 << 63 >> 1)},
{"1 << 64 >> 2", 0},
{"1 >> 1", 0},
{"256 >> 2", 64},
{"3 >> 1", 1},
{"3 << 1", 6},
{"1 | 3", 3},
{"4097 | 272", 4369},
{"0 | 272", 272},
{"0 | 0", 0},
{"0 & 0", 0},
{"0 & 1", 0},
{"4097 & 272", 0},
{"7 & 3", 3},
{"~0", ^0},
{"((1 << 10) - 1) ^ (1 << 8)", ((1 << 10) - 1) ^ (1 << 8)},
{"~123", ^123},
{"5", big.NewInt(5)},
{"10", big.NewInt(10)},
{"-5", big.NewInt(-5)},
{"-10", big.NewInt(-10)},
{"5 + 5 + 5 + 5 - 10", big.NewInt(10)},
{"2 * 2 * 2 * 2 * 2", big.NewInt(32)},
{"-50 + 100 + -50", big.NewInt(0)},
{"5 * 2 + 10", big.NewInt(20)},
{"5 + 2 * 10", big.NewInt(25)},
{"20 + 2 * -10", big.NewInt(0)},
{"50 / 2 * 2 + 10", big.NewInt(60)},
{"2 * (5 + 10)", big.NewInt(30)},
{"3 * 3 * 3 + 10", big.NewInt(37)},
{"3 * (3 * 3) + 10", big.NewInt(37)},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", big.NewInt(50)},
{"1 << 1", big.NewInt(2)},
{"1 << 62", big.NewInt(4611686018427387904)},
{"1 << 63 >> 1", big.NewInt(1 << 63 >> 1)},
{"1 << 64 >> 2", big.NewInt(0)},
{"1 >> 1", big.NewInt(0)},
{"256 >> 2", big.NewInt(64)},
{"3 >> 1", big.NewInt(1)},
{"3 << 1", big.NewInt(6)},
{"1 | 3", big.NewInt(3)},
{"4097 | 272", big.NewInt(4369)},
{"0 | 272", big.NewInt(272)},
{"0 | 0", big.NewInt(0)},
{"0 & 0", big.NewInt(0)},
{"0 & 1", big.NewInt(0)},
{"4097 & 272", big.NewInt(0)},
{"7 & 3", big.NewInt(3)},
{"~0", big.NewInt(^0)},
{"((1 << 10) - 1) ^ (1 << 8)", big.NewInt(int64((1<<10)-1) ^ (1 << 8))},
{"~123", big.NewInt(^123)},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
Expand Down
8 changes: 4 additions & 4 deletions evaluator/tests/for_statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ func TestForStatement(t *testing.T) {
input string
expected interface{}
}{
{`string a = ""; for(int i = 0; i < 10; i+=1) { a += "a" }; a`, "aaaaaaaaaa"},
{"int x = 55; for(int i = 10; i >= 0; i-=1) { x -= i }; x", 0},
{"int i = 0; for(; i < 20; i+=1) {}; i", 20},
{"int i = 5; for(; i > 0 ;) { i-=1 } i", 0},
{`string a = ""; for(int8 i = 0; i < 10; i+=1) { a += "a" }; a`, "aaaaaaaaaa"},
{"let x = 55; for(int16 i = 10; i >= 0; i-=1) { x -= i }; x", 0},
{"let i = 0; for(; i < 20; i+=1) {}; i", 20},
{"let i = 5; for(; i > 0 ;) { i-=1 } i", 0},
}
for _, tt := range tests {
testLiteralObject(t, testEval(tt.input), tt.expected)
Expand Down
21 changes: 12 additions & 9 deletions evaluator/tests/function_application_test.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
package evaluator_tests

import "testing"
import (
"math/big"
"testing"
)

func TestFunctionApplication(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"let identity = fn(x: int) -> int { x; }; identity(5);", 5},
{"let identity = fn(x: int) -> int { return x; }; identity(5);", 5},
{"let double = fn(x: int) -> int { x * 2; }; double(5);", 10},
{"let add = fn(x: int, y: int) -> int { x + y; }; add(5, 5);", 10},
{"let add = fn(x: int, y: int) -> int { x + y; }; add(5 + 5, add(5, 5));", 20},
{"fn(x: int)-> int { x; }(5)", 5},
{"a := 3; b := 4; let add = fn(x: int, y: int) -> int { x + y; }; add(a, b);", 7},
{"let identity = fn(x: int8) -> int8 { x; }; identity(5);", 5},
{"let identity = fn(x: int16) -> int16 { return x; }; identity(5);", 5},
{"let double = fn(x: int32) -> int32 { x * 2; }; double(5);", 10},
{"let add = fn(x: int64, y: int32) -> int64 { x + y; }; add(5, 5);", 10},
{"let add = fn(x: int64, y: int64) -> int64 { x + y; }; add(5 + 5, add(5, 5));", 20},
{"fn(x: uint8)-> uint8 { x; }(5)", 5},
{"a := 3; b := 4; let add = fn(x: uint32, y: uint32) -> uint32 { x + y; }; add(a, b);", 7},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), tt.expected)
testIntegerObject(t, testEval(tt.input), big.NewInt(tt.expected))
}
}
2 changes: 1 addition & 1 deletion evaluator/tests/function_object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

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

evaluated := testEval(input)
fn, ok := evaluated.(*object.Function)
Expand Down
Loading