lists modification: insert, remove, offset-end indexing, comparison.
This commit is contained in:
parent
c18345823b
commit
b56b5c521d
47
docs/List.md
47
docs/List.md
@ -12,13 +12,44 @@ you can use it's class to ensure type:
|
|||||||
[]::class == List
|
[]::class == List
|
||||||
>>> true
|
>>> true
|
||||||
|
|
||||||
|
## Indexing
|
||||||
|
|
||||||
|
indexing is zero-based, as in C/C++/Java/Kotlin, etc.
|
||||||
|
|
||||||
|
val list = [10, 20, 30]
|
||||||
|
list[1]
|
||||||
|
>>> 20
|
||||||
|
|
||||||
|
Using negative indexes has a special meaning: _offset from the end of the list_:
|
||||||
|
|
||||||
|
val list = [10, 20, 30]
|
||||||
|
list[-1]
|
||||||
|
>>> 30
|
||||||
|
|
||||||
|
__Important__ negative indexes works wherever indexes are used, e.g. in insertion and removal methods too.
|
||||||
|
|
||||||
|
## Concatenation
|
||||||
|
|
||||||
|
assert( [4,5] + [1,2] == [4,5,1,2])
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
## Comparisons
|
||||||
|
|
||||||
|
assert( [1, 2] != [1, 3])
|
||||||
|
assert( [1, 2, 3] > [1, 2])
|
||||||
|
assert( [1, 3] > [1, 2, 3])
|
||||||
|
assert( [1, 2, 3] == [1, 2, 3])
|
||||||
|
// note that in the case above objects are referentially different:
|
||||||
|
assert( [1, 2, 3] !== [1, 2, 3])
|
||||||
|
>>> void
|
||||||
|
|
||||||
## Members
|
## Members
|
||||||
|
|
||||||
| name | meaning | type |
|
| name | meaning | type |
|
||||||
|---------|-------------------------------|------|
|
|----------------------------|----------------------------------------------|----------|
|
||||||
| `.size` | property returns current size | Int |
|
| `size` | current size | Int |
|
||||||
| | | |
|
| `add(elements...)` | add one or more elements to the end | Any |
|
||||||
| | | |
|
| `addAt(index,elements...)` | insert elements at position | Int, Any |
|
||||||
| | | |
|
| `removeAt(index)` | remove element at position | Int |
|
||||||
| | | |
|
| `removeAt(start,end)` | remove range, start inclusive, end exclusive | Int, Int |
|
||||||
| | | |
|
| | | |
|
||||||
|
113
docs/tutorial.md
113
docs/tutorial.md
@ -123,24 +123,42 @@ Logical operation could be used the same
|
|||||||
|
|
||||||
## Supported operators
|
## Supported operators
|
||||||
|
|
||||||
| op | ass | args |
|
| op | ass | args | comments |
|
||||||
|:--------:|-----|-------------------|
|
|:--------:|-----|-------------------|----------|
|
||||||
| + | += | Int or Real |
|
| + | += | Int or Real | |
|
||||||
| - | -= | Int or Real |
|
| - | -= | Int or Real | infix |
|
||||||
| * | *= | Int or Real |
|
| * | *= | Int or Real | |
|
||||||
| / | /= | Int or Real |
|
| / | /= | Int or Real | |
|
||||||
| % | %= | Int or Real |
|
| % | %= | Int or Real | |
|
||||||
| && | | Bool |
|
| && | | Bool | |
|
||||||
| \|\| | | Bool |
|
| \|\| | | Bool | |
|
||||||
| !x | | Bool |
|
| !x | | Bool | |
|
||||||
| < | | String, Int, Real |
|
| < | | String, Int, Real | (1) |
|
||||||
| <= | | String, Int, Real |
|
| <= | | String, Int, Real | (1) |
|
||||||
| >= | | String, Int, Real |
|
| >= | | String, Int, Real | (1) |
|
||||||
| > | | String, Int, Real |
|
| > | | String, Int, Real | (1) |
|
||||||
| == | | Any |
|
| == | | Any | (1) |
|
||||||
| != | | Any |
|
| === | | Any | (2) |
|
||||||
| ++a, a++ | | Int |
|
| !== | | Any | (2) |
|
||||||
| --a, a-- | | Int |
|
| != | | Any | (1) |
|
||||||
|
| ++a, a++ | | Int | |
|
||||||
|
| --a, a-- | | Int | |
|
||||||
|
|
||||||
|
(1)
|
||||||
|
: comparison are based on comparison operator which can be overloaded
|
||||||
|
|
||||||
|
(2)
|
||||||
|
: referential equality means left and right operands references exactly same instance of some object. Nothe that all
|
||||||
|
singleton object, like `null`, are referentially equal too, while string different literals even being equal are most
|
||||||
|
likely referentially not equal:
|
||||||
|
|
||||||
|
assert( null == null) // singletons
|
||||||
|
assert( null === null)
|
||||||
|
// but, for non-singletons:
|
||||||
|
assert( 5 == 5)
|
||||||
|
assert( 5 !== 5)
|
||||||
|
assert( "foo" !== "foo" )
|
||||||
|
>>> void
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
|
|
||||||
@ -244,7 +262,7 @@ to call it:
|
|||||||
|
|
||||||
If you need to create _unnamed_ function, use alternative syntax (TBD, like { -> } ?)
|
If you need to create _unnamed_ function, use alternative syntax (TBD, like { -> } ?)
|
||||||
|
|
||||||
# Lists (arrays)
|
# Lists (aka arrays)
|
||||||
|
|
||||||
Ling has built-in mutable array class `List` with simple literals:
|
Ling has built-in mutable array class `List` with simple literals:
|
||||||
|
|
||||||
@ -259,7 +277,7 @@ Lists can contain any type of objects, lists too:
|
|||||||
assert(list[1].size == 2)
|
assert(list[1].size == 2)
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
Notice usage of indexing.
|
Notice usage of indexing. You can use negative indexes to offset from the end of the list; see more in [Lists](List.md).
|
||||||
|
|
||||||
When you want to "flatten" it to single array, you can use splat syntax:
|
When you want to "flatten" it to single array, you can use splat syntax:
|
||||||
|
|
||||||
@ -273,13 +291,66 @@ Of course, you can splat from anything that is List (or list-like, but it will b
|
|||||||
["start", ...b, ...a, "end"]
|
["start", ...b, ...a, "end"]
|
||||||
>>> ["start", 10.1, 20.2, "one", "two", "end"]
|
>>> ["start", 10.1, 20.2, "one", "two", "end"]
|
||||||
|
|
||||||
Of course, you can set any array element:
|
Of course, you can set any list element:
|
||||||
|
|
||||||
val a = [1, 2, 3]
|
val a = [1, 2, 3]
|
||||||
a[1] = 200
|
a[1] = 200
|
||||||
a
|
a
|
||||||
>>> [1, 200, 3]
|
>>> [1, 200, 3]
|
||||||
|
|
||||||
|
Lists are comparable, as long as their respective elements are:
|
||||||
|
|
||||||
|
assert( [1,2,3] == [1,2,3])
|
||||||
|
|
||||||
|
// but they are _different_ objects:
|
||||||
|
assert( [1,2,3] !== [1,2,3])
|
||||||
|
|
||||||
|
// when sizes are different, but common part is equal,
|
||||||
|
// longer is greater
|
||||||
|
assert( [1,2,3] > [1,2] )
|
||||||
|
|
||||||
|
// otherwise, where the common part is greater, the list is greater:
|
||||||
|
assert( [1,2,3] < [1,3] )
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
All comparison operators with list are working ok. Also, you can concatenate lists:
|
||||||
|
|
||||||
|
assert( [5, 4] + ["foo", 2] == [5, 4, "foo", 2])
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
To add elements to the list:
|
||||||
|
|
||||||
|
val x = [1,2]
|
||||||
|
x.add(3)
|
||||||
|
assert( x == [1,2,3])
|
||||||
|
// same as x += ["the", "end"] but faster:
|
||||||
|
x.add("the", "end")
|
||||||
|
assert( x == [1, 2, 3, "the", "end"])
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
Self-modifying concatenation by `+=` also works:
|
||||||
|
|
||||||
|
val x = [1, 2]
|
||||||
|
x += [3, 4]
|
||||||
|
assert( x == [1, 2, 3, 4])
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
You can insert elements at any position using `addAt`:
|
||||||
|
|
||||||
|
val x = [1,2,3]
|
||||||
|
x.addAt(1, "foo", "bar")
|
||||||
|
assert( x == [1, "foo", "bar", 2, 3])
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
## Removing list items
|
||||||
|
|
||||||
|
val x = [1, 2, 3, 4, 5]
|
||||||
|
x.removeAt(2)
|
||||||
|
assert( x == [1, 2, 4, 5])
|
||||||
|
// or remove range (start inclusive, end exclusive):
|
||||||
|
x.removeAt(1,3)
|
||||||
|
assert( x == [1, 5])
|
||||||
|
>>> void
|
||||||
|
|
||||||
# Flow control operators
|
# Flow control operators
|
||||||
|
|
||||||
|
@ -13,12 +13,6 @@ data class Arguments(val list: List<Info>): Iterable<Obj> {
|
|||||||
return list.first().value
|
return list.first().value
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T: Obj>required(index: Int, context: Context): T {
|
|
||||||
if( list.size <= index ) context.raiseError("Expected at least ${index+1} argument, got ${list.size}")
|
|
||||||
return (list[index].value as? T)
|
|
||||||
?: context.raiseError("Expected type ${T::class.simpleName}, got ${list[index].value::class.simpleName}")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = Arguments(emptyList())
|
val EMPTY = Arguments(emptyList())
|
||||||
}
|
}
|
||||||
@ -27,5 +21,3 @@ data class Arguments(val list: List<Info>): Iterable<Obj> {
|
|||||||
return list.map { it.value }.iterator()
|
return list.map { it.value }.iterator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<Arguments.Info>.toArguments() = Arguments(this )
|
|
@ -148,7 +148,10 @@ class Compiler(
|
|||||||
v.callInstanceMethod(
|
v.callInstanceMethod(
|
||||||
context,
|
context,
|
||||||
next.value,
|
next.value,
|
||||||
args.toArguments()
|
Arguments(args.map {
|
||||||
|
val st = it.value as Statement
|
||||||
|
Arguments.Info(st.execute(context),it.pos) }
|
||||||
|
)
|
||||||
), isMutable = false
|
), isMutable = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -838,6 +841,8 @@ class Compiler(
|
|||||||
// equality/ne 4
|
// equality/ne 4
|
||||||
Operator.simple(Token.Type.EQ, ++lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) == 0) },
|
Operator.simple(Token.Type.EQ, ++lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) == 0) },
|
||||||
Operator.simple(Token.Type.NEQ, lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) != 0) },
|
Operator.simple(Token.Type.NEQ, lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) != 0) },
|
||||||
|
Operator.simple(Token.Type.REF_EQ, lastPrty) { _, a, b -> ObjBool(a === b) },
|
||||||
|
Operator.simple(Token.Type.REF_NEQ, lastPrty) { _, a, b -> ObjBool(a !== b) },
|
||||||
// relational <=,... 5
|
// relational <=,... 5
|
||||||
Operator.simple(Token.Type.LTE, ++lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) <= 0) },
|
Operator.simple(Token.Type.LTE, ++lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) <= 0) },
|
||||||
Operator.simple(Token.Type.LT, lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) < 0) },
|
Operator.simple(Token.Type.LT, lastPrty) { c, a, b -> ObjBool(a.compareTo(c, b) < 0) },
|
||||||
|
@ -17,6 +17,8 @@ class Context(
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun raiseNPE(): Nothing = raiseError(ObjNullPointerError(this))
|
fun raiseNPE(): Nothing = raiseError(ObjNullPointerError(this))
|
||||||
|
|
||||||
|
fun raiseClassCastError(msg: String): Nothing = raiseError(ObjClassCastError(this, msg))
|
||||||
|
|
||||||
fun raiseError(message: String): Nothing {
|
fun raiseError(message: String): Nothing {
|
||||||
throw ExecutionError(ObjError(this, message))
|
throw ExecutionError(ObjError(this, message))
|
||||||
}
|
}
|
||||||
@ -25,6 +27,15 @@ class Context(
|
|||||||
throw ExecutionError(obj)
|
throw ExecutionError(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified T: Obj>requiredArg(index: Int): T {
|
||||||
|
if( args.list.size <= index ) raiseError("Expected at least ${index+1} argument, got ${args.list.size}")
|
||||||
|
return (args.list[index].value as? T)
|
||||||
|
?: raiseClassCastError("Expected type ${T::class.simpleName}, got ${args.list[index].value::class.simpleName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T: Obj>thisAs(): T = (thisObj as? T)
|
||||||
|
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
||||||
|
|
||||||
private val objects = mutableMapOf<String, StoredObj>()
|
private val objects = mutableMapOf<String, StoredObj>()
|
||||||
|
|
||||||
operator fun get(name: String): StoredObj? =
|
operator fun get(name: String): StoredObj? =
|
||||||
|
@ -31,6 +31,8 @@ sealed class Obj {
|
|||||||
// private val memberMutex = Mutex()
|
// private val memberMutex = Mutex()
|
||||||
private val parentInstances = listOf<Obj>()
|
private val parentInstances = listOf<Obj>()
|
||||||
|
|
||||||
|
open fun inspect(): String = toString()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some objects are by-value, historically [ObjInt] and [ObjReal] are usually treated as such.
|
* Some objects are by-value, historically [ObjInt] and [ObjReal] are usually treated as such.
|
||||||
* When initializing a var with it, by value objects must be copied. By-reference ones aren't.
|
* When initializing a var with it, by value objects must be copied. By-reference ones aren't.
|
||||||
@ -255,7 +257,13 @@ data class ObjString(val value: String) : Obj() {
|
|||||||
return this.value.compareTo(other.value)
|
return this.value.compareTo(other.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String = "\"$value\""
|
override fun toString(): String = value
|
||||||
|
|
||||||
|
override val asStr: ObjString by lazy { this }
|
||||||
|
|
||||||
|
override fun inspect(): String {
|
||||||
|
return "\"$value\""
|
||||||
|
}
|
||||||
|
|
||||||
override val objClass: ObjClass
|
override val objClass: ObjClass
|
||||||
get() = type
|
get() = type
|
||||||
@ -445,33 +453,6 @@ data class ObjBool(val value: Boolean) : Obj() {
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
class ObjList(val list: MutableList<Obj>) : Obj() {
|
|
||||||
|
|
||||||
override fun toString(): String = "[${list.joinToString(separator = ", ")}]"
|
|
||||||
|
|
||||||
override suspend fun getAt(context: Context, index: Int): Obj {
|
|
||||||
return list[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun putAt(context: Context, index: Int, newValue: Obj) {
|
|
||||||
list[index] = newValue
|
|
||||||
}
|
|
||||||
|
|
||||||
override val objClass: ObjClass
|
|
||||||
get() = type
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val type = ObjClass("List").apply {
|
|
||||||
createField("size",
|
|
||||||
statement(Pos.builtIn) {
|
|
||||||
(it.thisObj as ObjList).list.size.toObj()
|
|
||||||
},
|
|
||||||
false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ObjNamespace(val name: String) : Obj() {
|
data class ObjNamespace(val name: String) : Obj() {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "namespace ${name}"
|
return "namespace ${name}"
|
||||||
@ -485,3 +466,4 @@ open class ObjError(val context: Context, val message: String) : Obj() {
|
|||||||
class ObjNullPointerError(context: Context) : ObjError(context, "object is null")
|
class ObjNullPointerError(context: Context) : ObjError(context, "object is null")
|
||||||
|
|
||||||
class ObjAssertionError(context: Context, message: String) : ObjError(context, message)
|
class ObjAssertionError(context: Context, message: String) : ObjError(context, message)
|
||||||
|
class ObjClassCastError(context: Context, message: String) : ObjError(context, message)
|
||||||
|
93
library/src/commonMain/kotlin/net/sergeych/ling/ObjList.kt
Normal file
93
library/src/commonMain/kotlin/net/sergeych/ling/ObjList.kt
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package net.sergeych.ling
|
||||||
|
|
||||||
|
class ObjList(val list: MutableList<Obj>) : Obj() {
|
||||||
|
|
||||||
|
override fun toString(): String = "[${
|
||||||
|
list.joinToString(separator = ", ") { it.inspect() }
|
||||||
|
}]"
|
||||||
|
|
||||||
|
fun normalize(context: Context, index: Int): Int {
|
||||||
|
val i = if (index < 0) list.size + index else index
|
||||||
|
if (i !in list.indices) context.raiseError("index $index out of bounds for size ${list.size}")
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getAt(context: Context, index: Int): Obj {
|
||||||
|
val i = normalize(context, index)
|
||||||
|
return list[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun putAt(context: Context, index: Int, newValue: Obj) {
|
||||||
|
val i = normalize(context, index)
|
||||||
|
list[i] = newValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun compareTo(context: Context, other: Obj): Int {
|
||||||
|
if (other !is ObjList) context.raiseError("cannot compare $this with $other")
|
||||||
|
val mySize = list.size
|
||||||
|
val otherSize = other.list.size
|
||||||
|
val commonSize = minOf(mySize, otherSize)
|
||||||
|
for (i in 0..<commonSize) {
|
||||||
|
if (list[i].compareTo(context, other.list[i]) != 0) {
|
||||||
|
return list[i].compareTo(context, other.list[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// equal so far, longer is greater:
|
||||||
|
return when {
|
||||||
|
mySize < otherSize -> -1
|
||||||
|
mySize > otherSize -> 1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun plus(context: Context, other: Obj): Obj {
|
||||||
|
(other as? ObjList) ?: context.raiseError("cannot concatenate $this with $other")
|
||||||
|
return ObjList((list + other.list).toMutableList())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun plusAssign(context: Context, other: Obj): Obj {
|
||||||
|
(other as? ObjList) ?: context.raiseError("cannot concatenate $this with $other")
|
||||||
|
list += other.list
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override val objClass: ObjClass
|
||||||
|
get() = type
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val type = ObjClass("List").apply {
|
||||||
|
createField("size",
|
||||||
|
statement {
|
||||||
|
(thisObj as ObjList).list.size.toObj()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
createField("add",
|
||||||
|
statement {
|
||||||
|
val l = thisAs<ObjList>().list
|
||||||
|
for (a in args) l.add(a)
|
||||||
|
ObjVoid
|
||||||
|
}
|
||||||
|
)
|
||||||
|
createField("addAt",
|
||||||
|
statement {
|
||||||
|
if (args.size < 2) raiseError("addAt takes 2+ arguments")
|
||||||
|
val l = thisAs<ObjList>()
|
||||||
|
var index = l.normalize(this, requiredArg<ObjInt>(0).value.toInt())
|
||||||
|
for (i in 1..<args.size) l.list.add(index++, args[i])
|
||||||
|
ObjVoid
|
||||||
|
}
|
||||||
|
)
|
||||||
|
createField("removeAt",
|
||||||
|
statement {
|
||||||
|
val self = thisAs<ObjList>()
|
||||||
|
val start = self.normalize(this, requiredArg<ObjInt>(0).value.toInt())
|
||||||
|
if (args.size == 2) {
|
||||||
|
val end = requiredArg<ObjInt>(1).value.toInt()
|
||||||
|
self.list.subList(start, self.normalize(this, end)).clear()
|
||||||
|
} else
|
||||||
|
self.list.removeAt(start)
|
||||||
|
self
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -45,7 +45,12 @@ private class Parser(fromPos: Pos) {
|
|||||||
'=' -> {
|
'=' -> {
|
||||||
if (pos.currentChar == '=') {
|
if (pos.currentChar == '=') {
|
||||||
pos.advance()
|
pos.advance()
|
||||||
Token("==", from, Token.Type.EQ)
|
if( currentChar == '=' ) {
|
||||||
|
pos.advance()
|
||||||
|
Token("===", from, Token.Type.REF_EQ)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Token("==", from, Token.Type.EQ)
|
||||||
} else
|
} else
|
||||||
Token("=", from, Token.Type.ASSIGN)
|
Token("=", from, Token.Type.ASSIGN)
|
||||||
}
|
}
|
||||||
@ -150,7 +155,12 @@ private class Parser(fromPos: Pos) {
|
|||||||
'!' -> {
|
'!' -> {
|
||||||
if (currentChar == '=') {
|
if (currentChar == '=') {
|
||||||
pos.advance()
|
pos.advance()
|
||||||
Token("!=", from, Token.Type.NEQ)
|
if( currentChar == '=' ) {
|
||||||
|
pos.advance()
|
||||||
|
Token("!==", from, Token.Type.REF_NEQ)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Token("!=", from, Token.Type.NEQ)
|
||||||
} else
|
} else
|
||||||
Token("!", from, Token.Type.NOT)
|
Token("!", from, Token.Type.NOT)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class Script(
|
|||||||
}
|
}
|
||||||
|
|
||||||
addVoidFn("assert") {
|
addVoidFn("assert") {
|
||||||
val cond = args.required<ObjBool>(0, this)
|
val cond = requiredArg<ObjBool>(0)
|
||||||
if( !cond.value == true )
|
if( !cond.value == true )
|
||||||
raiseError(ObjAssertionError(this,"Assertion failed"))
|
raiseError(ObjAssertionError(this,"Assertion failed"))
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ data class Token(val value: String, val pos: Pos, val type: Type) {
|
|||||||
PLUS, MINUS, STAR, SLASH, PERCENT,
|
PLUS, MINUS, STAR, SLASH, PERCENT,
|
||||||
ASSIGN, PLUSASSIGN, MINUSASSIGN, STARASSIGN, SLASHASSIGN, PERCENTASSIGN,
|
ASSIGN, PLUSASSIGN, MINUSASSIGN, STARASSIGN, SLASHASSIGN, PERCENTASSIGN,
|
||||||
PLUS2, MINUS2,
|
PLUS2, MINUS2,
|
||||||
EQ, NEQ, LT, LTE, GT, GTE,
|
EQ, NEQ, LT, LTE, GT, GTE, REF_EQ, REF_NEQ,
|
||||||
AND, BITAND, OR, BITOR, NOT, BITNOT, DOT, ARROW, QUESTION, COLONCOLON,
|
AND, BITAND, OR, BITOR, NOT, BITNOT, DOT, ARROW, QUESTION, COLONCOLON,
|
||||||
SINLGE_LINE_COMMENT, MULTILINE_COMMENT,
|
SINLGE_LINE_COMMENT, MULTILINE_COMMENT,
|
||||||
LABEL, ATLABEL, // label@ at@label
|
LABEL, ATLABEL, // label@ at@label
|
||||||
|
@ -45,4 +45,10 @@ fun statement(pos: Pos, isStaticConst: Boolean = false, isConst: Boolean = false
|
|||||||
override suspend fun execute(context: Context): Obj = f(context)
|
override suspend fun execute(context: Context): Obj = f(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun statement(isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend Context.() -> Obj): Statement =
|
||||||
|
object : Statement(isStaticConst, isConst) {
|
||||||
|
override val pos: Pos = Pos.builtIn
|
||||||
|
override suspend fun execute(context: Context): Obj = f(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -795,6 +795,18 @@ class ScriptTest {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testArrayCompare() = runTest {
|
||||||
|
eval("""
|
||||||
|
val a = [4,3]
|
||||||
|
val b = [4,3]
|
||||||
|
assert(a == b)
|
||||||
|
assert( a === a )
|
||||||
|
assert( !(a === b) )
|
||||||
|
assert( a !== b )
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
// @Test
|
// @Test
|
||||||
// fun testLambda1() = runTest {
|
// fun testLambda1() = runTest {
|
||||||
// val l = eval("""
|
// val l = eval("""
|
||||||
|
@ -151,7 +151,7 @@ suspend fun DocTest.test() {
|
|||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
error = e
|
error = e
|
||||||
null
|
null
|
||||||
}?.toString()?.replace(Regex("@\\d+"), "@...")
|
}?.inspect()?.replace(Regex("@\\d+"), "@...")
|
||||||
|
|
||||||
if (error != null || expectedOutput != collectedOutput.toString() ||
|
if (error != null || expectedOutput != collectedOutput.toString() ||
|
||||||
expectedResult != result
|
expectedResult != result
|
||||||
|
Loading…
x
Reference in New Issue
Block a user