From 907affa41a3990f41efe0e5de223b29b51bab94d Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Mon, 7 Dec 2020 19:12:22 -0700 Subject: [PATCH] (range...) --- kiss/src/kiss/Macros.hx | 8 ++++++++ kiss/src/kiss/Prelude.hx | 17 +++++++++++++++++ kiss/src/test/cases/BasicTestCase.hx | 4 ++++ kiss/src/test/cases/BasicTestCase.kiss | 18 ++++++++++++++++-- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/kiss/src/kiss/Macros.hx b/kiss/src/kiss/Macros.hx index 65bc86e3..4811760a 100644 --- a/kiss/src/kiss/Macros.hx +++ b/kiss/src/kiss/Macros.hx @@ -83,6 +83,14 @@ class Macros { CallExp(Symbol("Reflect.callMethod").withPosOf(wholeExp), [callOn, func, args]).withPosOf(wholeExp); }; + macros["range"] = (wholeExp:ReaderExp, exps:Array, k) -> { + wholeExp.checkNumArgs(1, 3, '(range [?min] [max] [?step])'); + var min = if (exps.length > 1) exps[0] else Symbol("0").withPosOf(wholeExp); + var max = if (exps.length > 1) exps[1] else exps[0]; + var step = if (exps.length > 2) exps[2] else Symbol("1").withPosOf(wholeExp); + CallExp(Symbol("Prelude.range").withPosOf(wholeExp), [min, max, step]).withPosOf(wholeExp); + }; + function bodyIf(formName:String, negated:Bool, wholeExp:ReaderExp, args:Array, k) { wholeExp.checkNumArgs(2, null, '($formName [condition] [body...])'); var condition = if (negated) { diff --git a/kiss/src/kiss/Prelude.hx b/kiss/src/kiss/Prelude.hx index 9976a162..2600051f 100644 --- a/kiss/src/kiss/Prelude.hx +++ b/kiss/src/kiss/Prelude.hx @@ -186,6 +186,23 @@ class Prelude { ]; } + // Ranges with a min, exclusive max, and step size, just like Python. + public static function range(min, max, step):Iterator { + if (step <= 0) + throw "(range...) can only count up"; + var count = min; + return { + next: () -> { + var oldCount = count; + count += step; + oldCount; + }, + hasNext: () -> { + count < max; + } + }; + } + public static dynamic function truthy(v:Any) { return switch (Type.typeof(v)) { case TNull: false; diff --git a/kiss/src/test/cases/BasicTestCase.hx b/kiss/src/test/cases/BasicTestCase.hx index 5ee5948c..a3040c78 100644 --- a/kiss/src/test/cases/BasicTestCase.hx +++ b/kiss/src/test/cases/BasicTestCase.hx @@ -246,6 +246,10 @@ class BasicTestCase extends Test { function testMaps() { _testMaps(); } + + function testRange() { + _testRange(); + } } class BasicObject { diff --git a/kiss/src/test/cases/BasicTestCase.kiss b/kiss/src/test/cases/BasicTestCase.kiss index 3040e761..fbd1d183 100644 --- a/kiss/src/test/cases/BasicTestCase.kiss +++ b/kiss/src/test/cases/BasicTestCase.kiss @@ -349,8 +349,22 @@ (doFor =>key value myMap (Assert.isTrue (<= 0 (.indexOf ["hey" "found"] key))) (Assert.isTrue (<= 0 (.indexOf ["you" "me"] value)))) - + // Map destructuring: (let [[=>"hey" v1 =>"found" v2] myMap] (Assert.equals "you" v1) - (Assert.equals "me" v2))) \ No newline at end of file + (Assert.equals "me" v2))) + +(defun _testRange [] + // With just one arg, it's the max: + (deflocal &mut :kiss.List myList (for i (range 5) i)) + (Assert.equals 4 (nth myList -1)) + // with two args, they are min and max: + (set myList (for i (range 3 5) i)) + (Assert.equals 3 (first myList)) + (Assert.equals 4 (last myList)) + // With three args, they are min, max, and step: + (set myList (for i (range 7 17 2) i)) + (Assert.equals 7 (first myList)) + (Assert.equals 9 (second myList)) + (Assert.equals 15 (last myList))) \ No newline at end of file