pkg/list: adding range function as a builtin

this commit adds a range function which allows to generate a sequence
of numbers from a start point adding steps till a limit is reached.

For instance:

   Range(0, 5, 2)

results in

   [0, 2, 4]

Change-Id: I29eddca25c4c5206c226d518d617b7b69ab8852e
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3483
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/pkg/list/math.go b/pkg/list/math.go
index 4ce4ba3..d91adb5 100644
--- a/pkg/list/math.go
+++ b/pkg/list/math.go
@@ -86,6 +86,52 @@
 	return d, nil
 }
 
+// Range generates a list of numbers using a start value, a limit value, and a
+// step value.
+//
+// For instance:
+//
+//    Range(0, 5, 2)
+//
+// results in
+//
+//    [0, 2, 4]
+//
+func Range(start, limit, step *internal.Decimal) ([]*internal.Decimal, error) {
+	if step.IsZero() {
+		return nil, fmt.Errorf("step must be non zero")
+	}
+
+	if !step.Negative && +1 == start.Cmp(limit) {
+		return nil, fmt.Errorf("end must be greater than start when step is positive")
+	}
+
+	if step.Negative && -1 == start.Cmp(limit) {
+		return nil, fmt.Errorf("end must be less than start when step is negative")
+	}
+
+	var vals []*internal.Decimal
+	num := start
+	for {
+		if !step.Negative && -1 != num.Cmp(limit) {
+			break
+		}
+
+		if step.Negative && +1 != num.Cmp(limit) {
+			break
+		}
+
+		vals = append(vals, num)
+		d := apd.New(0, 0)
+		_, err := internal.BaseContext.Add(d, step, num)
+		if err != nil {
+			return nil, err
+		}
+		num = d
+	}
+	return vals, nil
+}
+
 // Sum returns the sum of a list non empty xs.
 func Sum(xs []*internal.Decimal) (*internal.Decimal, error) {
 	d := apd.New(0, 0)