Compare commits

...

8 Commits

2 changed files with 24 additions and 6 deletions

View File

@ -516,6 +516,23 @@ open class Scope(
open fun applyClosure(closure: Scope): Scope = ClosureScope(this, closure)
/**
* Resolve and evaluate a qualified identifier exactly as compiled code would.
* For input like `A.B.C`, it builds the same ObjRef chain the compiler emits:
* `LocalVarRef("A", Pos.builtIn)` followed by `FieldRef` for each segment, then evaluates it.
* This mirrors `eval("A.B.C")` resolution semantics without invoking the compiler.
*/
suspend fun resolveQualifiedIdentifier(qualifiedName: String): Obj {
val trimmed = qualifiedName.trim()
if (trimmed.isEmpty()) raiseSymbolNotFound("empty identifier")
val parts = trimmed.split('.')
var ref: ObjRef = LocalVarRef(parts[0], Pos.builtIn)
for (i in 1 until parts.size) {
ref = FieldRef(ref, parts[i], false)
}
return ref.evalValue(this)
}
companion object {
fun new(): Scope =

View File

@ -83,15 +83,16 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe
scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}")
it
} ?: run {
val fallback = runCatching { scope.eval(className.value) }.getOrNull()
if (fallback != null) {
println("Fallback to eval successful")
fallback as ObjClass
}
else scope.raiseSymbolNotFound("can't deserialize: not found type $className")
// Use Scope API that mirrors compiler-emitted ObjRef chain for qualified identifiers
val evaluated = scope.resolveQualifiedIdentifier(className.value)
if (evaluated !is ObjClass)
scope.raiseClassCastError("Expected obj class but got ${evaluated::class.simpleName}")
evaluated
}
}
// helper moved to Scope as resolveQualifiedIdentifier
suspend fun decodeAnyList(scope: Scope, fixedSize: Int? = null): MutableList<Obj> {
return if (bin.getBit() == 1) {
// homogenous