fix #10 set
+collection functions (map, forEach, toList, toSet, isEmpty, etc,)
This commit is contained in:
		
							parent
							
								
									8a4363bd84
								
							
						
					
					
						commit
						a4448ab2ff
					
				
							
								
								
									
										13
									
								
								docs/Collection.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								docs/Collection.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
# Collection
 | 
			
		||||
 | 
			
		||||
Is a [Iterable] with known `size`, a finite [Iterable]:
 | 
			
		||||
 | 
			
		||||
    class Collection : Iterable {
 | 
			
		||||
        val size
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
See [List], [Set] and [Iterable]
 | 
			
		||||
 | 
			
		||||
[Iterable]: Iterable.md
 | 
			
		||||
[List]: List.md
 | 
			
		||||
[Set]: Set.md
 | 
			
		||||
@ -1,13 +1,17 @@
 | 
			
		||||
# Iterable interface
 | 
			
		||||
 | 
			
		||||
The inteface which requires iterator to be implemented:
 | 
			
		||||
Iterable is a class that provides function that creates _the iterator_:
 | 
			
		||||
 | 
			
		||||
    fun iterator(): Iterator
 | 
			
		||||
    class Iterable {
 | 
			
		||||
        abstract fun iterator()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Note that each call of `iterator()` must provide an independent iterator.
 | 
			
		||||
 | 
			
		||||
Iterator itself is a simple interface that should provide only to method:
 | 
			
		||||
 | 
			
		||||
    interface Iterable {
 | 
			
		||||
        fun hasNext(): Bool
 | 
			
		||||
    class Iterator {
 | 
			
		||||
        abstract fun hasNext(): Bool
 | 
			
		||||
        fun next(): Obj
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -15,19 +19,26 @@ Just remember at this stage typed declarations are not yet supported.
 | 
			
		||||
 | 
			
		||||
Having `Iterable` in base classes allows to use it in for loop. Also, each `Iterable` has some utility functions available:
 | 
			
		||||
 | 
			
		||||
## Instance methods
 | 
			
		||||
 | 
			
		||||
    fun Iterable.toList(): List
 | 
			
		||||
    fun Iterable.toSet(): Set
 | 
			
		||||
    fun Iterable.indexOf(element): Int
 | 
			
		||||
    fun Iterable.contains(element): Bool
 | 
			
		||||
    fun Iterable.isEmpty(element): Bool
 | 
			
		||||
    fun Iterable.forEach(block: (Any?)->Void ): Void
 | 
			
		||||
    fun Iterable.map(block: (Any?)->Void ): List
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
## Abstract methods
 | 
			
		||||
 | 
			
		||||
    fun iterator(): Iterator
 | 
			
		||||
 | 
			
		||||
## Instance methods
 | 
			
		||||
 | 
			
		||||
### toList()
 | 
			
		||||
 | 
			
		||||
Creates a list by iterating to the end. So, the Iterator should be finite to be used with it.
 | 
			
		||||
 | 
			
		||||
## Included in interfaces:
 | 
			
		||||
 | 
			
		||||
- Collection, Array, [List]
 | 
			
		||||
- [Collection], Array, [List]
 | 
			
		||||
 | 
			
		||||
## Implemented in classes:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -116,6 +116,8 @@ Open end ranges remove head and tail elements:
 | 
			
		||||
: `+=` append either a single element, or all elements if the List or other Iterable
 | 
			
		||||
instance is appended. If you want to append an Iterable object itself, use `add` instead.
 | 
			
		||||
 | 
			
		||||
It inherits from [Iterable] too.
 | 
			
		||||
 | 
			
		||||
## Member inherited from Array
 | 
			
		||||
 | 
			
		||||
| name             | meaning                        | type  |
 | 
			
		||||
@ -130,8 +132,6 @@ instance is appended. If you want to append an Iterable object itself, use `add`
 | 
			
		||||
: end-inclisiveness allows to use negative indexes to, for exampe, remove several last elements, like
 | 
			
		||||
`list.removeRangeInclusive(-2, -1)` will remove two last elements.
 | 
			
		||||
 | 
			
		||||
# Notes
 | 
			
		||||
 | 
			
		||||
Could be rewritten using array as a class but List as the interface
 | 
			
		||||
 | 
			
		||||
[Range]: Range.md
 | 
			
		||||
[Range]: Range.md
 | 
			
		||||
[Iterable]: Iterable.md
 | 
			
		||||
							
								
								
									
										94
									
								
								docs/Set.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								docs/Set.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
			
		||||
# List built-in class
 | 
			
		||||
 | 
			
		||||
Mutable set of any objects: a group of different objects, no repetitions.
 | 
			
		||||
Sets are not ordered, order of appearance does not matter.
 | 
			
		||||
 | 
			
		||||
    val set = Set(1,2,3, "foo")
 | 
			
		||||
    assert( 1 in set )
 | 
			
		||||
    assert( "foo" in set)
 | 
			
		||||
    assert( "bar" !in set)
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Set is collection and therefore [Iterable]:
 | 
			
		||||
 | 
			
		||||
    assert( Set(1,2) is Set)
 | 
			
		||||
    assert( Set(1,2) is Iterable)
 | 
			
		||||
    assert( Set(1,2) is Collection)
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
So it supports all methods from [Iterable]; set is not, though, an [Array] and has
 | 
			
		||||
no indexing. Use [set.toList] as needed.
 | 
			
		||||
 | 
			
		||||
## Set operations
 | 
			
		||||
 | 
			
		||||
    // Union
 | 
			
		||||
    assertEquals( Set(1,2,3,4), Set(3, 1) + Set(2, 4))
 | 
			
		||||
 | 
			
		||||
    // intersection
 | 
			
		||||
    assertEquals( Set(1,4), Set(3, 1, 4).intersect(Set(2, 4, 1)) )
 | 
			
		||||
    // or simple
 | 
			
		||||
    assertEquals( Set(1,4), Set(3, 1, 4) * Set(2, 4, 1) )
 | 
			
		||||
 | 
			
		||||
    // To find collection elements not present in another collection, use the 
 | 
			
		||||
    // subtract() or `-`:
 | 
			
		||||
    assertEquals( Set( 1, 2), Set(1, 2, 4, 3) - Set(3, 4))
 | 
			
		||||
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Adding elements
 | 
			
		||||
 | 
			
		||||
    var s = Set()
 | 
			
		||||
    s += 1
 | 
			
		||||
    assertEquals( Set(1), s)
 | 
			
		||||
    
 | 
			
		||||
    s += [3, 3, 4]
 | 
			
		||||
    assertEquals( Set(3, 4, 1), s)
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Removing elements
 | 
			
		||||
 | 
			
		||||
List is mutable, so it is possible to remove its contents. To remove a single element
 | 
			
		||||
by index use:
 | 
			
		||||
 | 
			
		||||
    var s = Set(1,2,3)
 | 
			
		||||
    s.remove(2)
 | 
			
		||||
    assertEquals( s, Set(1,3) )
 | 
			
		||||
 | 
			
		||||
    s = Set(1,2,3)
 | 
			
		||||
    s.remove(2,1)
 | 
			
		||||
    assertEquals( s, Set(3) )
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
Note that `remove` returns true if at least one element was actually removed and false
 | 
			
		||||
if the set has not been changed.
 | 
			
		||||
 | 
			
		||||
## Comparisons and inclusion
 | 
			
		||||
 | 
			
		||||
Sets are only equal when contains exactly same elements, order, as was said, is not significant:
 | 
			
		||||
 | 
			
		||||
    assert( Set(1, 2) == Set(2, 1) )
 | 
			
		||||
    assert( Set(1, 2, 2) == Set(2, 1) )
 | 
			
		||||
    assert( Set(1, 3) != Set(2, 1) )
 | 
			
		||||
    assert( 1 in Set(5,1))
 | 
			
		||||
    assert( 10 !in Set(5,1))
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
## Members
 | 
			
		||||
 | 
			
		||||
| name                | meaning                              | type  |
 | 
			
		||||
|---------------------|--------------------------------------|-------|
 | 
			
		||||
| `size`              | current size                         | Int   |
 | 
			
		||||
| `+=`                | add one or more elements             | Any   |
 | 
			
		||||
| `+`, `union`         | union sets                           | Any   |
 | 
			
		||||
| `-`, `subtract`     | subtract sets                        | Any   |
 | 
			
		||||
| `*`, `intersect`    | subtract sets                        | Any   |
 | 
			
		||||
| `remove(items...)`  | remove one or more items             | Range |
 | 
			
		||||
| `contains(element)` | check the element is in the list (1) |       |
 | 
			
		||||
 | 
			
		||||
(1)
 | 
			
		||||
: optimized implementation that override `Iterable` one
 | 
			
		||||
 | 
			
		||||
Also, it inherits methods from [Iterable].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Range]: Range.md
 | 
			
		||||
@ -159,9 +159,8 @@ class Compiler(
 | 
			
		||||
                                    cc.next()
 | 
			
		||||
                                    isCall = true
 | 
			
		||||
                                    val lambda =
 | 
			
		||||
                                        parseExpression(cc) ?: throw ScriptError(t.pos, "expected valid lambda here")
 | 
			
		||||
                                        parseLambdaExpression(cc)
 | 
			
		||||
                                    println(cc.current())
 | 
			
		||||
                                    cc.skipTokenOfType(Token.Type.RBRACE)
 | 
			
		||||
                                    operand = Accessor { context ->
 | 
			
		||||
                                        context.pos = next.pos
 | 
			
		||||
                                        val v = left.getter(context).value
 | 
			
		||||
@ -172,7 +171,7 @@ class Compiler(
 | 
			
		||||
                                                v.invokeInstanceMethod(
 | 
			
		||||
                                                    context,
 | 
			
		||||
                                                    next.value,
 | 
			
		||||
                                                    Arguments(listOf(lambda), true)
 | 
			
		||||
                                                    Arguments(listOf(lambda.getter(context).value), true)
 | 
			
		||||
                                                ), isMutable = false
 | 
			
		||||
                                            )
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
@ -265,6 +265,7 @@ open class Obj {
 | 
			
		||||
                is Boolean -> ObjBool(obj)
 | 
			
		||||
                Unit -> ObjVoid
 | 
			
		||||
                null -> ObjNull
 | 
			
		||||
                is Iterator<*> -> ObjKotlinIterator(obj)
 | 
			
		||||
                else -> throw IllegalArgumentException("cannot convert to Obj: $obj")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArray.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjArray.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
val ObjArray by lazy {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Array abstract class is a [ObjCollection] with `getAt` method.
 | 
			
		||||
     */
 | 
			
		||||
    ObjClass("Array", ObjCollection).apply {
 | 
			
		||||
        // we can create iterators using size/getat:
 | 
			
		||||
 | 
			
		||||
        addFn("iterator") {
 | 
			
		||||
            ObjArrayIterator(thisObj).also { it.init(this) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("contains", isOpen = true) {
 | 
			
		||||
            val obj = args.firstAndOnly()
 | 
			
		||||
            for (i in 0..<thisObj.invokeInstanceMethod(this, "size").toInt()) {
 | 
			
		||||
                if (thisObj.getAt(this, ObjInt(i.toLong())).compareTo(this, obj) == 0) return@addFn ObjTrue
 | 
			
		||||
            }
 | 
			
		||||
            ObjFalse
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("last") {
 | 
			
		||||
            thisObj.invokeInstanceMethod(
 | 
			
		||||
                this,
 | 
			
		||||
                "getAt",
 | 
			
		||||
                (thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj()
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("lastIndex") { (thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj() }
 | 
			
		||||
 | 
			
		||||
        addFn("indices") {
 | 
			
		||||
            ObjRange(0.toObj(), thisObj.invokeInstanceMethod(this, "size"), false)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
class ObjArrayIterator(val array: Obj) : Obj() {
 | 
			
		||||
 | 
			
		||||
    override val objClass: ObjClass by lazy { type }
 | 
			
		||||
 | 
			
		||||
    private var nextIndex = 0
 | 
			
		||||
    private var lastIndex = 0
 | 
			
		||||
 | 
			
		||||
    suspend fun init(context: Context) {
 | 
			
		||||
        nextIndex = 0
 | 
			
		||||
        lastIndex = array.invokeInstanceMethod(context, "size").toInt()
 | 
			
		||||
        ObjVoid
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val type by lazy {
 | 
			
		||||
            ObjClass("ArrayIterator", ObjIterator).apply {
 | 
			
		||||
                addFn("next") {
 | 
			
		||||
                    val self = thisAs<ObjArrayIterator>()
 | 
			
		||||
                    if (self.nextIndex < self.lastIndex) {
 | 
			
		||||
                        self.array.invokeInstanceMethod(this, "getAt", (self.nextIndex++).toObj())
 | 
			
		||||
                    } else raiseError(ObjIterationFinishedException(this))
 | 
			
		||||
                }
 | 
			
		||||
                addFn("hasNext") {
 | 
			
		||||
                    val self = thisAs<ObjArrayIterator>()
 | 
			
		||||
                    if (self.nextIndex < self.lastIndex) ObjTrue else ObjFalse
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -69,118 +69,4 @@ open class ObjClass(
 | 
			
		||||
            ?: throw ScriptError(atPos, "symbol doesn't exist: $name")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract class that must provide `iterator` method that returns [ObjIterator] instance.
 | 
			
		||||
 */
 | 
			
		||||
val ObjIterable by lazy {
 | 
			
		||||
    ObjClass("Iterable").apply {
 | 
			
		||||
 | 
			
		||||
        addFn("toList") {
 | 
			
		||||
            val result = mutableListOf<Obj>()
 | 
			
		||||
            val iterator = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
 | 
			
		||||
            while (iterator.invokeInstanceMethod(this, "hasNext").toBool())
 | 
			
		||||
                result += iterator.invokeInstanceMethod(this, "next")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//        val next = iterator.getMemberOrNull("next")!!
 | 
			
		||||
//        val hasNext = iterator.getMemberOrNull("hasNext")!!
 | 
			
		||||
//        while( hasNext.invoke(this, iterator).toBool() )
 | 
			
		||||
//            result += next.invoke(this, iterator)
 | 
			
		||||
            ObjList(result)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Collection is an iterator with `size`]
 | 
			
		||||
 */
 | 
			
		||||
val ObjCollection by lazy {
 | 
			
		||||
    val i: ObjClass = ObjIterable
 | 
			
		||||
    ObjClass("Collection", i).apply {
 | 
			
		||||
        // it is not effective, but it is open:
 | 
			
		||||
        addFn("contains", isOpen = true) {
 | 
			
		||||
            val obj = args.firstAndOnly()
 | 
			
		||||
            val it = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
            while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
 | 
			
		||||
                if( obj.compareTo(this, it.invokeInstanceMethod(this, "next")) == 0 )
 | 
			
		||||
                    return@addFn ObjTrue
 | 
			
		||||
            }
 | 
			
		||||
            ObjFalse
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val ObjIterator by lazy { ObjClass("Iterator") }
 | 
			
		||||
 | 
			
		||||
class ObjArrayIterator(val array: Obj) : Obj() {
 | 
			
		||||
 | 
			
		||||
    override val objClass: ObjClass by lazy { type }
 | 
			
		||||
 | 
			
		||||
    private var nextIndex = 0
 | 
			
		||||
    private var lastIndex = 0
 | 
			
		||||
 | 
			
		||||
    suspend fun init(context: Context) {
 | 
			
		||||
        nextIndex = 0
 | 
			
		||||
        lastIndex = array.invokeInstanceMethod(context, "size").toInt()
 | 
			
		||||
        ObjVoid
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val type by lazy {
 | 
			
		||||
            ObjClass("ArrayIterator", ObjIterator).apply {
 | 
			
		||||
                addFn("next") {
 | 
			
		||||
                    val self = thisAs<ObjArrayIterator>()
 | 
			
		||||
                    if (self.nextIndex < self.lastIndex) {
 | 
			
		||||
                        self.array.invokeInstanceMethod(this, "getAt", (self.nextIndex++).toObj())
 | 
			
		||||
                    } else raiseError(ObjIterationFinishedException(this))
 | 
			
		||||
                }
 | 
			
		||||
                addFn("hasNext") {
 | 
			
		||||
                    val self = thisAs<ObjArrayIterator>()
 | 
			
		||||
                    if (self.nextIndex < self.lastIndex) ObjTrue else ObjFalse
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
val ObjArray by lazy {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Array abstract class is a [ObjCollection] with `getAt` method.
 | 
			
		||||
     */
 | 
			
		||||
    ObjClass("Array", ObjCollection).apply {
 | 
			
		||||
        // we can create iterators using size/getat:
 | 
			
		||||
 | 
			
		||||
        addFn("iterator") {
 | 
			
		||||
            ObjArrayIterator(thisObj).also { it.init(this) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("contains", isOpen = true) {
 | 
			
		||||
            val obj = args.firstAndOnly()
 | 
			
		||||
            for (i in 0..<thisObj.invokeInstanceMethod(this, "size").toInt()) {
 | 
			
		||||
                if (thisObj.getAt(this, ObjInt(i.toLong())).compareTo(this, obj) == 0) return@addFn ObjTrue
 | 
			
		||||
            }
 | 
			
		||||
            ObjFalse
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("last") {
 | 
			
		||||
            thisObj.invokeInstanceMethod(
 | 
			
		||||
                this,
 | 
			
		||||
                "getAt",
 | 
			
		||||
                (thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj()
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("lastIndex") { (thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj() }
 | 
			
		||||
 | 
			
		||||
        addFn("indices") {
 | 
			
		||||
            ObjRange(0.toObj(), thisObj.invokeInstanceMethod(this, "size"), false)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Collection is an iterator with `size`]
 | 
			
		||||
 */
 | 
			
		||||
val ObjCollection = ObjClass("Collection", ObjIterable).apply {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
@ -0,0 +1,80 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Abstract class that must provide `iterator` method that returns [ObjIterator] instance.
 | 
			
		||||
 */
 | 
			
		||||
val ObjIterable by lazy {
 | 
			
		||||
    ObjClass("Iterable").apply {
 | 
			
		||||
 | 
			
		||||
        addFn("toList") {
 | 
			
		||||
            val result = mutableListOf<Obj>()
 | 
			
		||||
            val iterator = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
 | 
			
		||||
            while (iterator.invokeInstanceMethod(this, "hasNext").toBool())
 | 
			
		||||
                result += iterator.invokeInstanceMethod(this, "next")
 | 
			
		||||
            ObjList(result)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // it is not effective, but it is open:
 | 
			
		||||
        addFn("contains", isOpen = true) {
 | 
			
		||||
            val obj = args.firstAndOnly()
 | 
			
		||||
            val it = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
            while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
 | 
			
		||||
                if (obj.compareTo(this, it.invokeInstanceMethod(this, "next")) == 0)
 | 
			
		||||
                    return@addFn ObjTrue
 | 
			
		||||
            }
 | 
			
		||||
            ObjFalse
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("indexOf", isOpen = true) {
 | 
			
		||||
            val obj = args.firstAndOnly()
 | 
			
		||||
            var index = 0
 | 
			
		||||
            val it = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
            while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
 | 
			
		||||
                if (obj.compareTo(this, it.invokeInstanceMethod(this, "next")) == 0)
 | 
			
		||||
                    return@addFn ObjInt(index.toLong())
 | 
			
		||||
                index++
 | 
			
		||||
            }
 | 
			
		||||
            ObjInt(-1L)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("toSet") {
 | 
			
		||||
            val result = mutableSetOf<Obj>()
 | 
			
		||||
            val it = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
            while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
 | 
			
		||||
                result += it.invokeInstanceMethod(this, "next")
 | 
			
		||||
            }
 | 
			
		||||
            ObjSet(result)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("forEach", isOpen = true) {
 | 
			
		||||
            val it = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
            val fn = requiredArg<Statement>(0)
 | 
			
		||||
            while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
 | 
			
		||||
                val x = it.invokeInstanceMethod(this, "next")
 | 
			
		||||
                fn.execute(this.copy(Arguments(listOf(x))))
 | 
			
		||||
            }
 | 
			
		||||
            ObjVoid
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("map", isOpen = true) {
 | 
			
		||||
            val it = thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
            val fn = requiredArg<Statement>(0)
 | 
			
		||||
            val result = mutableListOf<Obj>()
 | 
			
		||||
            while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
 | 
			
		||||
                val x = it.invokeInstanceMethod(this, "next")
 | 
			
		||||
                result += fn.execute(this.copy(Arguments(listOf(x))))
 | 
			
		||||
            }
 | 
			
		||||
            ObjList(result)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        addFn("isEmpty") {
 | 
			
		||||
            ObjBool(
 | 
			
		||||
                thisObj.invokeInstanceMethod(this, "iterator")
 | 
			
		||||
                    .invokeInstanceMethod(this, "hasNext").toBool()
 | 
			
		||||
                    .not()
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,3 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
val ObjIterator by lazy { ObjClass("Iterator") }
 | 
			
		||||
@ -0,0 +1,14 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
class ObjKotlinIterator(val iterator: Iterator<Any?>): Obj() {
 | 
			
		||||
 | 
			
		||||
    override val objClass = type
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val type = ObjClass("KotlinIterator", ObjIterator).apply {
 | 
			
		||||
            addFn("next") { thisAs<ObjKotlinIterator>().iterator.next().toObj() }
 | 
			
		||||
            addFn("hasNext") { thisAs<ObjKotlinIterator>().iterator.hasNext().toObj() }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -211,4 +211,6 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										97
									
								
								lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjSet.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								lynglib/src/commonMain/kotlin/net/sergeych/lyng/ObjSet.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
package net.sergeych.lyng
 | 
			
		||||
 | 
			
		||||
class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
 | 
			
		||||
 | 
			
		||||
    override val objClass = type
 | 
			
		||||
 | 
			
		||||
    override suspend fun contains(context: Context, other: Obj): Boolean {
 | 
			
		||||
        return set.contains(other)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun plus(context: Context, other: Obj): Obj {
 | 
			
		||||
        return ObjSet(
 | 
			
		||||
            if (other is ObjSet)
 | 
			
		||||
                (set + other.set).toMutableSet()
 | 
			
		||||
            else
 | 
			
		||||
                (set + other).toMutableSet()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun plusAssign(context: Context, other: Obj): Obj {
 | 
			
		||||
        when (other) {
 | 
			
		||||
            is ObjSet -> {
 | 
			
		||||
                set += other.set
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            is ObjList -> {
 | 
			
		||||
                set += other.list
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else -> {
 | 
			
		||||
                if (other.isInstanceOf(ObjIterable)) {
 | 
			
		||||
                    val i = other.invokeInstanceMethod(context, "iterable")
 | 
			
		||||
                    while (i.invokeInstanceMethod(context, "hasNext").toBool()) {
 | 
			
		||||
                        set += i.invokeInstanceMethod(context, "next")
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                set += other
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun mul(context: Context, other: Obj): Obj {
 | 
			
		||||
        return if (other is ObjSet) {
 | 
			
		||||
            ObjSet(set.intersect(other.set).toMutableSet())
 | 
			
		||||
        } else
 | 
			
		||||
            context.raiseArgumentError("set operator * requires another set")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun minus(context: Context, other: Obj): Obj {
 | 
			
		||||
        if (other !is ObjSet)
 | 
			
		||||
            context.raiseArgumentError("set operator - requires another set")
 | 
			
		||||
        return ObjSet(set.minus(other.set).toMutableSet())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun toString(): String {
 | 
			
		||||
        return "Set(${set.joinToString(", ")})"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun compareTo(context: Context, other: Obj): Int {
 | 
			
		||||
        return if (other !is ObjSet) -1
 | 
			
		||||
        else {
 | 
			
		||||
            if (set == other.set) 0
 | 
			
		||||
            else -1
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val type = object : ObjClass("Set", ObjCollection) {
 | 
			
		||||
            override suspend fun callOn(context: Context): Obj {
 | 
			
		||||
                return ObjSet(context.args.list.toMutableSet())
 | 
			
		||||
            }
 | 
			
		||||
        }.apply {
 | 
			
		||||
            addFn("size") {
 | 
			
		||||
                thisAs<ObjSet>().set.size.toObj()
 | 
			
		||||
            }
 | 
			
		||||
            addFn("intersect") {
 | 
			
		||||
                thisAs<ObjSet>().mul(this, args.firstAndOnly())
 | 
			
		||||
            }
 | 
			
		||||
            addFn("iterator") {
 | 
			
		||||
                thisAs<ObjSet>().set.iterator().toObj()
 | 
			
		||||
            }
 | 
			
		||||
            addFn("union") {
 | 
			
		||||
                thisAs<ObjSet>().plus(this, args.firstAndOnly())
 | 
			
		||||
            }
 | 
			
		||||
            addFn("subtract") {
 | 
			
		||||
                thisAs<ObjSet>().minus(this, args.firstAndOnly())
 | 
			
		||||
            }
 | 
			
		||||
            addFn("remove") {
 | 
			
		||||
                val set = thisAs<ObjSet>().set
 | 
			
		||||
                val n = set.size
 | 
			
		||||
                for( x in args.list ) set -= x
 | 
			
		||||
                if( n == set.size ) ObjFalse else ObjTrue
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -152,11 +152,13 @@ class Script(
 | 
			
		||||
            addConst("Bool", ObjBool.type)
 | 
			
		||||
            addConst("Char", ObjChar.type)
 | 
			
		||||
            addConst("List", ObjList.type)
 | 
			
		||||
            addConst("Set", ObjSet.type)
 | 
			
		||||
            addConst("Range", ObjRange.type)
 | 
			
		||||
            @Suppress("RemoveRedundantQualifierName")
 | 
			
		||||
            addConst("Callable", Statement.type)
 | 
			
		||||
            // interfaces
 | 
			
		||||
            addConst("Iterable", ObjIterable)
 | 
			
		||||
            addConst("Collection", ObjCollection)
 | 
			
		||||
            addConst("Array", ObjArray)
 | 
			
		||||
            addConst("Class", ObjClassType)
 | 
			
		||||
            addConst("Object", Obj().objClass)
 | 
			
		||||
 | 
			
		||||
@ -1221,21 +1221,6 @@ class ScriptTest {
 | 
			
		||||
        println(a)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun iterableList() = runTest {
 | 
			
		||||
        // 473
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            for( i in 0..<1024 ) {    
 | 
			
		||||
            val list = (1..1024).toList()
 | 
			
		||||
            assert(list.size == 1024)
 | 
			
		||||
            assert(list[0] == 1)
 | 
			
		||||
            assert(list.last == 1024)
 | 
			
		||||
            }
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testLambdaWithIt1() = runTest {
 | 
			
		||||
        eval(
 | 
			
		||||
@ -2206,4 +2191,55 @@ class ScriptTest {
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testCollectionStructure() = runTest {
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
                val list = [1,2,3]
 | 
			
		||||
                assert( 1 in list )
 | 
			
		||||
                assert( list.indexOf(3) == 2 )
 | 
			
		||||
                assert( list.indexOf(5) == -1 )
 | 
			
		||||
                assert( list is List )
 | 
			
		||||
                assert( list is Array )
 | 
			
		||||
                assert( list is Iterable )
 | 
			
		||||
                assert( list is Collection )
 | 
			
		||||
                
 | 
			
		||||
                val other = []
 | 
			
		||||
                list.forEach { other += it }
 | 
			
		||||
                assertEquals( list, other )
 | 
			
		||||
                
 | 
			
		||||
                assert( list.isEmpty() == false )
 | 
			
		||||
                
 | 
			
		||||
                assertEquals( [10, 20, 30], list.map { it * 10 } )
 | 
			
		||||
                assertEquals( [10, 20, 30], (1..3).map { it * 10 } )
 | 
			
		||||
                
 | 
			
		||||
            """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testSet() = runTest {
 | 
			
		||||
        eval(
 | 
			
		||||
            """
 | 
			
		||||
            val set = Set(1,2,3)
 | 
			
		||||
            
 | 
			
		||||
            assert( set.contains(1) )
 | 
			
		||||
            assert( 1 in set )
 | 
			
		||||
            
 | 
			
		||||
            assert(set is Set)
 | 
			
		||||
            assert(set is Iterable)
 | 
			
		||||
            assert(set is Collection)
 | 
			
		||||
            println(set)
 | 
			
		||||
            for( x in set ) println(x)
 | 
			
		||||
            assert([1,2,3] == set.toList())
 | 
			
		||||
            set += 4
 | 
			
		||||
            assert(set.toList() == [1,2,3,4])
 | 
			
		||||
            assert(set == Set(1,2,3,4))
 | 
			
		||||
            
 | 
			
		||||
            val s1 = [1, 2].toSet()
 | 
			
		||||
            assertEquals( Set(1,2), s1 * set) 
 | 
			
		||||
            
 | 
			
		||||
        """.trimIndent()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -255,6 +255,11 @@ class BookTest {
 | 
			
		||||
        runDocTests("../docs/Range.md")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testSet() = runTest {
 | 
			
		||||
        runDocTests("../docs/Set.md")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testSampleBooks() = runTest {
 | 
			
		||||
        for (bt in Files.list(Paths.get("../docs/samples")).toList()) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user