fix #39 correct implementation of ++ and -- with indexing access
This commit is contained in:
parent
f1ae4b2d23
commit
5848adca61
@ -54,6 +54,8 @@ Buffer provides concatenation with another Buffer:
|
|||||||
assertEquals( Buffer(101, 102, 1, 2), b + [1,2])
|
assertEquals( Buffer(101, 102, 1, 2), b + [1,2])
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
|
Please note that indexed bytes are _readonly projection_, e.g. you can't modify these with
|
||||||
|
|
||||||
## Comparing
|
## Comparing
|
||||||
|
|
||||||
Buffers are comparable with other buffers:
|
Buffers are comparable with other buffers:
|
||||||
|
@ -12,10 +12,6 @@ class Compiler(
|
|||||||
settings: Settings = Settings()
|
settings: Settings = Settings()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
init {
|
|
||||||
println("Compiler initialized: $importManager")
|
|
||||||
}
|
|
||||||
|
|
||||||
var packageName: String? = null
|
var packageName: String? = null
|
||||||
|
|
||||||
class Settings
|
class Settings
|
||||||
@ -27,7 +23,7 @@ class Compiler(
|
|||||||
// package level declarations
|
// package level declarations
|
||||||
do {
|
do {
|
||||||
val t = cc.current()
|
val t = cc.current()
|
||||||
if(t.type == Token.Type.NEWLINE || t.type == Token.Type.SINLGE_LINE_COMMENT || t.type == Token.Type.MULTILINE_COMMENT) {
|
if (t.type == Token.Type.NEWLINE || t.type == Token.Type.SINLGE_LINE_COMMENT || t.type == Token.Type.MULTILINE_COMMENT) {
|
||||||
cc.next()
|
cc.next()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -44,6 +40,7 @@ class Compiler(
|
|||||||
packageName = name
|
packageName = name
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
"import" -> {
|
"import" -> {
|
||||||
cc.next()
|
cc.next()
|
||||||
val pos = cc.currentPos()
|
val pos = cc.currentPos()
|
||||||
@ -349,17 +346,26 @@ class Compiler(
|
|||||||
left.setter(startPos)
|
left.setter(startPos)
|
||||||
operand = Accessor { cxt ->
|
operand = Accessor { cxt ->
|
||||||
val x = left.getter(cxt)
|
val x = left.getter(cxt)
|
||||||
if (x.isMutable)
|
if (x.isMutable) {
|
||||||
x.value.getAndIncrement(cxt).asReadonly
|
if (x.value.isConst) {
|
||||||
else cxt.raiseError("Cannot increment immutable value")
|
x.value.plus(cxt, ObjInt.One).also {
|
||||||
|
left.setter(startPos)(cxt, it)
|
||||||
|
}.asReadonly
|
||||||
|
} else
|
||||||
|
x.value.getAndIncrement(cxt).asReadonly
|
||||||
|
} else cxt.raiseError("Cannot increment immutable value")
|
||||||
}
|
}
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// no lvalue means pre-increment, expression to increment follows
|
// no lvalue means pre-increment, expression to increment follows
|
||||||
val next = parseAccessor() ?: throw ScriptError(t.pos, "Expecting expression")
|
val next = parseTerm() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = Accessor { ctx ->
|
operand = Accessor { ctx ->
|
||||||
next.getter(ctx).also {
|
val x = next.getter(ctx).also {
|
||||||
if (!it.isMutable) ctx.raiseError("Cannot increment immutable value")
|
if (!it.isMutable) ctx.raiseError("Cannot increment immutable value")
|
||||||
}.value.incrementAndGet(ctx).asReadonly
|
}.value
|
||||||
|
if (x.isConst) {
|
||||||
|
next.setter(startPos)(ctx, x.plus(ctx, ObjInt.One))
|
||||||
|
x.asReadonly
|
||||||
|
} else x.incrementAndGet(ctx).asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,18 +375,28 @@ class Compiler(
|
|||||||
operand?.let { left ->
|
operand?.let { left ->
|
||||||
// post decrement
|
// post decrement
|
||||||
left.setter(startPos)
|
left.setter(startPos)
|
||||||
operand = Accessor { ctx ->
|
operand = Accessor { cxt ->
|
||||||
left.getter(ctx).also {
|
val x = left.getter(cxt)
|
||||||
if (!it.isMutable) ctx.raiseError("Cannot decrement immutable value")
|
if (!x.isMutable) cxt.raiseError("Cannot decrement immutable value")
|
||||||
}.value.getAndDecrement(ctx).asReadonly
|
if (x.value.isConst) {
|
||||||
|
x.value.minus(cxt, ObjInt.One).also {
|
||||||
|
left.setter(startPos)(cxt, it)
|
||||||
|
}.asReadonly
|
||||||
|
} else
|
||||||
|
x.value.getAndDecrement(cxt).asReadonly
|
||||||
}
|
}
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// no lvalue means pre-decrement, expression to decrement follows
|
// no lvalue means pre-decrement, expression to decrement follows
|
||||||
val next = parseAccessor() ?: throw ScriptError(t.pos, "Expecting expression")
|
val next = parseTerm() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = Accessor { ctx ->
|
operand = Accessor { cxt ->
|
||||||
next.getter(ctx).also {
|
val x = next.getter(cxt)
|
||||||
if (!it.isMutable) ctx.raiseError("Cannot decrement immutable value")
|
if (!x.isMutable) cxt.raiseError("Cannot decrement immutable value")
|
||||||
}.value.decrementAndGet(ctx).asReadonly
|
if (x.value.isConst) {
|
||||||
|
x.value.minus(cxt, ObjInt.One).also {
|
||||||
|
next.setter(startPos)(cxt, it)
|
||||||
|
}.asReadonly
|
||||||
|
} else
|
||||||
|
x.value.decrementAndGet(cxt).asReadonly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1623,8 +1639,8 @@ class Compiler(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
suspend fun compile(source: Source,importManager: ImportProvider): Script {
|
suspend fun compile(source: Source, importManager: ImportProvider): Script {
|
||||||
return Compiler(CompilerContext(parseLyng(source)),importManager).parseScript()
|
return Compiler(CompilerContext(parseLyng(source)), importManager).parseScript()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastPriority = 0
|
private var lastPriority = 0
|
||||||
|
@ -48,6 +48,12 @@ data class Accessor(
|
|||||||
|
|
||||||
open class Obj {
|
open class Obj {
|
||||||
|
|
||||||
|
open val isConst: Boolean = false
|
||||||
|
|
||||||
|
fun ensureNotConst(scope: Scope) {
|
||||||
|
if( isConst ) scope.raiseError("can't assign to constant")
|
||||||
|
}
|
||||||
|
|
||||||
val isNull by lazy { this === ObjNull }
|
val isNull by lazy { this === ObjNull }
|
||||||
|
|
||||||
var isFrozen: Boolean = false
|
var isFrozen: Boolean = false
|
||||||
|
@ -82,7 +82,6 @@ open class ObjClass(
|
|||||||
|
|
||||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||||
classMembers[name]?.let {
|
classMembers[name]?.let {
|
||||||
println("class field $it")
|
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
return super.readField(scope, name)
|
return super.readField(scope, name)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
class ObjInt(var value: Long,val isConst: Boolean = false) : Obj(), Numeric {
|
class ObjInt(var value: Long,override val isConst: Boolean = false) : Obj(), Numeric {
|
||||||
override val asStr get() = ObjString(value.toString())
|
override val asStr get() = ObjString(value.toString())
|
||||||
override val longValue get() = value
|
override val longValue get() = value
|
||||||
override val doubleValue get() = value.toDouble()
|
override val doubleValue get() = value.toDouble()
|
||||||
@ -14,18 +14,22 @@ class ObjInt(var value: Long,val isConst: Boolean = false) : Obj(), Numeric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getAndIncrement(scope: Scope): Obj {
|
override suspend fun getAndIncrement(scope: Scope): Obj {
|
||||||
|
ensureNotConst(scope)
|
||||||
return ObjInt(value).also { value++ }
|
return ObjInt(value).also { value++ }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getAndDecrement(scope: Scope): Obj {
|
override suspend fun getAndDecrement(scope: Scope): Obj {
|
||||||
|
ensureNotConst(scope)
|
||||||
return ObjInt(value).also { value-- }
|
return ObjInt(value).also { value-- }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun incrementAndGet(scope: Scope): Obj {
|
override suspend fun incrementAndGet(scope: Scope): Obj {
|
||||||
|
ensureNotConst(scope)
|
||||||
return ObjInt(++value)
|
return ObjInt(++value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun decrementAndGet(scope: Scope): Obj {
|
override suspend fun decrementAndGet(scope: Scope): Obj {
|
||||||
|
ensureNotConst(scope)
|
||||||
return ObjInt(--value)
|
return ObjInt(--value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,6 @@ class ImportManager(
|
|||||||
*/
|
*/
|
||||||
private suspend fun doImport(packageName: String, pos: Pos): ModuleScope {
|
private suspend fun doImport(packageName: String, pos: Pos): ModuleScope {
|
||||||
val entry = imports[packageName] ?: throw ImportException(pos, "package not found: $packageName")
|
val entry = imports[packageName] ?: throw ImportException(pos, "package not found: $packageName")
|
||||||
println("import enrty found: $packageName")
|
|
||||||
return entry.getScope(pos)
|
return entry.getScope(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ sealed class ObjType {
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
abstract class Statement(
|
abstract class Statement(
|
||||||
val isStaticConst: Boolean = false,
|
val isStaticConst: Boolean = false,
|
||||||
val isConst: Boolean = false,
|
override val isConst: Boolean = false,
|
||||||
val returnType: ObjType = ObjType.Any
|
val returnType: ObjType = ObjType.Any
|
||||||
) : Obj() {
|
) : Obj() {
|
||||||
|
|
||||||
|
@ -707,19 +707,13 @@ class ScriptTest {
|
|||||||
var t1 = 10
|
var t1 = 10
|
||||||
outer@ while( t1 > 0 ) {
|
outer@ while( t1 > 0 ) {
|
||||||
var t2 = 10
|
var t2 = 10
|
||||||
println("starting t2 = " + t2)
|
|
||||||
while( t2 > 0 ) {
|
while( t2 > 0 ) {
|
||||||
t2 = t2 - 1
|
t2 = t2 - 1
|
||||||
println("t2 " + t2 + " t1 " + t1)
|
|
||||||
if( t2 == 3 && t1 == 7) {
|
if( t2 == 3 && t1 == 7) {
|
||||||
println("will break")
|
|
||||||
break@outer "ok2:"+t2+":"+t1
|
break@outer "ok2:"+t2+":"+t1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("next t1")
|
--t1
|
||||||
t1 = t1 - 1
|
|
||||||
println("t1 now "+t1)
|
|
||||||
t1
|
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
).toString()
|
).toString()
|
||||||
@ -734,8 +728,6 @@ class ScriptTest {
|
|||||||
"""
|
"""
|
||||||
val count = 3
|
val count = 3
|
||||||
val res = if( count > 10 ) "too much" else "just " + count
|
val res = if( count > 10 ) "too much" else "just " + count
|
||||||
println(count)
|
|
||||||
println(res)
|
|
||||||
res
|
res
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
@ -771,7 +763,7 @@ class ScriptTest {
|
|||||||
fun testDecr() = runTest {
|
fun testDecr() = runTest {
|
||||||
val c = Scope()
|
val c = Scope()
|
||||||
c.eval("var x = 9")
|
c.eval("var x = 9")
|
||||||
assertEquals(9, c.eval("x--").toInt())
|
assertEquals(9, c.eval("println(x); val a = x--; println(x); println(a); a").toInt())
|
||||||
assertEquals(8, c.eval("x--").toInt())
|
assertEquals(8, c.eval("x--").toInt())
|
||||||
assertEquals(7, c.eval("x--").toInt())
|
assertEquals(7, c.eval("x--").toInt())
|
||||||
assertEquals(6, c.eval("x--").toInt())
|
assertEquals(6, c.eval("x--").toInt())
|
||||||
@ -2612,4 +2604,40 @@ class ScriptTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIndexIntIncrements() = runTest {
|
||||||
|
eval("""
|
||||||
|
val x = [1,2,3]
|
||||||
|
x[1]++
|
||||||
|
++x[0]
|
||||||
|
assertEquals( [2,3,3], x )
|
||||||
|
|
||||||
|
import lyng.buffer
|
||||||
|
|
||||||
|
val b = Buffer(1,2,3)
|
||||||
|
b[1]++
|
||||||
|
assert( b == Buffer(1,3,3) )
|
||||||
|
++b[0]
|
||||||
|
assertEquals( b, Buffer(2,3,3) )
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIndexIntDecrements() = runTest {
|
||||||
|
eval("""
|
||||||
|
val x = [1,2,3]
|
||||||
|
x[1]--
|
||||||
|
--x[0]
|
||||||
|
assertEquals( [0,1,3], x )
|
||||||
|
|
||||||
|
import lyng.buffer
|
||||||
|
|
||||||
|
val b = Buffer(1,2,3)
|
||||||
|
b[1]--
|
||||||
|
assert( b == Buffer(1,1,3) )
|
||||||
|
--b[0]
|
||||||
|
assertEquals( b, Buffer(0,1,3) )
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user