diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 9e7aa37..62597b4 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -4,6 +4,7 @@ import ( "fmt" "monkey/ast" "monkey/object" + "strings" ) var ( @@ -304,6 +305,18 @@ func evalIntegerPrefixOperatorExpression(operator string, right object.Object) o func evalInfixExpression(operator string, left, right object.Object) object.Object { switch { + + // " " * 4 + case left.Type() == object.STRING_OBJ && right.Type() == object.INTEGER_OBJ: + leftVal := left.(*object.String).Value + rightVal := right.(*object.Integer).Value + return &object.String{Value: strings.Repeat(leftVal, int(rightVal))} + // 4 * " " + case left.Type() == object.INTEGER_OBJ && right.Type() == object.STRING_OBJ: + leftVal := left.(*object.Integer).Value + rightVal := right.(*object.String).Value + return &object.String{Value: strings.Repeat(rightVal, int(leftVal))} + case left.Type() == object.BOOLEAN_OBJ && right.Type() == object.BOOLEAN_OBJ: return evalBooleanInfixExpression(operator, left, right) case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ: diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index c47767a..6cac41c 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -func TestEvalIntegerExpression(t *testing.T) { +func TestEvalExpressions(t *testing.T) { tests := []struct { input string expected interface{} @@ -36,6 +36,8 @@ func TestEvalIntegerExpression(t *testing.T) { {"1 | 2", 3}, {"2 ^ 4", 6}, {"3 & 6", 2}, + {`" " * 4`, " "}, + {`4 * " "`, " "}, } for _, tt := range tests { diff --git a/vm/vm.go b/vm/vm.go index 8828bcb..baed531 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -526,6 +526,18 @@ func (vm *VM) executeBinaryOperation(op code.Opcode) error { rightType := right.Type() switch { + + // " " * 4 + case left.Type() == object.STRING_OBJ && right.Type() == object.INTEGER_OBJ: + leftVal := left.(*object.String).Value + rightVal := right.(*object.Integer).Value + return vm.push(&object.String{Value: strings.Repeat(leftVal, int(rightVal))}) + // 4 * " " + case left.Type() == object.INTEGER_OBJ && right.Type() == object.STRING_OBJ: + leftVal := left.(*object.Integer).Value + rightVal := right.(*object.String).Value + return vm.push(&object.String{Value: strings.Repeat(rightVal, int(leftVal))}) + case leftType == object.BOOLEAN_OBJ && rightType == object.BOOLEAN_OBJ: return vm.executeBinaryBooleanOperation(op, left, right) case leftType == object.INTEGER_OBJ && rightType == object.INTEGER_OBJ: diff --git a/vm/vm_test.go b/vm/vm_test.go index 831972a..c8533b9 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -326,6 +326,8 @@ func TestStringExpressions(t *testing.T) { {`"monkey"`, "monkey"}, {`"mon" + "key"`, "monkey"}, {`"mon" + "key" + "banana"`, "monkeybanana"}, + {`" " * 4`, " "}, + {`4 * " "`, " "}, } runVmTests(t, tests)