1.1.1-SNPASHOT some serious bugs in initilazation fixed. They were revealed by delegation real world usage
This commit is contained in:
1 parent
20f777f9f6
commit
f792c73b8f
17 files changed
+283
-48
No files matched your search
@@ -623,9 +623,16 @@ open class Scope(
|
||||
|
||||
suspend fun resolve(rec: ObjRecord, name: String): Obj {
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val del = rec.delegate ?: raiseError("Internal error: delegated property $name has no delegate")
|
||||
val del = rec.delegate ?: run {
|
||||
if (thisObj is ObjInstance) {
|
||||
val res = (thisObj as ObjInstance).resolveRecord(this, rec, name, rec.declaringClass).value
|
||||
rec.value = res
|
||||
return res
|
||||
}
|
||||
raiseError("Internal error: delegated property $name has no delegate")
|
||||
}
|
||||
val th = if (thisObj === ObjVoid) ObjNull else thisObj
|
||||
return del.invokeInstanceMethod(this, "getValue", Arguments(th, ObjString(name)), onNotFoundResult = {
|
||||
val res = del.invokeInstanceMethod(this, "getValue", Arguments(th, ObjString(name)), onNotFoundResult = {
|
||||
// If getValue not found, return a wrapper that calls invoke
|
||||
object : Statement() {
|
||||
override val pos: Pos = Pos.builtIn
|
||||
@@ -636,13 +643,21 @@ open class Scope(
|
||||
}
|
||||
}
|
||||
})!!
|
||||
rec.value = res
|
||||
return res
|
||||
}
|
||||
return rec.value
|
||||
}
|
||||
|
||||
suspend fun assign(rec: ObjRecord, name: String, newValue: Obj) {
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val del = rec.delegate ?: raiseError("Internal error: delegated property $name has no delegate")
|
||||
val del = rec.delegate ?: run {
|
||||
if (thisObj is ObjInstance) {
|
||||
(thisObj as ObjInstance).writeField(this, name, newValue)
|
||||
return
|
||||
}
|
||||
raiseError("Internal error: delegated property $name has no delegate")
|
||||
}
|
||||
val th = if (thisObj === ObjVoid) ObjNull else thisObj
|
||||
del.invokeInstanceMethod(this, "setValue", Arguments(th, ObjString(name), newValue))
|
||||
return
|
||||
|
||||
@@ -137,11 +137,20 @@ open class Obj {
|
||||
// methods that to override
|
||||
|
||||
open suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if( other === this) return 0
|
||||
if( other === ObjNull ) return 2
|
||||
if (other === this) return 0
|
||||
if (other === ObjNull || other === ObjUnset || other === ObjVoid) return 2
|
||||
scope.raiseNotImplemented()
|
||||
}
|
||||
|
||||
open suspend fun equals(scope: Scope, other: Obj): Boolean {
|
||||
if (other === this) return true
|
||||
return try {
|
||||
compareTo(scope, other) == 0
|
||||
} catch (e: ExecutionError) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
open suspend fun contains(scope: Scope, other: Obj): Boolean {
|
||||
return invokeInstanceMethod(scope, "contains", other).toBool()
|
||||
}
|
||||
@@ -364,7 +373,7 @@ open class Obj {
|
||||
)
|
||||
}
|
||||
|
||||
protected open suspend fun resolveRecord(scope: Scope, obj: ObjRecord, name: String, decl: ObjClass?): ObjRecord {
|
||||
open suspend fun resolveRecord(scope: Scope, obj: ObjRecord, name: String, decl: ObjClass?): ObjRecord {
|
||||
if (obj.type == ObjRecord.Type.Delegated) {
|
||||
val del = obj.delegate ?: scope.raiseError("Internal error: delegated property $name has no delegate")
|
||||
return obj.copy(
|
||||
|
||||
@@ -235,7 +235,7 @@ open class ObjClass(
|
||||
// 1) members-defined methods
|
||||
for ((k, v) in members) {
|
||||
if (v.value is Statement || v.type == ObjRecord.Type.Delegated) {
|
||||
instance.instanceScope.objects[k] = v
|
||||
instance.instanceScope.objects[k] = if (v.type == ObjRecord.Type.Delegated) v.copy() else v
|
||||
}
|
||||
}
|
||||
// 2) class-scope methods registered during class-body execution
|
||||
@@ -243,7 +243,7 @@ open class ObjClass(
|
||||
if (rec.value is Statement || rec.type == ObjRecord.Type.Delegated) {
|
||||
// if not already present, copy reference for dispatch
|
||||
if (!instance.instanceScope.objects.containsKey(k)) {
|
||||
instance.instanceScope.objects[k] = rec
|
||||
instance.instanceScope.objects[k] = if (rec.type == ObjRecord.Type.Delegated) rec.copy() else rec
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,7 +480,7 @@ open class ObjClass(
|
||||
|
||||
fun addClassConst(name: String, value: Obj) = createClassField(name, value)
|
||||
fun addClassFn(name: String, isOpen: Boolean = false, code: suspend Scope.() -> Obj) {
|
||||
createClassField(name, statement { code() }, isOpen)
|
||||
createClassField(name, statement { code() }, isOpen, type = ObjRecord.Type.Fun)
|
||||
}
|
||||
|
||||
|
||||
@@ -588,11 +588,21 @@ open class ObjClass(
|
||||
getInstanceMemberOrNull(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: findDeclaringClassOf(name) ?: this
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val del = rec.delegate ?: scope.raiseError("Internal error: delegated function $name has no delegate")
|
||||
val del = rec.delegate ?: scope.raiseError("Internal error: delegated member $name has no delegate")
|
||||
val allArgs = (listOf(this, ObjString(name)) + args.list).toTypedArray()
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs))
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs), onNotFoundResult = {
|
||||
// Fallback: property delegation
|
||||
val propVal = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
propVal.invoke(scope, this, args, decl)
|
||||
})!!
|
||||
}
|
||||
if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(scope, this, args, decl)
|
||||
} else {
|
||||
// Resolved field or property value
|
||||
val resolved = readField(scope, name)
|
||||
return resolved.value.invoke(scope, this, args, decl)
|
||||
}
|
||||
return rec.value.invoke(scope, this, args, decl)
|
||||
}
|
||||
return super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
}
|
||||
|
||||
@@ -92,10 +92,9 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
}
|
||||
del = del ?: obj.delegate ?: scope.raiseError("Internal error: delegated property $name has no delegate (tried $storageName)")
|
||||
return obj.copy(
|
||||
value = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name))),
|
||||
type = ObjRecord.Type.Other
|
||||
)
|
||||
val res = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
obj.value = res
|
||||
return obj
|
||||
}
|
||||
return super.resolveRecord(scope, obj, name, decl)
|
||||
}
|
||||
@@ -197,11 +196,15 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val storageName = "${cls.className}::$name"
|
||||
val del = instanceScope[storageName]?.delegate ?: rec.delegate
|
||||
?: scope.raiseError("Internal error: delegated function $name has no delegate (tried $storageName)")
|
||||
?: scope.raiseError("Internal error: delegated member $name has no delegate (tried $storageName)")
|
||||
val allArgs = (listOf(this, ObjString(name)) + args.list).toTypedArray()
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs))
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs), onNotFoundResult = {
|
||||
// Fallback: property delegation
|
||||
val propVal = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
propVal.invoke(scope, this, args, rec.declaringClass ?: cls)
|
||||
})!!
|
||||
}
|
||||
if (rec.type != ObjRecord.Type.Property && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Fun && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val caller = scope.currentClassCtx ?: if (scope.thisObj === this) objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
@@ -217,6 +220,9 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
args,
|
||||
decl
|
||||
)
|
||||
} else if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property) && !rec.isAbstract) {
|
||||
val resolved = readField(scope, name)
|
||||
return resolved.value.invoke(scope, this, args, resolved.declaringClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,8 +243,8 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
||||
BinOp.OR -> a.logicalOr(scope, b)
|
||||
BinOp.AND -> a.logicalAnd(scope, b)
|
||||
BinOp.EQARROW -> ObjMapEntry(a, b)
|
||||
BinOp.EQ -> ObjBool(a.compareTo(scope, b) == 0)
|
||||
BinOp.NEQ -> ObjBool(a.compareTo(scope, b) != 0)
|
||||
BinOp.EQ -> ObjBool(a.equals(scope, b))
|
||||
BinOp.NEQ -> ObjBool(!a.equals(scope, b))
|
||||
BinOp.REF_EQ -> ObjBool(a === b)
|
||||
BinOp.REF_NEQ -> ObjBool(a !== b)
|
||||
BinOp.MATCH -> a.operatorMatch(scope, b)
|
||||
@@ -611,7 +611,7 @@ class FieldRef(
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
val fieldPic = PerfFlags.FIELD_PIC
|
||||
val picCounters = PerfFlags.PIC_DEBUG_COUNTERS
|
||||
val base = target.get(scope).value
|
||||
val base = target.evalValue(scope)
|
||||
if (base == ObjNull && isOptional) {
|
||||
// no-op on null receiver for optional chaining assignment
|
||||
return
|
||||
@@ -714,10 +714,9 @@ class FieldRef(
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
// Mirror get(), but return raw Obj to avoid transient ObjRecord on R-value paths
|
||||
val fastRval = PerfFlags.RVAL_FASTPATH
|
||||
val fieldPic = PerfFlags.FIELD_PIC
|
||||
val picCounters = PerfFlags.PIC_DEBUG_COUNTERS
|
||||
val base = if (fastRval) target.evalValue(scope) else target.get(scope).value
|
||||
val base = target.evalValue(scope)
|
||||
if (base == ObjNull && isOptional) return ObjNull
|
||||
if (fieldPic) {
|
||||
val (key, ver) = receiverKeyAndVersion(base)
|
||||
@@ -1583,7 +1582,7 @@ class FastLocalVarRef(
|
||||
if (slot >= 0 && actualOwner != null) {
|
||||
val rec = actualOwner.getSlotRecord(slot)
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx)) {
|
||||
return actualOwner.resolve(rec, name)
|
||||
return scope.resolve(rec, name)
|
||||
}
|
||||
}
|
||||
// Try per-frame local binding maps in the ancestry first
|
||||
|
||||
Reference in new issue
Block a user