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
|
# 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:
|
Iterator itself is a simple interface that should provide only to method:
|
||||||
|
|
||||||
interface Iterable {
|
class Iterator {
|
||||||
fun hasNext(): Bool
|
abstract fun hasNext(): Bool
|
||||||
fun next(): Obj
|
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:
|
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
|
## Abstract methods
|
||||||
|
|
||||||
fun iterator(): Iterator
|
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.
|
Creates a list by iterating to the end. So, the Iterator should be finite to be used with it.
|
||||||
|
|
||||||
## Included in interfaces:
|
## Included in interfaces:
|
||||||
|
|
||||||
- Collection, Array, [List]
|
- [Collection], Array, [List]
|
||||||
|
|
||||||
## Implemented in classes:
|
## 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
|
: `+=` 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.
|
instance is appended. If you want to append an Iterable object itself, use `add` instead.
|
||||||
|
|
||||||
|
It inherits from [Iterable] too.
|
||||||
|
|
||||||
## Member inherited from Array
|
## Member inherited from Array
|
||||||
|
|
||||||
| name | meaning | type |
|
| 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
|
: end-inclisiveness allows to use negative indexes to, for exampe, remove several last elements, like
|
||||||
`list.removeRangeInclusive(-2, -1)` will remove two last elements.
|
`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()
|
cc.next()
|
||||||
isCall = true
|
isCall = true
|
||||||
val lambda =
|
val lambda =
|
||||||
parseExpression(cc) ?: throw ScriptError(t.pos, "expected valid lambda here")
|
parseLambdaExpression(cc)
|
||||||
println(cc.current())
|
println(cc.current())
|
||||||
cc.skipTokenOfType(Token.Type.RBRACE)
|
|
||||||
operand = Accessor { context ->
|
operand = Accessor { context ->
|
||||||
context.pos = next.pos
|
context.pos = next.pos
|
||||||
val v = left.getter(context).value
|
val v = left.getter(context).value
|
||||||
@ -172,7 +171,7 @@ class Compiler(
|
|||||||
v.invokeInstanceMethod(
|
v.invokeInstanceMethod(
|
||||||
context,
|
context,
|
||||||
next.value,
|
next.value,
|
||||||
Arguments(listOf(lambda), true)
|
Arguments(listOf(lambda.getter(context).value), true)
|
||||||
), isMutable = false
|
), isMutable = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,7 @@ open class Obj {
|
|||||||
is Boolean -> ObjBool(obj)
|
is Boolean -> ObjBool(obj)
|
||||||
Unit -> ObjVoid
|
Unit -> ObjVoid
|
||||||
null -> ObjNull
|
null -> ObjNull
|
||||||
|
is Iterator<*> -> ObjKotlinIterator(obj)
|
||||||
else -> throw IllegalArgumentException("cannot convert to Obj: $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")
|
?: 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() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -212,3 +212,5 @@ 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("Bool", ObjBool.type)
|
||||||
addConst("Char", ObjChar.type)
|
addConst("Char", ObjChar.type)
|
||||||
addConst("List", ObjList.type)
|
addConst("List", ObjList.type)
|
||||||
|
addConst("Set", ObjSet.type)
|
||||||
addConst("Range", ObjRange.type)
|
addConst("Range", ObjRange.type)
|
||||||
@Suppress("RemoveRedundantQualifierName")
|
@Suppress("RemoveRedundantQualifierName")
|
||||||
addConst("Callable", Statement.type)
|
addConst("Callable", Statement.type)
|
||||||
// interfaces
|
// interfaces
|
||||||
addConst("Iterable", ObjIterable)
|
addConst("Iterable", ObjIterable)
|
||||||
|
addConst("Collection", ObjCollection)
|
||||||
addConst("Array", ObjArray)
|
addConst("Array", ObjArray)
|
||||||
addConst("Class", ObjClassType)
|
addConst("Class", ObjClassType)
|
||||||
addConst("Object", Obj().objClass)
|
addConst("Object", Obj().objClass)
|
||||||
|
@ -1221,21 +1221,6 @@ class ScriptTest {
|
|||||||
println(a)
|
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
|
@Test
|
||||||
fun testLambdaWithIt1() = runTest {
|
fun testLambdaWithIt1() = runTest {
|
||||||
eval(
|
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")
|
runDocTests("../docs/Range.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSet() = runTest {
|
||||||
|
runDocTests("../docs/Set.md")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSampleBooks() = runTest {
|
fun testSampleBooks() = runTest {
|
||||||
for (bt in Files.list(Paths.get("../docs/samples")).toList()) {
|
for (bt in Files.list(Paths.get("../docs/samples")).toList()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user