Move qualified identifier resolution to Scope as resolveQualifiedIdentifier, replace inline logic in LynonDecoder.
This commit is contained in:
parent
5a8881bfd5
commit
5d8fdce637
@ -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 =
|
||||
|
||||
@ -17,9 +17,10 @@
|
||||
|
||||
package net.sergeych.lynon
|
||||
|
||||
import net.sergeych.lyng.Pos
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.obj.Obj
|
||||
import net.sergeych.lyng.obj.ObjClass
|
||||
import net.sergeych.lyng.obj.ObjString
|
||||
|
||||
open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSettings.default) {
|
||||
|
||||
@ -82,28 +83,15 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe
|
||||
scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}")
|
||||
it
|
||||
} ?: run {
|
||||
// Precisely mimic what `scope.eval(className.value)` would compile and execute for
|
||||
// a simple qualified name: LocalVarRef(head) followed by chained FieldRef segments.
|
||||
val evaluated = evaluateQualifiedNameAsCompiled(scope, className.value)
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// Build and execute the exact ObjRef chain that the compiler would emit for an identifier
|
||||
// with optional dotted selectors, e.g., "A.B.C" -> LocalVarRef("A") -> FieldRef(..., "B") -> FieldRef(..., "C")
|
||||
private suspend fun evaluateQualifiedNameAsCompiled(scope: Scope, name: String): Obj {
|
||||
val trimmed = name.trim()
|
||||
if (trimmed.isEmpty()) scope.raiseSymbolNotFound("empty identifier")
|
||||
val parts = trimmed.split('.')
|
||||
// Use built-in position; eval() would carry a Source position, which does not affect resolution semantics here
|
||||
var ref: ObjRef = LocalVarRef(parts[0], Pos.builtIn)
|
||||
for (i in 1 until parts.size) {
|
||||
ref = FieldRef(ref, parts[i], false)
|
||||
}
|
||||
return ref.evalValue(scope)
|
||||
}
|
||||
// helper moved to Scope as resolveQualifiedIdentifier
|
||||
|
||||
suspend fun decodeAnyList(scope: Scope, fixedSize: Int? = null): MutableList<Obj> {
|
||||
return if (bin.getBit() == 1) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user