Category talk:Wren-trait: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎Source code: Added two more constructors to Stepped class.)
m (→‎Source code: Now uses Wren S/H lexer.)
 
(18 intermediate revisions by the same user not shown)
Line 1: Line 1:
===Source code===
===Source code===
<lang ecmascript>/* Module "trait.wren" */
<syntaxhighlight lang="wren">/* Module "trait.wren" */


/* Cloneable is an abstract class which enables child classes to automatically be
/* Cloneable is an abstract class which enables child classes to automatically be
Line 13: Line 13:
*/
*/
class CloneableSeq is Sequence {
class CloneableSeq is Sequence {
clone() { this } /* to be overridden by child class */
clone() { this } /* to be overridden by child class */
}
}


Line 29: Line 29:


< (other) { compare(other) < 0 }
< (other) { compare(other) < 0 }
> (other) { compare(other) > 0 }
> (other) { compare(other) > 0 }
<=(other) { compare(other) <= 0 }
<=(other) { compare(other) <= 0 }
>=(other) { compare(other) >= 0 }
>=(other) { compare(other) >= 0 }
Line 36: Line 36:
}
}


/* Stepped wraps a Sequence so it can be iterated by steps other than 1. */
/* ByRef wraps a value to enable it to be passed by reference to a method or function. */
class Stepped is Sequence {
class ByRef {
// Constructs a new stepped sequence.
// Constructs a new ByRef object.
construct new(seq, step) {
construct new(value) {
_value = value
if (!(seq is Sequence)) Fiber.abort("First argument must be a sequence.")
_seq = seq
_step = (step < 1) ? 1 : step // minimum step of 1
}
}


// Ensures a range is ascending before passing it to the constructor.
// Properties to get and set the value of the current instance.
value { _value }
// It it isn't, returns an empty range. Useful when bounds are variable.
value=(v) { _value = v }
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
}


// Returns the string representation of the current instance's value.
// Ensures a range is descending before passing it to the constructor.
toString { _value.toString }
// 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
ByKey wraps a reference type object to enable it to be used as a Map key. It does this
by using a counter to create a unique integral key for each such object and maintaining
an internal map which enables the object to be quickly retrieved from its key.
*/
class ByKey {
// Retrieves a ByKey object from its key. Returns null if the key is not present.
static [key] { __map ? __map[key] : null }

// Retrieves a ByKey object's key from the object it wraps.
// If the same object has been wrapped more than once, returns the first key found which may
// not be the lowest. Returns 0 if the object is unwrapped.
static findKey(obj) {
for (me in __map) {
if (me.value.obj == obj) return me.key
}
return 0
}
}


// Returns the number of objects currently in the internal map.
// Iterator protocol methods.
static mapCount { __tally ? __map.count : 0 }
iterate(iterator) {

if (!iterator) {
// Returns the total number of keys created to date.
return _seq.iterate(iterator)
static keyCount { __tally ? __tally : 0 }

// Constructs a new ByKey object.
construct new(obj) {
_obj = obj
if (!__tally) {
__map = {}
__tally = 1
} else {
} else {
var count = _step
__tally = __tally + 1
while (count > 0 && iterator) {
iterator = _seq.iterate(iterator)
count = count - 1
}
return iterator
}
}
_key = __tally
__map[_key] = this
}
}


// Properties
iteratorValue(iterator) { _seq.iteratorValue(iterator) }
obj { _obj } // returns the current instance
key { _key } // returns the current instance's key

// Removes the current instance from the internal map and sets it to null.
unkey() {
__map.remove(_key)
_obj = null
}

// Returns the string representation of the current instance.
toString { _obj.toString }
}
}


/*
/*
Const represents a group of individually named read-only values which are
Reversed wraps a Sequence (other than a range) so it can be iterated in reverse
stored internally in a map. Any attempt to change such a value is ignored
and by steps other than 1.
though they can be removed from the map.
*/
*/
class Reversed is Sequence {
class Const {
// Returns the value of 'name' if it is present in the internal map
// Constructs a new reversed sequence.
// or null otherwise.
construct new(seq, step) {
static [name] { (__cmap && __cmap.containsKey(name)) ? __cmap[name] : null }
if (!(seq is Sequence) || seq is Range) {

Fiber.abort("First argument must be a sequence other than a range.")
// 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
}
}
_seq = seq
_step = (step < 1) ? 1 : step // minimum step of 1
}
}


// Removes 'name' and its associated value from the internal map and returns
// Convenience method which calls the constructor with a step of 1.
// that value. If 'name' was not present in the map, returns null.
static new(seq) { Reversed.new(seq, 1) }
static remove(name) { __cmap.remove(name) }


// Returns a list of the entries (name/value pairs) in the internal map.
// Iterator protocol methods.
static entries { __cmap.toList }
iterate(iterator) {
}
var it = _seq.iterate(iterator)

if (it == null || it == 0) {
/*
it = _seq.count - 1
Var represents a group of individually named read/write values which are
} else if (it == false) {
stored internally in a map. It can be used to simulate the creation of
it = _seq.count - 1 - _step
variables at runtime. It can also be used to allow variable names which would
} else {
otherwise be illegal in Wren such as those which include non-ASCII characters.
it = it - 1 - _step
*/
}
class Var {
return (it >= 0) ? it : false
// 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
iteratorValue(iterator) { _seq.iteratorValue(iterator) }
// 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
// Type aliases for classes in case of any name clashes with other modules.
same type as they had when they were originally created.
var Trait_Cloneable = Cloneable
*/
var Trait_CloneableSeq = CloneableSeq
class TypedVar {
var Trait_Comparable = Comparable
// Returns the value of 'name' if it is present in the internal map
var Trait_Stepped = Stepped
// or null otherwise.
var Trait_Reversed = Reversed</lang>
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>

Latest revision as of 11:54, 3 November 2023

Source code

/* Module "trait.wren" */

/* Cloneable is an abstract class which enables child classes to automatically be
   recognized as 'cloneable' by overriding the 'clone' method.
*/
class Cloneable {
    clone() { this } /* to be overridden by child class */
}

/* CloneableSeq is an abstract class which enables child classes to automatically be
   recognized as both Sequences and 'cloneable' by overriding the 'clone' method.
*/
class CloneableSeq is Sequence {
    clone() { this } /* to be overridden by child class */
}

/*
    Comparable is an abstract class which enables child classes to automatically
    inherit the comparison operators by just overriding the 'compare' method.
    Comparable itself inherits from Cloneable though if one does not wish to override
    the 'clone' method, it will just return the current object by default.
*/
class Comparable is Cloneable {
    compare(other) {
        // This should be overridden in child classes to return -1, 0 or +1
        // depending on whether this < other, this == other or this > other.
    }

    < (other) { compare(other) <  0 }
    > (other) { compare(other) >  0 }
    <=(other) { compare(other) <= 0 }
    >=(other) { compare(other) >= 0 }
    ==(other) { compare(other) == 0 }
    !=(other) { compare(other) != 0 }
}

/*  ByRef wraps a value to enable it to be passed by reference to a method or function. */
class ByRef {
    // Constructs a new ByRef object.
    construct new(value) {
        _value = value
    }

    // Properties to get and set the value of the current instance.
    value     { _value }
    value=(v) { _value = v }

    // Returns the string representation of the current instance's value.
    toString { _value.toString }
}

/*
    ByKey wraps a reference type object to enable it to be used as a Map key. It does this
    by using a counter to create a unique integral key for each such object and maintaining
    an internal map which enables the object to be quickly retrieved from its key.
*/
class ByKey {
    // Retrieves a ByKey object from its key. Returns null if the key is not present.
    static [key] { __map ? __map[key] : null }

    // Retrieves a ByKey object's key from the object it wraps.
    // If the same object has been wrapped more than once, returns the first key found which may
    // not be the lowest. Returns 0 if the object is unwrapped.
    static findKey(obj) {
        for (me in __map) {
            if (me.value.obj == obj) return me.key
        }
        return 0
    }

    // Returns the number of objects currently in the internal map.
    static mapCount { __tally ? __map.count : 0 }

    // Returns the total number of keys created to date.
    static keyCount { __tally ? __tally : 0 }

    // Constructs a new ByKey object.
    construct new(obj) {
        _obj = obj
        if (!__tally) {
            __map = {}
            __tally = 1
        } else {
            __tally = __tally + 1
        }
        _key = __tally
        __map[_key] = this
    }

    // Properties
    obj { _obj }  // returns the current instance
    key { _key }  // returns the current instance's key

    // Removes the current instance from the internal map and sets it to null.
    unkey() {
        __map.remove(_key)
        _obj = null
    }

    // 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 }
}