optimizing refactoring: no more StoredObj.kt, WithAccess now always deals with Obj and is renamed to ObjRecord
This commit is contained in:
parent
33fdb0934a
commit
56e0d2fd63
@ -132,7 +132,7 @@ class Compiler(
|
|||||||
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
|
||||||
WithAccess(
|
ObjRecord(
|
||||||
v.invokeInstanceMethod(
|
v.invokeInstanceMethod(
|
||||||
context,
|
context,
|
||||||
next.value,
|
next.value,
|
||||||
@ -641,7 +641,7 @@ class Compiler(
|
|||||||
else -> {
|
else -> {
|
||||||
Accessor({
|
Accessor({
|
||||||
it.pos = t.pos
|
it.pos = t.pos
|
||||||
it.get(t.value)?.asAccess
|
it.get(t.value)
|
||||||
?: it.raiseError("symbol not defined: '${t.value}'")
|
?: it.raiseError("symbol not defined: '${t.value}'")
|
||||||
}) { ctx, newValue ->
|
}) { ctx, newValue ->
|
||||||
ctx.get(t.value)?.let { stored ->
|
ctx.get(t.value)?.let { stored ->
|
||||||
@ -886,7 +886,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loopIntRange(
|
private suspend fun loopIntRange(
|
||||||
forContext: Context, start: Int, end: Int, loopVar: StoredObj,
|
forContext: Context, start: Int, end: Int, loopVar: ObjRecord,
|
||||||
body: Statement, elseStatement: Statement?, label: String?, catchBreak: Boolean
|
body: Statement, elseStatement: Statement?, label: String?, catchBreak: Boolean
|
||||||
): Obj {
|
): Obj {
|
||||||
var result: Obj = ObjVoid
|
var result: Obj = ObjVoid
|
||||||
@ -914,7 +914,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loopIterable(
|
private suspend fun loopIterable(
|
||||||
forContext: Context, sourceObj: Obj, loopVar: StoredObj,
|
forContext: Context, sourceObj: Obj, loopVar: ObjRecord,
|
||||||
body: Statement, elseStatement: Statement?, label: String?,
|
body: Statement, elseStatement: Statement?, label: String?,
|
||||||
catchBreak: Boolean
|
catchBreak: Boolean
|
||||||
): Obj {
|
): Obj {
|
||||||
|
@ -56,9 +56,9 @@ class Context(
|
|||||||
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
|
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
|
||||||
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
||||||
|
|
||||||
private val objects = mutableMapOf<String, StoredObj>()
|
private val objects = mutableMapOf<String, ObjRecord>()
|
||||||
|
|
||||||
operator fun get(name: String): StoredObj? =
|
operator fun get(name: String): ObjRecord? =
|
||||||
objects[name]
|
objects[name]
|
||||||
?: parent?.get(name)
|
?: parent?.get(name)
|
||||||
|
|
||||||
@ -70,12 +70,12 @@ class Context(
|
|||||||
|
|
||||||
fun copy() = Context(this, args, pos, thisObj)
|
fun copy() = Context(this, args, pos, thisObj)
|
||||||
|
|
||||||
fun addItem(name: String, isMutable: Boolean, value: Obj?): StoredObj {
|
fun addItem(name: String, isMutable: Boolean, value: Obj): ObjRecord {
|
||||||
return StoredObj(value, isMutable).also { objects.put(name, it) }
|
return ObjRecord(value, isMutable).also { objects.put(name, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOrCreateNamespace(name: String): ObjClass {
|
fun getOrCreateNamespace(name: String): ObjClass {
|
||||||
val ns = objects.getOrPut(name) { StoredObj(ObjNamespace(name), isMutable = false) }.value
|
val ns = objects.getOrPut(name) { ObjRecord(ObjNamespace(name), isMutable = false) }.value
|
||||||
return ns!!.objClass
|
return ns!!.objClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,20 +6,35 @@ import kotlinx.serialization.SerialName
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import net.sergeych.synctools.ProtectedOp
|
import net.sergeych.synctools.ProtectedOp
|
||||||
|
|
||||||
//typealias InstanceMethod = (Context, Obj) -> Obj
|
/**
|
||||||
|
* Record to store object with access rules, e.g. [isMutable] and access level [visibility].
|
||||||
data class WithAccess<T>(
|
*/
|
||||||
var value: T,
|
data class ObjRecord(
|
||||||
|
var value: Obj,
|
||||||
val isMutable: Boolean,
|
val isMutable: Boolean,
|
||||||
val visibility: Compiler.Visibility = Compiler.Visibility.Public
|
val visibility: Compiler.Visibility = Compiler.Visibility.Public
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we need read-write access to an object in some abstract storage, we need Accessor,
|
||||||
|
* as in-site assigning is not always sufficient, in general case we need to replace the object
|
||||||
|
* in the storage.
|
||||||
|
*
|
||||||
|
* Note that assigning new value is more complex than just replacing the object, see how assignment
|
||||||
|
* operator is implemented in [Compiler.allOps].
|
||||||
|
*/
|
||||||
data class Accessor(
|
data class Accessor(
|
||||||
val getter: suspend (Context) -> WithAccess<Obj>,
|
val getter: suspend (Context) -> ObjRecord,
|
||||||
val setterOrNull: (suspend (Context, Obj) -> Unit)?
|
val setterOrNull: (suspend (Context, Obj) -> Unit)?
|
||||||
) {
|
) {
|
||||||
constructor(getter: suspend (Context) -> WithAccess<Obj>) : this(getter, null)
|
/**
|
||||||
|
* Simplified constructor for immutable stores.
|
||||||
|
*/
|
||||||
|
constructor(getter: suspend (Context) -> ObjRecord) : this(getter, null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the setter or throw.
|
||||||
|
*/
|
||||||
fun setter(pos: Pos) = setterOrNull ?: throw ScriptError(pos, "can't assign value")
|
fun setter(pos: Pos) = setterOrNull ?: throw ScriptError(pos, "can't assign value")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,13 +179,13 @@ open class Obj {
|
|||||||
|
|
||||||
suspend fun <T> sync(block: () -> T): T = monitor.withLock { block() }
|
suspend fun <T> sync(block: () -> T): T = monitor.withLock { block() }
|
||||||
|
|
||||||
suspend fun readField(context: Context, name: String): WithAccess<Obj> {
|
suspend fun readField(context: Context, name: String): ObjRecord {
|
||||||
// could be property or class field:
|
// could be property or class field:
|
||||||
val obj = objClass.getInstanceMemberOrNull(name)
|
val obj = objClass.getInstanceMemberOrNull(name)
|
||||||
val value = obj?.value
|
val value = obj?.value
|
||||||
return when (value) {
|
return when (value) {
|
||||||
is Statement -> {
|
is Statement -> {
|
||||||
WithAccess(value.execute(context.copy(context.pos, newThisObj = this)), obj.isMutable)
|
ObjRecord(value.execute(context.copy(context.pos, newThisObj = this)), obj.isMutable)
|
||||||
}
|
}
|
||||||
// could be writable property naturally
|
// could be writable property naturally
|
||||||
null -> ObjNull.asReadonly
|
null -> ObjNull.asReadonly
|
||||||
@ -221,8 +236,8 @@ open class Obj {
|
|||||||
callOn(context.copy(atPos, args = args, newThisObj = thisObj))
|
callOn(context.copy(atPos, args = args, newThisObj = thisObj))
|
||||||
|
|
||||||
|
|
||||||
val asReadonly: WithAccess<Obj> by lazy { WithAccess(this, false) }
|
val asReadonly: ObjRecord by lazy { ObjRecord(this, false) }
|
||||||
val asMutable: WithAccess<Obj> by lazy { WithAccess(this, true) }
|
val asMutable: ObjRecord by lazy { ObjRecord(this, true) }
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -16,7 +16,7 @@ class ObjClass(
|
|||||||
override val objClass: ObjClass by lazy { ObjClassType }
|
override val objClass: ObjClass by lazy { ObjClassType }
|
||||||
|
|
||||||
// members: fields most often
|
// members: fields most often
|
||||||
private val members = mutableMapOf<String, WithAccess<Obj>>()
|
private val members = mutableMapOf<String, ObjRecord>()
|
||||||
|
|
||||||
override fun toString(): String = className
|
override fun toString(): String = className
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class ObjClass(
|
|||||||
) {
|
) {
|
||||||
if (name in members || allParentsSet.any { name in it.members } == true)
|
if (name in members || allParentsSet.any { name in it.members } == true)
|
||||||
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||||
members[name] = WithAccess(initialValue, isMutable)
|
members[name] = ObjRecord(initialValue, isMutable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addFn(name: String, isOpen: Boolean = false, code: suspend Context.() -> Obj) {
|
fun addFn(name: String, isOpen: Boolean = false, code: suspend Context.() -> Obj) {
|
||||||
@ -59,13 +59,13 @@ class ObjClass(
|
|||||||
/**
|
/**
|
||||||
* Get instance member traversing the hierarchy if needed. Its meaning is different for different objects.
|
* Get instance member traversing the hierarchy if needed. Its meaning is different for different objects.
|
||||||
*/
|
*/
|
||||||
fun getInstanceMemberOrNull(name: String): WithAccess<Obj>? {
|
fun getInstanceMemberOrNull(name: String): ObjRecord? {
|
||||||
members[name]?.let { return it }
|
members[name]?.let { return it }
|
||||||
allParentsSet.forEach { parent -> parent.getInstanceMemberOrNull(name)?.let { return it } }
|
allParentsSet.forEach { parent -> parent.getInstanceMemberOrNull(name)?.let { return it } }
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInstanceMember(atPos: Pos, name: String): WithAccess<Obj> =
|
fun getInstanceMember(atPos: Pos, name: String): ObjRecord =
|
||||||
getInstanceMemberOrNull(name)
|
getInstanceMemberOrNull(name)
|
||||||
?: throw ScriptError(atPos, "symbol doesn't exist: $name")
|
?: throw ScriptError(atPos, "symbol doesn't exist: $name")
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package net.sergeych.lyng
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whatever [Obj] stored somewhere
|
|
||||||
*/
|
|
||||||
data class StoredObj(
|
|
||||||
var value: Obj?,
|
|
||||||
val isMutable: Boolean = false
|
|
||||||
) {
|
|
||||||
val asAccess: WithAccess<Obj>? get() = value?.let { WithAccess(it, isMutable) }
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user