Category talk:Wren-trait: Difference between revisions

m
→‎Source code: Now uses Wren S/H lexer.
(→‎Source code: Improved the robustness of the iteration classes.)
m (→‎Source code: Now uses Wren S/H lexer.)
 
(4 intermediate revisions by the same user not shown)
Line 1:
===Source code===
<syntaxhighlight lang="ecmascriptwren">/* Module "trait.wren" */
 
/* Cloneable is an abstract class which enables child classes to automatically be
Line 34:
==(other) { compare(other) == 0 }
!=(other) { compare(other) != 0 }
}
 
/* Stepped wraps a Sequence so it can be iterated by steps other than 1. */
class Stepped is Sequence {
// Constructs a new stepped sequence.
construct new(seq, step) {
if (!(seq is Sequence)) Fiber.abort("First argument must be a sequence.")
if (!((step is Num) && step.isInteger && step > 0)) {
Fiber.abort("Second argument must be a positive integer.")
}
_seq = seq
_step = step
}
 
// Ensures a range is ascending before passing it to the constructor.
// It it isn't, returns an empty range. Useful when bounds are variable.
static ascend(range, step) {
if (!(range is Range)) Fiber.abort("First argument must be a range.")
return (range.from <= range.to) ? new(range, step) : 0...0
}
 
// Ensures a range is descending before passing it to the constructor.
// It it isn't, returns an empty range. Useful when bounds are variable.
static descend(range, step) {
if (!(range is Range)) Fiber.abort("First argument must be a range.")
return (range.from >= range.to) ? new(range, step) : 0...0
}
 
// Convenience versions of the above methods which call them with a step of 1.
static ascend(range) { ascend(range, 1) }
static descend(range) { descend(range, 1) }
 
// Iterator protocol methods.
iterate(iterator) {
if (!iterator) {
return _seq.iterate(iterator)
} else {
var count = _step
while (count > 0 && iterator) {
iterator = _seq.iterate(iterator)
count = count - 1
}
return iterator
}
}
 
iteratorValue(iterator) { _seq.iteratorValue(iterator) }
}
 
/*
Reversed wraps a Sequence so it can be iterated in reverse
and by steps other than 1. To ensure this always works, non-lists
are converted internally to lists.
*/
class Reversed is Sequence {
// Constructs a new reversed sequence.
construct new(seq, step) {
if (!(seq is Sequence)) Fiber.abort("First argument must be a sequence.")
if (!((step is Num) && step.isInteger && step > 0)) {
Fiber.abort("Second argument must be a positive integer.")
}
_seq = (seq is List) ? seq : seq.toList
_step = step
}
 
// Convenience method which calls the constructor with a step of 1.
static new(seq) { Reversed.new(seq, 1) }
 
// Iterator protocol methods.
iterate(iterator) {
var it = _seq.iterate(iterator)
if (it == null || it == 0) {
it = _seq.count - 1
} else if (it == false) {
it = _seq.count - 1 - _step
} else {
it = it - 1 - _step
}
return (it >= 0) ? it : false
}
 
iteratorValue(iterator) { _seq.iteratorValue(iterator) }
}
 
/* SeqEntry represents an (index, value) pair for use with the Indexed class. */
class SeqEntry {
// Constructs a new SeqEntry object.
construct new(index, value) {
_index = index
_value = value
}
 
// Properties.
index { _index }
value { _value }
 
// Returns the current instance's string representation.
toString { "%(_index):%(_value)" }
}
 
/*
Indexed wraps a Sequence so its elements can be iterated over
together with their zero-based indices. To ensure this always works, non-lists
are converted internally to lists.
*/
class Indexed is Sequence {
// Constructs a new indexed sequence with a step of 'step' and optionally reversed.
construct new(seq, step, reversed) {
if (!(reversed is Bool)) Fiber.abort("Third argument must be true or false.")
_seq = (seq is List) ? seq : seq.toList
_seq = !reversed ? Stepped.new(_seq, step) : Reversed.new(_seq, step)
}
 
// Constructs a new indexed sequence with a step of 'step' and 'reversed' set to false.
static new(seq, step) { new(seq, step, false) }
 
// Constructs a new indexed sequence with a step of 1 and reversed set to false.
static new(seq) { new(seq, 1, false) }
 
// Iterator protocol methods.
iterate(iterator) { _seq.iterate(iterator) }
 
iteratorValue(iterator) {
return SeqEntry.new(iterator, _seq.iteratorValue(iterator))
}
}
 
Line 226 ⟶ 101:
// Returns the string representation of the current instance.
toString { _obj.toString }
}
 
/*
Const represents a group of individually named read-only values which are
stored internally in a map. Any attempt to change such a value is ignored
though they can be removed from the map.
*/
class Const {
// Returns the value of 'name' if it is present in the internal map
// or null otherwise.
static [name] { (__cmap && __cmap.containsKey(name)) ? __cmap[name] : null }
 
// Associates 'value' with 'name' in the internal map.
// If 'name' is already in the map, the change is ignored.
static [name]=(value) {
if (!__cmap) __cmap = {}
if (!__cmap.containsKey(name)) {
__cmap[name] = value
}
}
 
// Removes 'name' and its associated value from the internal map and returns
// that value. If 'name' was not present in the map, returns null.
static remove(name) { __cmap.remove(name) }
 
// Returns a list of the entries (name/value pairs) in the internal map.
static entries { __cmap.toList }
}
 
/*
Var represents a group of individually named read/write values which are
stored internally in a map. It can be used to simulate the creation of
variables at runtime. It can also be used to allow variable names which would
otherwise be illegal in Wren such as those which include non-ASCII characters.
*/
class Var {
// Returns the value of 'name' if it is present in the internal map
// or null otherwise.
static [name] { (__vmap && __vmap.containsKey(name)) ? __vmap[name] : null }
 
// Associates 'value' with 'name' in the internal map.
// Any existing value is replaced.
static [name]=(value) {
if (!__vmap) __vmap = {}
__vmap[name] = value
}
 
// Removes 'name' and its associated value from the internal map and returns
// that value. If 'name' was not present in the map, returns null.
static remove(name) { __vmap.remove(name) }
 
// Returns a list of the entries (name/value pairs) in the internal map.
static entries { __vmap.toList }
}
 
/* TypedVar is similar to Var except that simulated variables always retain the
same type as they had when they were originally created.
*/
class TypedVar {
// Returns the value of 'name' if it is present in the internal map
// or null otherwise.
static [name] { (__vmap && __vmap.containsKey(name)) ? __vmap[name] : null }
 
// Associates 'value' with 'name' in the internal map.
// Any existing value is replaced. However, it is an error to attempt to replace
// an existing value with a value of a different type.
static [name]=(value) {
if (!__vmap) __vmap = {}
if (!__vmap.containsKey(name)) {
__vmap[name] = value
} else {
var vtype = value.type
var mtype = __vmap[name].type
if (vtype != mtype) {
Fiber.abort("Expecting an item of type %(mtype), got %(vtype).")
} else {
__vmap[name] = value
}
}
}
 
// Removes 'name' and its associated value from the internal map and returns
// that value. If 'name' was not present in the map, returns null.
static remove(name) { __vmap.remove(name) }
 
// Returns a list of the entries (name/value pairs) in the internal map.
static entries { __vmap.toList }
}</syntaxhighlight>
9,476

edits