optimizations
This commit is contained in:
@@ -133,6 +133,9 @@ func Eval(ctx context.Context, node ast.Node, env *object.Environment) object.Ob
|
||||
case *ast.IntegerLiteral:
|
||||
return object.Integer{Value: node.Value}
|
||||
|
||||
case *ast.FloatLiteral:
|
||||
return object.Float{Value: node.Value}
|
||||
|
||||
case *ast.Boolean:
|
||||
return nativeBoolToBooleanObject(node.Value)
|
||||
|
||||
@@ -401,6 +404,8 @@ func evalInfixExpression(operator string, left, right object.Object) object.Obje
|
||||
return evalBooleanInfixExpression(operator, left, right)
|
||||
case left.Type() == object.IntegerType && right.Type() == object.IntegerType:
|
||||
return evalIntegerInfixExpression(operator, left, right)
|
||||
case left.Type() == right.Type() && left.Type() == object.FloatType:
|
||||
return evalFloatInfixExpression(operator, left, right)
|
||||
case left.Type() == object.StringType && right.Type() == object.StringType:
|
||||
return evalStringInfixExpression(operator, left, right)
|
||||
|
||||
@@ -409,6 +414,36 @@ func evalInfixExpression(operator string, left, right object.Object) object.Obje
|
||||
}
|
||||
}
|
||||
|
||||
func evalFloatInfixExpression(operator string, left, right object.Object) object.Object {
|
||||
leftVal := left.(object.Float).Value
|
||||
rightVal := right.(object.Float).Value
|
||||
|
||||
switch operator {
|
||||
case "+":
|
||||
return object.Float{Value: leftVal + rightVal}
|
||||
case "-":
|
||||
return object.Float{Value: leftVal - rightVal}
|
||||
case "*":
|
||||
return object.Float{Value: leftVal * rightVal}
|
||||
case "/":
|
||||
return object.Float{Value: leftVal / rightVal}
|
||||
case "<":
|
||||
return nativeBoolToBooleanObject(leftVal < rightVal)
|
||||
case "<=":
|
||||
return nativeBoolToBooleanObject(leftVal <= rightVal)
|
||||
case ">":
|
||||
return nativeBoolToBooleanObject(leftVal > rightVal)
|
||||
case ">=":
|
||||
return nativeBoolToBooleanObject(leftVal >= rightVal)
|
||||
case "==":
|
||||
return nativeBoolToBooleanObject(leftVal == rightVal)
|
||||
case "!=":
|
||||
return nativeBoolToBooleanObject(leftVal != rightVal)
|
||||
default:
|
||||
return NULL
|
||||
}
|
||||
}
|
||||
|
||||
func evalBooleanInfixExpression(operator string, left, right object.Object) object.Object {
|
||||
leftVal := left.(object.Boolean).Value
|
||||
rightVal := right.(object.Boolean).Value
|
||||
|
||||
@@ -57,7 +57,7 @@ func assertEvaluated(t *testing.T, expected interface{}, actual object.Object) {
|
||||
func TestEvalExpressions(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected interface{}
|
||||
expected any
|
||||
}{
|
||||
{"5", 5},
|
||||
{"10", 10},
|
||||
@@ -84,12 +84,15 @@ func TestEvalExpressions(t *testing.T) {
|
||||
{`4 * " "`, " "},
|
||||
{"1 << 2", 4},
|
||||
{"4 >> 2", 1},
|
||||
{"5.0 / 2.0", 2.5},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
evaluated := testEval(tt.input)
|
||||
if expected, ok := tt.expected.(int64); ok {
|
||||
testIntegerObject(t, evaluated, expected)
|
||||
} else if expected, ok := tt.expected.(float64); ok {
|
||||
testFloatObject(t, evaluated, expected)
|
||||
} else if expected, ok := tt.expected.(bool); ok {
|
||||
testBooleanObject(t, evaluated, expected)
|
||||
}
|
||||
@@ -405,17 +408,45 @@ func TestClosures(t *testing.T) {
|
||||
testIntegerObject(t, testEval(input), 4)
|
||||
}
|
||||
|
||||
func TestIntegerLiteral(t *testing.T) {
|
||||
input := `2`
|
||||
|
||||
evaluated := testEval(input)
|
||||
obj, ok := evaluated.(object.Integer)
|
||||
if !ok {
|
||||
t.Fatalf("object is not Integer. got=%T (%+v)", evaluated, evaluated)
|
||||
}
|
||||
|
||||
if obj.Value != 2 {
|
||||
t.Errorf("Integer has wrong value. got=%q", obj.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatLiteral(t *testing.T) {
|
||||
input := `2.5`
|
||||
|
||||
evaluated := testEval(input)
|
||||
obj, ok := evaluated.(object.Float)
|
||||
if !ok {
|
||||
t.Fatalf("object is not Float. got=%T (%+v)", evaluated, evaluated)
|
||||
}
|
||||
|
||||
if obj.Value != 2.5 {
|
||||
t.Errorf("Float has wrong value. got=%f", obj.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringLiteral(t *testing.T) {
|
||||
input := `"Hello World!"`
|
||||
|
||||
evaluated := testEval(input)
|
||||
str, ok := evaluated.(object.String)
|
||||
obj, 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)
|
||||
if obj.Value != "Hello World!" {
|
||||
t.Errorf("String has wrong value. got=%q", obj.Value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,6 +834,20 @@ func testEval(input string) object.Object {
|
||||
return Eval(context.New(), program, env)
|
||||
}
|
||||
|
||||
func testFloatObject(t *testing.T, obj object.Object, expected float64) bool {
|
||||
result, ok := obj.(object.Float)
|
||||
if !ok {
|
||||
t.Errorf("object is not Float. got=%T (%+v)", obj, obj)
|
||||
return false
|
||||
}
|
||||
if result.Value != expected {
|
||||
t.Errorf("object has wrong value. got=%f, want=%f",
|
||||
result.Value, expected)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
|
||||
result, ok := obj.(object.Integer)
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user