diff --git a/builtin/core.wren b/builtin/core.wren index 91695011..da6e46a4 100644 --- a/builtin/core.wren +++ b/builtin/core.wren @@ -41,6 +41,15 @@ class List is Sequence { } return result } + + contains(element) { + for (item in this) { + if (element == item) { + return true + } + } + return false + } } class Range is Sequence {} diff --git a/doc/site/classes.markdown b/doc/site/classes.markdown index f7c9635c..134ffdcf 100644 --- a/doc/site/classes.markdown +++ b/doc/site/classes.markdown @@ -240,6 +240,8 @@ class using `is` when you declare the class: This declares a new class `Pegasus` that inherits from `Unicorn`. +Note that you should not create classes that inherit from the built-in types (Bool, Num, String, Range, List). The built-in types expect their internal bit representation to be very specific and get horribly confused when you invoke one of the inherited built-in methods on the derived type. + The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if `Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from `Unicorn`'s metaclass. In more prosaic terms, this means that static methods diff --git a/example/set.wren b/example/set.wren new file mode 100644 index 00000000..b13f38de --- /dev/null +++ b/example/set.wren @@ -0,0 +1,110 @@ +class Set { + new { + _list = [] + _clean = true + } + + new (list) { + if (list is List) { + _list = list + _clean = false + cleanup + } // raise error? + } + + cleanup { + // Removes duplicates in the underlying list. + if (!_clean) { + var newList = [] + for (element in _list) { + if (!newList.contains(element)) newList.add(element) + } + _list = newList + _clean = true + } + } + + add(element) { + _clean = false + _list.add(element) + } + + remove(element) { + cleanup // Remove duplicates, so we can return early upon deletion. + for (i in 0.._list.count) { + if (_list[i] == element) { + _list.removeAt(i) + return + } + } + } + + contains(element) { + return _list.contains(element) + } + + count { + cleanup + return _list.count + } + + iterate(i) { + cleanup + if (i == null) { + if (count > 0) return 0 + return null + } + if (i < count || i >= count) return false + return i + 1 + } + + iteratorValue(i) { + cleanup + return _list[i] + } + + map(f) { + return new Set(_list.map(f)) + } + + where(f) { + return new Set(_list.where(f)) + } + + |(that) { + // Union + return new Set(_list + that) + } + + +(that) { + // A synonym for | + return this | that + } + + &(that) { + // Intersection + return new Set( + _list.where { |element| + return that.contains(element) + } + that.where { |element| + return _list.contains(element) + }) + } + + -(that) { + // Set minus + return new Set( + _list.where { |element| + return !that.contains(element) + }) + } +} + +var a = "a" +var as = new Set([a, a, a]) + +var b = "b" +var bs = new Set([b, b, b]) + +IO.write((as | bs).contains(b)) +IO.write((as & bs).contains(a)) diff --git a/src/wren_core.c b/src/wren_core.c index 0ee7f528..8e946f38 100644 --- a/src/wren_core.c +++ b/src/wren_core.c @@ -84,6 +84,15 @@ static const char* libSource = " }\n" " return result\n" " }\n" +"\n" +" contains(element) {\n" +" for (item in this) {\n" +" if (element == item) {\n" +" return true\n" +" }\n" +" }\n" +" return false\n" +" }\n" "}\n" "\n" "class Range is Sequence {}\n";