From d46dfc95005eb5c0aa7fdea79e20d9bb457e7244 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Wed, 24 Feb 2016 07:48:03 -0800 Subject: [PATCH] Allow "*" on lists and strings to repeat them. This is not implemented on Sequence because, at least for lists and strings, I think users expect an eager result. Multiplying a string should give you back a string, not a lazy sequence of repeated characters. This also mirrors "+" on strings and lists, which is eager. I like the idea of having a general guideline that operators are eager. Repetition is useful for arbitrary sequences, but for that maybe we should add a "repeat()" method. --- src/vm/wren_core.wren | 24 ++++++++++++++++++++++++ src/vm/wren_core.wren.inc | 24 ++++++++++++++++++++++++ test/core/list/multiply.wren | 8 ++++++++ test/core/list/multiply_negative.wren | 1 + test/core/list/multiply_not_int.wren | 1 + test/core/list/multiply_not_num.wren | 1 + test/core/list/plus.wren | 23 ++++++++--------------- test/core/list/plus_not_iterable.wren | 1 + test/core/string/multiply.wren | 3 +++ test/core/string/multiply_negative.wren | 1 + test/core/string/multiply_not_int.wren | 1 + test/core/string/multiply_not_num.wren | 1 + 12 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 test/core/list/multiply.wren create mode 100644 test/core/list/multiply_negative.wren create mode 100644 test/core/list/multiply_not_int.wren create mode 100644 test/core/list/multiply_not_num.wren create mode 100644 test/core/list/plus_not_iterable.wren create mode 100644 test/core/string/multiply.wren create mode 100644 test/core/string/multiply_negative.wren create mode 100644 test/core/string/multiply_not_int.wren create mode 100644 test/core/string/multiply_not_num.wren diff --git a/src/vm/wren_core.wren b/src/vm/wren_core.wren index e88808cf..973e9e16 100644 --- a/src/vm/wren_core.wren +++ b/src/vm/wren_core.wren @@ -131,6 +131,18 @@ class WhereSequence is Sequence { class String is Sequence { bytes { StringByteSequence.new(this) } codePoints { StringCodePointSequence.new(this) } + + *(count) { + if (!(count is Num) || !count.isInteger || count < 0) { + Fiber.abort("Count must be a non-negative integer.") + } + + var result = "" + for (i in 0...count) { + result = result + this + } + return result + } } class StringByteSequence is Sequence { @@ -174,6 +186,18 @@ class List is Sequence { } return result } + + *(count) { + if (!(count is Num) || !count.isInteger || count < 0) { + Fiber.abort("Count must be a non-negative integer.") + } + + var result = [] + for (i in 0...count) { + result.addAll(this) + } + return result + } } class Map { diff --git a/src/vm/wren_core.wren.inc b/src/vm/wren_core.wren.inc index 4c420683..d14b5399 100644 --- a/src/vm/wren_core.wren.inc +++ b/src/vm/wren_core.wren.inc @@ -133,6 +133,18 @@ static const char* coreModuleSource = "class String is Sequence {\n" " bytes { StringByteSequence.new(this) }\n" " codePoints { StringCodePointSequence.new(this) }\n" +"\n" +" *(count) {\n" +" if (!(count is Num) || !count.isInteger || count < 0) {\n" +" Fiber.abort(\"Count must be a non-negative integer.\")\n" +" }\n" +"\n" +" var result = \"\"\n" +" for (i in 0...count) {\n" +" result = result + this\n" +" }\n" +" return result\n" +" }\n" "}\n" "\n" "class StringByteSequence is Sequence {\n" @@ -176,6 +188,18 @@ static const char* coreModuleSource = " }\n" " return result\n" " }\n" +"\n" +" *(count) {\n" +" if (!(count is Num) || !count.isInteger || count < 0) {\n" +" Fiber.abort(\"Count must be a non-negative integer.\")\n" +" }\n" +"\n" +" var result = []\n" +" for (i in 0...count) {\n" +" result.addAll(this)\n" +" }\n" +" return result\n" +" }\n" "}\n" "\n" "class Map {\n" diff --git a/test/core/list/multiply.wren b/test/core/list/multiply.wren new file mode 100644 index 00000000..60b528dd --- /dev/null +++ b/test/core/list/multiply.wren @@ -0,0 +1,8 @@ +System.print([1, 2, 3] * 0) // expect: [] +System.print([1, 2, 3] * 1) // expect: [1, 2, 3] +System.print([1, 2, 3] * 4) // expect: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] + +// Doesn't modify original list. +var a = [1, 2, 3] +a * 5 +System.print(a) // expect: [1, 2, 3] diff --git a/test/core/list/multiply_negative.wren b/test/core/list/multiply_negative.wren new file mode 100644 index 00000000..740c2189 --- /dev/null +++ b/test/core/list/multiply_negative.wren @@ -0,0 +1 @@ +[1, 2, 3] * -3 // expect runtime error: Count must be a non-negative integer. diff --git a/test/core/list/multiply_not_int.wren b/test/core/list/multiply_not_int.wren new file mode 100644 index 00000000..0eebf191 --- /dev/null +++ b/test/core/list/multiply_not_int.wren @@ -0,0 +1 @@ +[1, 2, 3] * 1.2 // expect runtime error: Count must be a non-negative integer. diff --git a/test/core/list/multiply_not_num.wren b/test/core/list/multiply_not_num.wren new file mode 100644 index 00000000..fbf2a387 --- /dev/null +++ b/test/core/list/multiply_not_num.wren @@ -0,0 +1 @@ +[1, 2, 3] * "not num" // expect runtime error: Count must be a non-negative integer. diff --git a/test/core/list/plus.wren b/test/core/list/plus.wren index 98cf60ea..53969333 100644 --- a/test/core/list/plus.wren +++ b/test/core/list/plus.wren @@ -1,18 +1,11 @@ -var a = [1, 2, 3] -var b = [4, 5, 6] -var c = a + b -var d = a + (4..6) -var e = a + [] -var f = [] + a -var g = [] + [] - -System.print(a) // expect: [1, 2, 3] -System.print(b) // expect: [4, 5, 6] -System.print(c) // expect: [1, 2, 3, 4, 5, 6] -System.print(d) // expect: [1, 2, 3, 4, 5, 6] -System.print(e) // expect: [1, 2, 3] -System.print(f) // expect: [1, 2, 3] -System.print(g) // expect: [] +System.print([1, 2, 3] + [4, 5, 6]) // expect: [1, 2, 3, 4, 5, 6] +System.print([1, 2, 3] + (4..6)) // expect: [1, 2, 3, 4, 5, 6] +System.print([1, 2, 3] + "abc") // expect: [1, 2, 3, a, b, c] +System.print([] + []) // expect: [] +System.print([1, 2] + []) // expect: [1, 2] +System.print([] + [3, 4]) // expect: [3, 4] // Doesn't modify original list. +var a = [1, 2, 3] +a * 5 System.print(a) // expect: [1, 2, 3] diff --git a/test/core/list/plus_not_iterable.wren b/test/core/list/plus_not_iterable.wren new file mode 100644 index 00000000..131ff762 --- /dev/null +++ b/test/core/list/plus_not_iterable.wren @@ -0,0 +1 @@ +[1, 2, 3] + 4 // expect runtime error: Num does not implement 'iterate(_)'. diff --git a/test/core/string/multiply.wren b/test/core/string/multiply.wren new file mode 100644 index 00000000..b3479483 --- /dev/null +++ b/test/core/string/multiply.wren @@ -0,0 +1,3 @@ +System.print("|" + "abc" * 0 + "|") // expect: || +System.print("abc" * 1) // expect: abc +System.print("abc" * 4) // expect: abcabcabcabc diff --git a/test/core/string/multiply_negative.wren b/test/core/string/multiply_negative.wren new file mode 100644 index 00000000..61311818 --- /dev/null +++ b/test/core/string/multiply_negative.wren @@ -0,0 +1 @@ +"abc" * -3 // expect runtime error: Count must be a non-negative integer. diff --git a/test/core/string/multiply_not_int.wren b/test/core/string/multiply_not_int.wren new file mode 100644 index 00000000..75111486 --- /dev/null +++ b/test/core/string/multiply_not_int.wren @@ -0,0 +1 @@ +"abc" * 1.2 // expect runtime error: Count must be a non-negative integer. diff --git a/test/core/string/multiply_not_num.wren b/test/core/string/multiply_not_num.wren new file mode 100644 index 00000000..d6f40444 --- /dev/null +++ b/test/core/string/multiply_not_num.wren @@ -0,0 +1 @@ +"abc" * "not num" // expect runtime error: Count must be a non-negative integer.