diff --git a/builtin/core.wren b/builtin/core.wren index d1e406d6..54b48f3b 100644 --- a/builtin/core.wren +++ b/builtin/core.wren @@ -42,6 +42,20 @@ class Sequence { return result } + join { join("") } + + join(sep) { + var first = true + var result = "" + + for (element in this) { + if (!first) result = result + sep + first = false + result = result + element.toString + } + + return result + } } class String is Sequence {} @@ -54,15 +68,7 @@ class List is Sequence { return other } - toString { - var result = "[" - for (i in 0...count) { - if (i > 0) result = result + ", " - result = result + this[i].toString - } - result = result + "]" - return result - } + toString { "[" + join(", ") + "]" } +(other) { var result = this[0..-1] diff --git a/doc/site/core/sequence.markdown b/doc/site/core/sequence.markdown index 4ed8c942..af55277e 100644 --- a/doc/site/core/sequence.markdown +++ b/doc/site/core/sequence.markdown @@ -18,6 +18,17 @@ If it returns `false`, stops iterating and returns `false`. Otherwise, returns [1, 2, 3].all {|n| n > 2} // False. [1, 2, 3].all {|n| n < 4} // True. +### **join**(sep) + +Returns a string representation of the list. The string representations of the +elements in the list is concatenated with intervening occurrences of `sep`. + +It is a runtime error if `sep` is not a string. + +### **join** + +Calls `join` with the empty string as the separator. + ### **map**(transformation) Creates a new list by applying `transformation` to each element in the diff --git a/src/wren_core.c b/src/wren_core.c index b551f701..d8db5cf5 100644 --- a/src/wren_core.c +++ b/src/wren_core.c @@ -85,6 +85,20 @@ static const char* libSource = " return result\n" " }\n" "\n" +" join { join(\"\") }\n" +"\n" +" join(sep) {\n" +" var first = true\n" +" var result = \"\"\n" +"\n" +" for (element in this) {\n" +" if (!first) result = result + sep\n" +" first = false\n" +" result = result + element.toString\n" +" }\n" +"\n" +" return result\n" +" }\n" "}\n" "\n" "class String is Sequence {}\n" @@ -97,15 +111,7 @@ static const char* libSource = " return other\n" " }\n" "\n" -" toString {\n" -" var result = \"[\"\n" -" for (i in 0...count) {\n" -" if (i > 0) result = result + \", \"\n" -" result = result + this[i].toString\n" -" }\n" -" result = result + \"]\"\n" -" return result\n" -" }\n" +" toString { \"[\" + join(\", \") + \"]\" }\n" "\n" " +(other) {\n" " var result = this[0..-1]\n" diff --git a/test/list/join.wren b/test/list/join.wren new file mode 100644 index 00000000..12a39307 --- /dev/null +++ b/test/list/join.wren @@ -0,0 +1,23 @@ +// Handle empty list. +IO.print([].join(",") == "") // expect: true + +// Handle a simple list with an empty delimeter. +IO.print([1, 2, 3].join("")) // expect: 123 + +// Handle a simple list with no separator. +IO.print([1, 2, 3].join) // expect: 123 + +// Does not quote strings. +IO.print([1, "2", true].join(",")) // expect: 1,2,true + +// Nested lists. +IO.print([1, [2, [3], 4], 5].join(",")) // expect: 1,[2, [3], 4],5 + +// Calls toString on elements. +class Foo { + toString { "Foo.toString" } +} + +IO.print([1, new Foo, 2].join(", ")) // expect: 1, Foo.toString, 2 + +// TODO: Handle lists that contain themselves. diff --git a/test/list/join_sep_non_string.wren b/test/list/join_sep_non_string.wren new file mode 100644 index 00000000..d63d83f4 --- /dev/null +++ b/test/list/join_sep_non_string.wren @@ -0,0 +1 @@ +[1, 2, 3].join(2) // expect runtime error: Right operand must be a string. diff --git a/test/range/join.wren b/test/range/join.wren new file mode 100644 index 00000000..81c336a1 --- /dev/null +++ b/test/range/join.wren @@ -0,0 +1,4 @@ +var a = 1..3 + +IO.print(a.join) // expect: 123 +IO.print(a.join(", ")) // expect: 1, 2, 3 diff --git a/test/range/join_sep_non_string.wren b/test/range/join_sep_non_string.wren new file mode 100644 index 00000000..7dfccf99 --- /dev/null +++ b/test/range/join_sep_non_string.wren @@ -0,0 +1 @@ +(1..3).join(2) // expect runtime error: Right operand must be a string. diff --git a/test/string/join.wren b/test/string/join.wren new file mode 100644 index 00000000..6c1183c1 --- /dev/null +++ b/test/string/join.wren @@ -0,0 +1,5 @@ +var str = "string" + +IO.print(str.join("") == str) // expect: true + +IO.print(str.join(", ")) // expect: s, t, r, i, n, g diff --git a/test/string/join_sep_non_string.wren b/test/string/join_sep_non_string.wren new file mode 100644 index 00000000..feaaa5aa --- /dev/null +++ b/test/string/join_sep_non_string.wren @@ -0,0 +1 @@ +"string".join(2) // // expect runtime error: Right operand must be a string.