Compare commits
No commits in common. "74d73540c628d30b317dbc0b472cf5bc8ba95fd6" and "062f9e786619b001ecec57ca5a2fb09a7449887a" have entirely different histories.
74d73540c6
...
062f9e7866
File diff suppressed because it is too large
Load Diff
@ -392,24 +392,6 @@ open class Scope(
|
||||
nameToSlot[name]?.let { slots[it] = record }
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a precomputed slot plan (name -> slot index) for this scope.
|
||||
* This enables direct slot references to bypass name-based lookup.
|
||||
*/
|
||||
fun applySlotPlan(plan: Map<String, Int>) {
|
||||
if (plan.isEmpty()) return
|
||||
val maxIndex = plan.values.maxOrNull() ?: return
|
||||
if (slots.size <= maxIndex) {
|
||||
val targetSize = maxIndex + 1
|
||||
while (slots.size < targetSize) {
|
||||
slots.add(ObjRecord(ObjUnset, isMutable = true))
|
||||
}
|
||||
}
|
||||
for ((name, idx) in plan) {
|
||||
nameToSlot[name] = idx
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all references and maps to prevent memory leaks when pooled.
|
||||
*/
|
||||
@ -521,7 +503,6 @@ open class Scope(
|
||||
if (this is ClosureScope) {
|
||||
callScope.localBindings[name] = it
|
||||
}
|
||||
bumpClassLayoutIfNeeded(name, value, recordType)
|
||||
it
|
||||
} ?: addItem(name, true, value, visibility, writeVisibility, recordType, isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride)
|
||||
|
||||
@ -548,24 +529,6 @@ open class Scope(
|
||||
isTransient = isTransient
|
||||
)
|
||||
objects[name] = rec
|
||||
bumpClassLayoutIfNeeded(name, value, recordType)
|
||||
if (recordType == ObjRecord.Type.Field || recordType == ObjRecord.Type.ConstructorField) {
|
||||
val inst = thisObj as? net.sergeych.lyng.obj.ObjInstance
|
||||
if (inst != null) {
|
||||
val slot = inst.objClass.fieldSlotForKey(name)
|
||||
if (slot != null) inst.setFieldSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
if (value is Statement ||
|
||||
recordType == ObjRecord.Type.Fun ||
|
||||
recordType == ObjRecord.Type.Delegated ||
|
||||
recordType == ObjRecord.Type.Property) {
|
||||
val inst = thisObj as? net.sergeych.lyng.obj.ObjInstance
|
||||
if (inst != null) {
|
||||
val slot = inst.objClass.methodSlotForKey(name)
|
||||
if (slot != null) inst.setMethodSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
// Index this binding within the current frame to help resolve locals across suspension
|
||||
localBindings[name] = rec
|
||||
// If we are a ClosureScope, mirror binding into the caller frame to keep it discoverable
|
||||
@ -595,14 +558,6 @@ open class Scope(
|
||||
return rec
|
||||
}
|
||||
|
||||
private fun bumpClassLayoutIfNeeded(name: String, value: Obj, recordType: ObjRecord.Type) {
|
||||
val cls = thisObj as? net.sergeych.lyng.obj.ObjClass ?: return
|
||||
if (cls.classScope !== this) return
|
||||
if (!(value is Statement || recordType == ObjRecord.Type.Fun || recordType == ObjRecord.Type.Delegated)) return
|
||||
if (cls.members.containsKey(name)) return
|
||||
cls.layoutVersion += 1
|
||||
}
|
||||
|
||||
fun getOrCreateNamespace(name: String): ObjClass {
|
||||
val ns = objects.getOrPut(name) { ObjRecord(ObjNamespace(name), isMutable = false) }.value
|
||||
return ns.objClass
|
||||
|
||||
@ -114,7 +114,8 @@ open class ObjClass(
|
||||
val classId: Long = ClassIdGen.nextId()
|
||||
var layoutVersion: Int = 0
|
||||
|
||||
fun mangledName(name: String): String = "$className::$name"
|
||||
private val mangledNameCache = mutableMapOf<String, String>()
|
||||
fun mangledName(name: String): String = mangledNameCache.getOrPut(name) { "$className::$name" }
|
||||
|
||||
/**
|
||||
* Map of public member names to their effective storage keys in instanceScope.objects.
|
||||
@ -127,7 +128,7 @@ open class ObjClass(
|
||||
if (cls.className == "Obj") continue
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.visibility == Visibility.Public) {
|
||||
val key = if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
val key = if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
res[name] = key
|
||||
}
|
||||
}
|
||||
@ -266,119 +267,6 @@ open class ObjClass(
|
||||
*/
|
||||
internal val members = mutableMapOf<String, ObjRecord>()
|
||||
|
||||
internal data class FieldSlot(val slot: Int, val record: ObjRecord)
|
||||
internal data class ResolvedMember(val record: ObjRecord, val declaringClass: ObjClass)
|
||||
internal data class MethodSlot(val slot: Int, val record: ObjRecord)
|
||||
private var fieldSlotLayoutVersion: Int = -1
|
||||
private var fieldSlotMap: Map<String, FieldSlot> = emptyMap()
|
||||
private var fieldSlotCount: Int = 0
|
||||
private var instanceMemberLayoutVersion: Int = -1
|
||||
private var instanceMemberCache: Map<String, ResolvedMember> = emptyMap()
|
||||
private var methodSlotLayoutVersion: Int = -1
|
||||
private var methodSlotMap: Map<String, MethodSlot> = emptyMap()
|
||||
private var methodSlotCount: Int = 0
|
||||
|
||||
private fun ensureFieldSlots(): Map<String, FieldSlot> {
|
||||
if (fieldSlotLayoutVersion == layoutVersion) return fieldSlotMap
|
||||
val res = mutableMapOf<String, FieldSlot>()
|
||||
var idx = 0
|
||||
for (cls in mro) {
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.isAbstract) continue
|
||||
if (rec.type != ObjRecord.Type.Field && rec.type != ObjRecord.Type.ConstructorField) continue
|
||||
val key = cls.mangledName(name)
|
||||
if (res.containsKey(key)) continue
|
||||
res[key] = FieldSlot(idx, rec)
|
||||
idx += 1
|
||||
}
|
||||
}
|
||||
fieldSlotMap = res
|
||||
fieldSlotCount = idx
|
||||
fieldSlotLayoutVersion = layoutVersion
|
||||
return fieldSlotMap
|
||||
}
|
||||
|
||||
private fun ensureInstanceMemberCache(): Map<String, ResolvedMember> {
|
||||
if (instanceMemberLayoutVersion == layoutVersion) return instanceMemberCache
|
||||
val res = mutableMapOf<String, ResolvedMember>()
|
||||
for (cls in mro) {
|
||||
if (cls.className == "Obj") break
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.isAbstract) continue
|
||||
if (res.containsKey(name)) continue
|
||||
val decl = rec.declaringClass ?: cls
|
||||
res[name] = ResolvedMember(rec, decl)
|
||||
}
|
||||
cls.classScope?.objects?.forEach { (name, rec) ->
|
||||
if (rec.isAbstract) return@forEach
|
||||
if (res.containsKey(name)) return@forEach
|
||||
val decl = rec.declaringClass ?: cls
|
||||
res[name] = ResolvedMember(rec, decl)
|
||||
}
|
||||
}
|
||||
instanceMemberCache = res
|
||||
instanceMemberLayoutVersion = layoutVersion
|
||||
return instanceMemberCache
|
||||
}
|
||||
|
||||
private fun ensureMethodSlots(): Map<String, MethodSlot> {
|
||||
if (methodSlotLayoutVersion == layoutVersion) return methodSlotMap
|
||||
val res = mutableMapOf<String, MethodSlot>()
|
||||
var idx = 0
|
||||
for (cls in mro) {
|
||||
if (cls.className == "Obj") break
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.isAbstract) continue
|
||||
if (rec.value !is Statement &&
|
||||
rec.type != ObjRecord.Type.Delegated &&
|
||||
rec.type != ObjRecord.Type.Fun &&
|
||||
rec.type != ObjRecord.Type.Property) {
|
||||
continue
|
||||
}
|
||||
val key = if (rec.visibility == Visibility.Private || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
if (res.containsKey(key)) continue
|
||||
res[key] = MethodSlot(idx, rec)
|
||||
idx += 1
|
||||
}
|
||||
cls.classScope?.objects?.forEach { (name, rec) ->
|
||||
if (rec.isAbstract) return@forEach
|
||||
if (rec.value !is Statement &&
|
||||
rec.type != ObjRecord.Type.Delegated &&
|
||||
rec.type != ObjRecord.Type.Property) return@forEach
|
||||
val key = if (rec.visibility == Visibility.Private || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
if (res.containsKey(key)) return@forEach
|
||||
res[key] = MethodSlot(idx, rec)
|
||||
idx += 1
|
||||
}
|
||||
}
|
||||
methodSlotMap = res
|
||||
methodSlotCount = idx
|
||||
methodSlotLayoutVersion = layoutVersion
|
||||
return methodSlotMap
|
||||
}
|
||||
|
||||
internal fun fieldSlotCount(): Int {
|
||||
ensureFieldSlots()
|
||||
return fieldSlotCount
|
||||
}
|
||||
|
||||
internal fun fieldSlotForKey(key: String): FieldSlot? {
|
||||
ensureFieldSlots()
|
||||
return fieldSlotMap[key]
|
||||
}
|
||||
|
||||
internal fun fieldSlotMap(): Map<String, FieldSlot> = ensureFieldSlots()
|
||||
internal fun resolveInstanceMember(name: String): ResolvedMember? = ensureInstanceMemberCache()[name]
|
||||
internal fun methodSlotCount(): Int {
|
||||
ensureMethodSlots()
|
||||
return methodSlotCount
|
||||
}
|
||||
internal fun methodSlotForKey(key: String): MethodSlot? {
|
||||
ensureMethodSlots()
|
||||
return methodSlotMap[key]
|
||||
}
|
||||
internal fun methodSlotMap(): Map<String, MethodSlot> = ensureMethodSlots()
|
||||
|
||||
override fun toString(): String = className
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int = if (other === this) 0 else -1
|
||||
@ -396,8 +284,8 @@ open class ObjClass(
|
||||
for (cls in mro) {
|
||||
// 1) members-defined methods and fields
|
||||
for ((k, v) in cls.members) {
|
||||
if (!v.isAbstract && (v.value is Statement || v.type == ObjRecord.Type.Delegated || v.type == ObjRecord.Type.Field || v.type == ObjRecord.Type.ConstructorField)) {
|
||||
val key = if (v.visibility == Visibility.Private || v.type == ObjRecord.Type.Field || v.type == ObjRecord.Type.ConstructorField || v.type == ObjRecord.Type.Delegated) cls.mangledName(k) else k
|
||||
if (!v.isAbstract && (v.value is Statement || v.type == ObjRecord.Type.Delegated || v.type == ObjRecord.Type.Field)) {
|
||||
val key = if (v.visibility == Visibility.Private || v.type == ObjRecord.Type.Field || v.type == ObjRecord.Type.Delegated) cls.mangledName(k) else k
|
||||
if (!res.containsKey(key)) {
|
||||
res[key] = v
|
||||
}
|
||||
@ -439,47 +327,12 @@ open class ObjClass(
|
||||
val stableParent = classScope ?: scope.parent
|
||||
instance.instanceScope = Scope(stableParent, scope.args, scope.pos, instance)
|
||||
instance.instanceScope.currentClassCtx = null
|
||||
val fieldSlots = fieldSlotMap()
|
||||
if (fieldSlots.isNotEmpty()) {
|
||||
instance.initFieldSlots(fieldSlotCount())
|
||||
}
|
||||
val methodSlots = methodSlotMap()
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
instance.initMethodSlots(methodSlotCount())
|
||||
}
|
||||
// Expose instance methods (and other callable members) directly in the instance scope for fast lookup
|
||||
// This mirrors Obj.autoInstanceScope behavior for ad-hoc scopes and makes fb.method() resolution robust
|
||||
|
||||
instance.instanceScope.objects.putAll(templateMethods)
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
for ((key, rec) in templateMethods) {
|
||||
val slot = methodSlots[key]
|
||||
if (slot != null) {
|
||||
instance.setMethodSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (p in templateOthers) {
|
||||
val rec = p.second.copy()
|
||||
instance.instanceScope.objects[p.first] = rec
|
||||
val slot = fieldSlots[p.first]
|
||||
if (slot != null) {
|
||||
instance.setFieldSlotRecord(slot.slot, rec)
|
||||
}
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
val mSlot = methodSlots[p.first]
|
||||
if (mSlot != null) {
|
||||
instance.setMethodSlotRecord(mSlot.slot, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
for ((_, mSlot) in methodSlots) {
|
||||
val idx = mSlot.slot
|
||||
if (idx >= 0 && idx < instance.methodSlots.size && instance.methodSlots[idx] == null) {
|
||||
instance.setMethodSlotRecord(idx, mSlot.record)
|
||||
}
|
||||
}
|
||||
instance.instanceScope.objects[p.first] = p.second.copy()
|
||||
}
|
||||
return instance
|
||||
}
|
||||
@ -564,10 +417,6 @@ open class ObjClass(
|
||||
if (rec != null) {
|
||||
val mangled = c.mangledName(p.name)
|
||||
instance.instanceScope.objects[mangled] = rec
|
||||
val slot = instance.objClass.fieldSlotForKey(mangled)
|
||||
if (slot != null) {
|
||||
instance.setFieldSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -889,3 +738,5 @@ open class ObjClass(
|
||||
scope.raiseNotImplemented()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -30,36 +30,6 @@ import net.sergeych.lynon.LynonType
|
||||
class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
|
||||
internal lateinit var instanceScope: Scope
|
||||
internal var fieldSlots: Array<ObjRecord?> = emptyArray()
|
||||
internal var methodSlots: Array<ObjRecord?> = emptyArray()
|
||||
|
||||
internal fun initFieldSlots(size: Int) {
|
||||
fieldSlots = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
internal fun setFieldSlotRecord(slot: Int, rec: ObjRecord) {
|
||||
if (slot >= 0 && slot < fieldSlots.size) fieldSlots[slot] = rec
|
||||
}
|
||||
|
||||
internal fun initMethodSlots(size: Int) {
|
||||
methodSlots = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
internal fun setMethodSlotRecord(slot: Int, rec: ObjRecord) {
|
||||
if (slot >= 0 && slot < methodSlots.size) methodSlots[slot] = rec
|
||||
}
|
||||
|
||||
internal fun fieldRecordForKey(key: String): ObjRecord? {
|
||||
val slot = objClass.fieldSlotForKey(key) ?: return null
|
||||
val idx = slot.slot
|
||||
return if (idx >= 0 && idx < fieldSlots.size) fieldSlots[idx] else null
|
||||
}
|
||||
|
||||
internal fun methodRecordForKey(key: String): ObjRecord? {
|
||||
val slot = objClass.methodSlotForKey(key) ?: return null
|
||||
val idx = slot.slot
|
||||
return if (idx >= 0 && idx < methodSlots.size) methodSlots[idx] else null
|
||||
}
|
||||
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
val caller = scope.currentClassCtx
|
||||
@ -67,16 +37,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// Fast path for public members when outside any class context
|
||||
if (caller == null) {
|
||||
objClass.publicMemberResolution[name]?.let { key ->
|
||||
fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name) ?: objClass
|
||||
return resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
instanceScope.objects[key]?.let { rec ->
|
||||
// Directly return fields to bypass resolveRecord overhead
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
@ -96,16 +56,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
// Check for private fields (stored in instanceScope)
|
||||
val mangled = c.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return resolveRecord(scope, rec, name, c)
|
||||
@ -117,16 +67,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
for (cls in objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val mangled = cls.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
@ -141,12 +81,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
methodRecordForKey(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.visibility, decl, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fall back to super (handles class members and extensions)
|
||||
return super.readField(scope, name)
|
||||
@ -175,15 +109,10 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
val d = decl ?: obj.declaringClass
|
||||
if (d != null) {
|
||||
val mangled = d.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let {
|
||||
targetRec = it
|
||||
}
|
||||
if (targetRec === obj) {
|
||||
instanceScope.objects[mangled]?.let {
|
||||
targetRec = it
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetRec === obj) {
|
||||
instanceScope.objects[name]?.let { rec ->
|
||||
// Check if this record in instanceScope is the one we want.
|
||||
@ -205,29 +134,10 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// Fast path for public members when outside any class context
|
||||
if (caller == null) {
|
||||
objClass.publicMemberResolution[name]?.let { key ->
|
||||
fieldRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public) {
|
||||
// Skip property/delegated overhead if it's a plain mutable field
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && rec.isMutable && !rec.isAbstract) {
|
||||
if (rec.value.assign(scope, newValue) == null)
|
||||
rec.value = newValue
|
||||
return
|
||||
}
|
||||
updateRecord(scope, rec, name, newValue, rec.declaringClass)
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, rec.declaringClass)
|
||||
return
|
||||
}
|
||||
}
|
||||
instanceScope.objects[key]?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public) {
|
||||
// Skip property/delegated overhead if it's a plain mutable field
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && rec.isMutable && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Field && rec.isMutable && !rec.isAbstract) {
|
||||
if (rec.value.assign(scope, newValue) == null)
|
||||
rec.value = newValue
|
||||
return
|
||||
@ -250,19 +160,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
// Check for private fields (stored in instanceScope)
|
||||
val mangled = c.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
updateRecord(scope, rec, name, newValue, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
updateRecord(scope, rec, name, newValue, c)
|
||||
@ -275,19 +172,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
for (cls in objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val mangled = cls.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name) &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
return
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
@ -304,14 +188,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name) &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
super.writeField(scope, name, newValue)
|
||||
}
|
||||
@ -349,16 +225,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// Fast path for public members when outside any class context
|
||||
if (caller == null) {
|
||||
objClass.publicMemberResolution[name]?.let { key ->
|
||||
methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
instanceScope.objects[key]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass
|
||||
@ -375,15 +241,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// 0. Prefer private member of current class context
|
||||
caller?.let { c ->
|
||||
val mangled = c.mangledName(name)
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, c)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
@ -404,23 +261,13 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
}
|
||||
|
||||
// Fast path for non-delegated instance methods in class context
|
||||
methodRecordForKey(name)?.let { rec ->
|
||||
if (!rec.isAbstract && rec.type == ObjRecord.Type.Fun) {
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name) ?: objClass
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === this) objClass else null
|
||||
if (canAccessMember(rec.visibility, decl, effectiveCaller, name)) {
|
||||
return rec.value.invoke(instanceScope, this, args, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Resolve instance member via cached MRO lookup, handling delegation
|
||||
objClass.resolveInstanceMember(name)?.let { resolvedMember ->
|
||||
val rec = resolvedMember.record
|
||||
val decl = resolvedMember.declaringClass
|
||||
// 1. Walk MRO to find member, handling delegation
|
||||
for (cls in objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||
if (rec != null && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val storageName = decl.mangledName(name)
|
||||
val storageName = cls.mangledName(name)
|
||||
val del = instanceScope[storageName]?.delegate ?: rec.delegate
|
||||
?: scope.raiseError("Internal error: delegated member $name has no delegate (tried $storageName)")
|
||||
|
||||
@ -429,9 +276,10 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs), onNotFoundResult = {
|
||||
// Fallback: property delegation (getValue then call result)
|
||||
val propVal = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
propVal.invoke(scope, this, args, rec.declaringClass ?: decl)
|
||||
propVal.invoke(scope, this, args, rec.declaringClass ?: cls)
|
||||
})
|
||||
}
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === this) objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(
|
||||
@ -455,6 +303,7 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return resolved.value.invoke(scope, this, args, resolved.declaringClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fall back to super (handles extensions and root fallback)
|
||||
return super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
@ -582,14 +431,6 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
// Qualified field access: prefer mangled storage for the qualified ancestor
|
||||
val mangled = "${startClass.className}::$name"
|
||||
instance.fieldRecordForKey(mangled)?.let { rec ->
|
||||
// Visibility: declaring class is the qualified ancestor for mangled storage
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access field $name (declared in ${decl.className})"))
|
||||
return instance.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
instance.instanceScope.objects[mangled]?.let { rec ->
|
||||
// Visibility: declaring class is the qualified ancestor for mangled storage
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
@ -626,18 +467,6 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
||||
// Qualified write: target mangled storage for the ancestor
|
||||
val mangled = "${startClass.className}::$name"
|
||||
instance.fieldRecordForKey(mangled)?.let { f ->
|
||||
val decl = f.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't assign to field $name (declared in ${decl.className})"
|
||||
).raise()
|
||||
if (!f.isMutable && f.value !== ObjUnset) ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
if (f.value.assign(scope, newValue) == null) f.value = newValue
|
||||
return
|
||||
}
|
||||
instance.instanceScope.objects[mangled]?.let { f ->
|
||||
val decl = f.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
|
||||
@ -381,7 +381,7 @@ class CastRef(
|
||||
}
|
||||
|
||||
/** Qualified `this@Type`: resolves to a view of current `this` starting dispatch from the ancestor Type. */
|
||||
class QualifiedThisRef(val typeName: String, private val atPos: Pos) : ObjRef {
|
||||
class QualifiedThisRef(private val typeName: String, private val atPos: Pos) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
val t = scope[typeName]?.value as? ObjClass
|
||||
?: scope.raiseError("unknown type $typeName")
|
||||
@ -403,188 +403,6 @@ class QualifiedThisRef(val typeName: String, private val atPos: Pos) : ObjRef {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun resolveQualifiedThisInstance(scope: Scope, typeName: String): Pair<ObjInstance, ObjClass> {
|
||||
val t = scope[typeName]?.value as? ObjClass
|
||||
?: scope.raiseError("unknown type $typeName")
|
||||
var s: Scope? = scope
|
||||
while (s != null) {
|
||||
val inst = s.thisObj as? ObjInstance
|
||||
if (inst != null && (inst.objClass === t || inst.objClass.allParentsSet.contains(t))) {
|
||||
return inst to t
|
||||
}
|
||||
s = s.parent
|
||||
}
|
||||
scope.raiseClassCastError(
|
||||
"No instance of type ${t.className} found in the scope chain"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this@Type.name` access using slot maps when possible.
|
||||
*/
|
||||
class QualifiedThisFieldSlotRef(
|
||||
private val typeName: String,
|
||||
val name: String,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
val (inst, startClass) = resolveQualifiedThisInstance(scope, typeName)
|
||||
if (isOptional && inst == ObjNull) return ObjNull.asMutable
|
||||
|
||||
if (startClass !== inst.objClass) {
|
||||
return ObjQualifiedView(inst, startClass).readField(scope, name)
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
inst.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return inst.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
inst.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return inst.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = inst.objClass.publicMemberResolution[name] ?: name
|
||||
inst.fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
inst.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: inst.objClass.findDeclaringClassOf(name) ?: inst.objClass
|
||||
return inst.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
|
||||
return inst.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
val (inst, startClass) = resolveQualifiedThisInstance(scope, typeName)
|
||||
if (isOptional && inst == ObjNull) return
|
||||
|
||||
if (startClass !== inst.objClass) {
|
||||
ObjQualifiedView(inst, startClass).writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
inst.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
writeDirectOrFallback(scope, inst, rec, name, newValue, caller)
|
||||
return
|
||||
}
|
||||
}
|
||||
inst.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
inst.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = inst.objClass.publicMemberResolution[name] ?: name
|
||||
inst.fieldRecordForKey(key)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: inst.objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
writeDirectOrFallback(scope, inst, rec, name, newValue, decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
inst.methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
inst.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
inst.writeField(scope, name, newValue)
|
||||
}
|
||||
|
||||
private suspend fun writeDirectOrFallback(
|
||||
scope: Scope,
|
||||
inst: ObjInstance,
|
||||
rec: ObjRecord,
|
||||
name: String,
|
||||
newValue: Obj,
|
||||
decl: ObjClass?
|
||||
) {
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
if (!rec.isMutable && rec.value !== ObjUnset) {
|
||||
ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
}
|
||||
if (rec.value.assign(scope, newValue) == null) rec.value = newValue
|
||||
} else {
|
||||
inst.writeField(scope, name, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this@Type.method(...)` calls using slots when the qualifier is the
|
||||
* dynamic class. Otherwise falls back to a qualified view dispatch.
|
||||
*/
|
||||
class QualifiedThisMethodSlotCallRef(
|
||||
private val typeName: String,
|
||||
private val name: String,
|
||||
private val args: List<ParsedArgument>,
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
val (inst, startClass) = resolveQualifiedThisInstance(scope, typeName)
|
||||
if (isOptional && inst == ObjNull) return ObjNull
|
||||
val callArgs = args.toArguments(scope, tailBlock)
|
||||
|
||||
if (startClass !== inst.objClass) {
|
||||
return ObjQualifiedView(inst, startClass).invokeInstanceMethod(scope, name, callArgs, null)
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
inst.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, inst, caller)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(inst.instanceScope, inst, callArgs, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = inst.objClass.publicMemberResolution[name] ?: name
|
||||
inst.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: inst.objClass.findDeclaringClassOf(name) ?: inst.objClass
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === inst) inst.objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method $name (declared in ${decl.className})"))
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, inst, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(inst.instanceScope, inst, callArgs, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inst.invokeInstanceMethod(scope, name, callArgs)
|
||||
}
|
||||
}
|
||||
|
||||
/** Assignment compound op: target op= value */
|
||||
class AssignOpRef(
|
||||
private val op: BinOp,
|
||||
@ -873,20 +691,9 @@ class FieldRef(
|
||||
if (effectiveKey != null) {
|
||||
rKey1 = key; rVer1 = ver; rGetter1 = { obj, sc ->
|
||||
if (obj is ObjInstance && obj.objClass === cls) {
|
||||
val slot = cls.fieldSlotForKey(effectiveKey)
|
||||
if (slot != null) {
|
||||
val idx = slot.slot
|
||||
val rec = if (idx >= 0 && idx < obj.fieldSlots.size) obj.fieldSlots[idx] else null
|
||||
if (rec != null &&
|
||||
(rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) &&
|
||||
!rec.isAbstract) {
|
||||
rec
|
||||
} else obj.readField(sc, name)
|
||||
} else {
|
||||
val rec = obj.fieldRecordForKey(effectiveKey) ?: obj.instanceScope.objects[effectiveKey]
|
||||
val rec = obj.instanceScope.objects[effectiveKey]
|
||||
if (rec != null && rec.type != ObjRecord.Type.Delegated) rec
|
||||
else obj.readField(sc, name)
|
||||
}
|
||||
} else obj.readField(sc, name)
|
||||
}
|
||||
} else {
|
||||
@ -1002,24 +809,10 @@ class FieldRef(
|
||||
if (effectiveKey != null) {
|
||||
wKey1 = key; wVer1 = ver; wSetter1 = { obj, sc, nv ->
|
||||
if (obj is ObjInstance && obj.objClass === cls) {
|
||||
val slot = cls.fieldSlotForKey(effectiveKey)
|
||||
if (slot != null) {
|
||||
val idx = slot.slot
|
||||
val rec = if (idx >= 0 && idx < obj.fieldSlots.size) obj.fieldSlots[idx] else null
|
||||
if (rec != null &&
|
||||
rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
rec.isMutable &&
|
||||
(rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) &&
|
||||
!rec.isAbstract) {
|
||||
val rec = obj.instanceScope.objects[effectiveKey]
|
||||
if (rec != null && rec.effectiveWriteVisibility == Visibility.Public && rec.isMutable && rec.type == ObjRecord.Type.Field) {
|
||||
if (rec.value.assign(sc, nv) == null) rec.value = nv
|
||||
} else obj.writeField(sc, name, nv)
|
||||
} else {
|
||||
val rec = obj.fieldRecordForKey(effectiveKey) ?: obj.instanceScope.objects[effectiveKey]
|
||||
if (rec != null && rec.effectiveWriteVisibility == Visibility.Public && rec.isMutable &&
|
||||
(rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField)) {
|
||||
if (rec.value.assign(sc, nv) == null) rec.value = nv
|
||||
} else obj.writeField(sc, name, nv)
|
||||
}
|
||||
} else obj.writeField(sc, name, nv)
|
||||
}
|
||||
} else {
|
||||
@ -1097,113 +890,6 @@ class FieldRef(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this.name` access using slot maps.
|
||||
* Falls back to normal member resolution when needed.
|
||||
*/
|
||||
class ThisFieldSlotRef(
|
||||
val name: String,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
val th = scope.thisObj
|
||||
if (th == ObjNull && isOptional) return ObjNull.asMutable
|
||||
if (th !is ObjInstance) return th.readField(scope, name)
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
th.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name) ?: th.objClass
|
||||
return th.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
|
||||
return th.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
val th = scope.thisObj
|
||||
if (th == ObjNull && isOptional) return
|
||||
if (th !is ObjInstance) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
th.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
writeDirectOrFallback(scope, th, rec, name, newValue, caller)
|
||||
return
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
writeDirectOrFallback(scope, th, rec, name, newValue, decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
th.writeField(scope, name, newValue)
|
||||
}
|
||||
|
||||
private suspend fun writeDirectOrFallback(
|
||||
scope: Scope,
|
||||
inst: ObjInstance,
|
||||
rec: ObjRecord,
|
||||
name: String,
|
||||
newValue: Obj,
|
||||
decl: ObjClass?
|
||||
) {
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
if (!rec.isMutable && rec.value !== ObjUnset) {
|
||||
ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
}
|
||||
if (rec.value.assign(scope, newValue) == null) rec.value = newValue
|
||||
} else {
|
||||
inst.writeField(scope, name, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to index access (a[i]) with optional chaining.
|
||||
*/
|
||||
@ -1650,51 +1336,37 @@ class MethodCallRef(
|
||||
is ObjInstance -> {
|
||||
// Prefer resolved class member to avoid per-call lookup on hit
|
||||
// BUT only if it's NOT a root object member (which can be shadowed by extensions)
|
||||
var hierarchyMember: ObjRecord? = null
|
||||
val cls0 = base.objClass
|
||||
val keyInScope = cls0.publicMemberResolution[name]
|
||||
val methodSlot = if (keyInScope != null) cls0.methodSlotForKey(keyInScope) else null
|
||||
val fastRec = if (methodSlot != null) {
|
||||
val idx = methodSlot.slot
|
||||
if (idx >= 0 && idx < base.methodSlots.size) base.methodSlots[idx] else null
|
||||
} else if (keyInScope != null) {
|
||||
base.methodRecordForKey(keyInScope) ?: base.instanceScope.objects[keyInScope]
|
||||
} else null
|
||||
val resolved = if (fastRec != null) null else cls0.resolveInstanceMember(name)
|
||||
if (keyInScope != null) {
|
||||
val rec = base.instanceScope.objects[keyInScope]
|
||||
if (rec != null && rec.type == ObjRecord.Type.Fun) {
|
||||
hierarchyMember = rec
|
||||
}
|
||||
}
|
||||
|
||||
val targetRec = when {
|
||||
fastRec != null && fastRec.type == ObjRecord.Type.Fun -> fastRec
|
||||
resolved != null && resolved.record.type == ObjRecord.Type.Fun && !resolved.record.isAbstract -> resolved.record
|
||||
else -> null
|
||||
}
|
||||
if (targetRec != null) {
|
||||
val visibility = targetRec.visibility
|
||||
val decl = targetRec.declaringClass ?: (resolved?.declaringClass ?: cls0)
|
||||
if (methodSlot != null && targetRec.type == ObjRecord.Type.Fun) {
|
||||
val slotIndex = methodSlot.slot
|
||||
mKey1 = key; mVer1 = ver; mInvoker1 = { obj, sc, a ->
|
||||
val inst = obj as ObjInstance
|
||||
if (inst.objClass === cls0) {
|
||||
val rec = if (slotIndex >= 0 && slotIndex < inst.methodSlots.size) inst.methodSlots[slotIndex] else null
|
||||
if (rec != null && rec.type == ObjRecord.Type.Fun && !rec.isAbstract) {
|
||||
if (!visibility.isPublic && !canAccessMember(visibility, decl, sc.currentClassCtx, name))
|
||||
sc.raiseError(ObjIllegalAccessException(sc, "can't invoke non-public method $name"))
|
||||
rec.value.invoke(inst.instanceScope, inst, a, decl)
|
||||
} else {
|
||||
obj.invokeInstanceMethod(sc, name, a)
|
||||
}
|
||||
} else {
|
||||
obj.invokeInstanceMethod(sc, name, a)
|
||||
if (hierarchyMember == null) {
|
||||
for (cls in base.objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||
if (rec != null && !rec.isAbstract && rec.type != ObjRecord.Type.Field) {
|
||||
hierarchyMember = rec
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val callable = targetRec.value
|
||||
}
|
||||
|
||||
if (hierarchyMember != null) {
|
||||
val visibility = hierarchyMember.visibility
|
||||
val callable = hierarchyMember.value
|
||||
val decl = hierarchyMember.declaringClass ?: base.objClass
|
||||
mKey1 = key; mVer1 = ver; mInvoker1 = { obj, sc, a ->
|
||||
val inst = obj as ObjInstance
|
||||
if (!visibility.isPublic && !canAccessMember(visibility, decl, sc.currentClassCtx, name))
|
||||
sc.raiseError(ObjIllegalAccessException(sc, "can't invoke non-public method $name"))
|
||||
callable.invoke(inst.instanceScope, inst, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to name-based lookup per call (handles extensions and root members)
|
||||
mKey1 = key; mVer1 = ver; mInvoker1 = { obj, sc, a -> obj.invokeInstanceMethod(sc, name, a) }
|
||||
@ -1727,57 +1399,6 @@ class MethodCallRef(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this.method(...)` calls using slot maps.
|
||||
* Falls back to normal invoke semantics when needed.
|
||||
*/
|
||||
class ThisMethodSlotCallRef(
|
||||
private val name: String,
|
||||
private val args: List<ParsedArgument>,
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
val base = scope.thisObj
|
||||
if (base == ObjNull && isOptional) return ObjNull
|
||||
val callArgs = args.toArguments(scope, tailBlock)
|
||||
if (base !is ObjInstance) return base.invokeInstanceMethod(scope, name, callArgs)
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
base.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, base, caller)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(base.instanceScope, base, callArgs, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = base.objClass.publicMemberResolution[name] ?: name
|
||||
base.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: base.objClass.findDeclaringClassOf(name) ?: base.objClass
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === base) base.objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method $name (declared in ${decl.className})"))
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, base, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(base.instanceScope, base, callArgs, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.invokeInstanceMethod(scope, name, callArgs)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to a local/visible variable by name (Phase A: scope lookup).
|
||||
*/
|
||||
@ -2108,240 +1729,6 @@ class FastLocalVarRef(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier reference in class context that prefers member slots on `this` after local lookup.
|
||||
* Falls back to normal scope lookup for globals/outer scopes.
|
||||
*/
|
||||
class ImplicitThisMemberRef(
|
||||
val name: String,
|
||||
val atPos: Pos
|
||||
) : ObjRef {
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
block(name)
|
||||
}
|
||||
|
||||
override fun forEachVariableWithPos(block: (String, Pos) -> Unit) {
|
||||
block(name, atPos)
|
||||
}
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
scope.pos = atPos
|
||||
val caller = scope.currentClassCtx
|
||||
val th = scope.thisObj
|
||||
|
||||
// 1) locals in the same `this` chain
|
||||
var s: Scope? = scope
|
||||
while (s != null && s.thisObj === th) {
|
||||
scope.tryGetLocalRecord(s, name, caller)?.let { return it }
|
||||
s = s.parent
|
||||
}
|
||||
|
||||
// 2) member slots on this instance
|
||||
if (th is ObjInstance) {
|
||||
// private member access for current class context
|
||||
caller?.let { c ->
|
||||
val mangled = c.mangledName(name)
|
||||
th.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name) ?: th.objClass
|
||||
return th.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3) fallback to normal scope resolution (globals/outer scopes)
|
||||
scope[name]?.let { return it }
|
||||
try {
|
||||
return th.readField(scope, name)
|
||||
} catch (e: ExecutionError) {
|
||||
if ((e.message ?: "").contains("no such field: $name")) scope.raiseSymbolNotFound(name)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
val rec = get(scope)
|
||||
return scope.resolve(rec, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
scope.pos = atPos
|
||||
val caller = scope.currentClassCtx
|
||||
val th = scope.thisObj
|
||||
|
||||
// 1) locals in the same `this` chain
|
||||
var s: Scope? = scope
|
||||
while (s != null && s.thisObj === th) {
|
||||
val rec = scope.tryGetLocalRecord(s, name, caller)
|
||||
if (rec != null) {
|
||||
scope.assign(rec, name, newValue)
|
||||
return
|
||||
}
|
||||
s = s.parent
|
||||
}
|
||||
|
||||
// 2) member slots on this instance
|
||||
if (th is ObjInstance) {
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
if (!rec.isMutable && rec.value !== ObjUnset) {
|
||||
ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
}
|
||||
if (rec.value.assign(scope, newValue) == null) rec.value = newValue
|
||||
} else {
|
||||
th.writeField(scope, name, newValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3) fallback to normal scope resolution
|
||||
scope[name]?.let { stored ->
|
||||
scope.assign(stored, name, newValue)
|
||||
return
|
||||
}
|
||||
th.writeField(scope, name, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for implicit member calls in class bodies: `foo(...)` resolves locals first,
|
||||
* then falls back to member lookup on `this`.
|
||||
*/
|
||||
class ImplicitThisMethodCallRef(
|
||||
private val name: String,
|
||||
private val args: List<ParsedArgument>,
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean,
|
||||
private val atPos: Pos
|
||||
) : ObjRef {
|
||||
private val memberRef = ImplicitThisMemberRef(name, atPos)
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
scope.pos = atPos
|
||||
val callee = memberRef.evalValue(scope)
|
||||
if (callee == ObjNull && isOptional) return ObjNull
|
||||
val callArgs = args.toArguments(scope, tailBlock)
|
||||
val usePool = PerfFlags.SCOPE_POOL
|
||||
return if (usePool) {
|
||||
scope.withChildFrame(callArgs) { child ->
|
||||
callee.callOn(child)
|
||||
}
|
||||
} else {
|
||||
callee.callOn(scope.createChildScope(scope.pos, callArgs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct local slot reference with known slot index and lexical depth.
|
||||
* Depth=0 means current scope, depth=1 means parent scope, etc.
|
||||
*/
|
||||
class LocalSlotRef(
|
||||
val name: String,
|
||||
private val slot: Int,
|
||||
private val depth: Int,
|
||||
private val atPos: Pos,
|
||||
) : ObjRef {
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
block(name)
|
||||
}
|
||||
|
||||
private val fallbackRef = LocalVarRef(name, atPos)
|
||||
private var cachedFrameId: Long = 0L
|
||||
private var cachedOwner: Scope? = null
|
||||
private var cachedOwnerVerified: Boolean = false
|
||||
|
||||
private fun resolveOwner(scope: Scope): Scope? {
|
||||
if (cachedOwner != null && cachedFrameId == scope.frameId && cachedOwnerVerified) return cachedOwner
|
||||
var s: Scope? = scope
|
||||
var remaining = depth
|
||||
while (s != null && remaining > 0) {
|
||||
s = s.parent
|
||||
remaining--
|
||||
}
|
||||
if (s == null || s.getSlotIndexOf(name) != slot) {
|
||||
cachedOwner = null
|
||||
cachedOwnerVerified = false
|
||||
cachedFrameId = scope.frameId
|
||||
return null
|
||||
}
|
||||
cachedOwner = s
|
||||
cachedOwnerVerified = true
|
||||
cachedFrameId = scope.frameId
|
||||
return s
|
||||
}
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
scope.pos = atPos
|
||||
val owner = resolveOwner(scope) ?: return fallbackRef.get(scope)
|
||||
if (slot < 0 || slot >= owner.slotCount()) return fallbackRef.get(scope)
|
||||
val rec = owner.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||
}
|
||||
return rec
|
||||
}
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
scope.pos = atPos
|
||||
val owner = resolveOwner(scope) ?: return fallbackRef.evalValue(scope)
|
||||
if (slot < 0 || slot >= owner.slotCount()) return fallbackRef.evalValue(scope)
|
||||
val rec = owner.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||
}
|
||||
return scope.resolve(rec, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
scope.pos = atPos
|
||||
val owner = resolveOwner(scope) ?: run {
|
||||
fallbackRef.setAt(pos, scope, newValue)
|
||||
return
|
||||
}
|
||||
if (slot < 0 || slot >= owner.slotCount()) {
|
||||
fallbackRef.setAt(pos, scope, newValue)
|
||||
return
|
||||
}
|
||||
val rec = owner.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||
}
|
||||
scope.assign(rec, name, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
for (e in entries) {
|
||||
@ -2523,15 +1910,7 @@ class AssignRef(
|
||||
val v = value.evalValue(scope)
|
||||
// For properties, we should not call get() on target because it invokes the getter.
|
||||
// Instead, we call setAt directly.
|
||||
if (target is FieldRef ||
|
||||
target is IndexRef ||
|
||||
target is LocalVarRef ||
|
||||
target is FastLocalVarRef ||
|
||||
target is BoundLocalVarRef ||
|
||||
target is LocalSlotRef ||
|
||||
target is ThisFieldSlotRef ||
|
||||
target is QualifiedThisFieldSlotRef ||
|
||||
target is ImplicitThisMemberRef) {
|
||||
if (target is FieldRef || target is IndexRef || target is LocalVarRef || target is FastLocalVarRef || target is BoundLocalVarRef) {
|
||||
target.setAt(atPos, scope, v)
|
||||
} else {
|
||||
val rec = target.get(scope)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user