Skip to content

Commit

Permalink
Fix the range-operator for "backwards" ranges.
Browse files Browse the repository at this point in the history
This pull-request closes #98, by ensuring that the range operator
(`..`) can count down as well as up.  This allows ranges such as:

* 3..10
* 4..0

However note that the first number cannot be negative, as that's
then treated as "- [1, 2..]" - i.e. negative array, which makes
no sense.  This should be resolved, but it is a bigger job.
  • Loading branch information
skx committed Nov 22, 2023
1 parent 2aa97a9 commit 6bb0866
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
21 changes: 19 additions & 2 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,12 +448,29 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje
case "!=":
return nativeBoolToBooleanObject(leftVal != rightVal)
case "..":
len := int(rightVal-leftVal) + 1
// The start and end might not be ascending, so the size
// will be the span
diff := float64(rightVal - leftVal)
len := int(math.Abs(diff)) + 1

// Step is generally +1, but if we're going to
// express the range "10..0" it will be -1 to allow
// us to count down via subtraction
var step int64
step = 1.0

if rightVal < leftVal {
step = -1.0
}

// Make an array to hold the return value
array := make([]object.Object, len)

// Now make the range of integers, counting via the step.
i := 0
for i < len {
array[i] = &object.Integer{Value: leftVal}
leftVal++
leftVal += step
i++
}
return &object.Array{Elements: array}
Expand Down
24 changes: 24 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -721,3 +721,27 @@ if (match( "+", name) ) { puts( "Hello\n" ); }
}

}

func TestRangeOperator(t *testing.T) {
tests := []struct {
input string
expected string
}{
// normal
{"return 0..3;", "[0, 1, 2, 3]"},
{"return 0..1;", "[0, 1]"},
{"return 0..0;", "[0]"},
{"a = -3; b = 3; return a..b;", "[-3, -2, -1, 0, 1, 2, 3]"},
// reversed
{"return 3..0;", "[3, 2, 1, 0]"},
{"return 1..0;", "[1, 0]"},
{"return 0..0;", "[0]"},
{"return 3..-5;", "[3, 2, 1, 0, -1, -2, -3, -4, -5]"},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
if tt.expected != evaluated.Inspect() {
t.Fatalf("unexpected output for range operator, got %s for input %s", evaluated.Inspect(), tt.input)
}
}
}

0 comments on commit 6bb0866

Please sign in to comment.