Implement qualified cast views for MI
This commit is contained in:
1 parent
308a9c0bcb
commit
43a6a7aaf4
28 files changed
+400
-341
No files matched your search
@@ -21,6 +21,7 @@ import net.sergeych.lyng.obj.Obj
|
||||
class ClassDeclStatement(
|
||||
private val delegate: Statement,
|
||||
private val startPos: Pos,
|
||||
val declaredName: String?,
|
||||
) : Statement() {
|
||||
override val pos: Pos = startPos
|
||||
|
||||
|
||||
@@ -145,6 +145,10 @@ class Compiler(
|
||||
if (!record.visibility.isPublic) continue
|
||||
if (plan.slots.containsKey(name)) continue
|
||||
declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated)
|
||||
val instance = record.value as? ObjInstance
|
||||
if (instance != null && nameObjClass[name] == null) {
|
||||
nameObjClass[name] = instance.objClass
|
||||
}
|
||||
}
|
||||
for ((cls, map) in current.extensions) {
|
||||
for ((name, record) in map) {
|
||||
@@ -457,6 +461,13 @@ class Compiler(
|
||||
return MemberIds(fieldId, methodId)
|
||||
}
|
||||
if (qualifier != null) {
|
||||
val classCtx = codeContexts.asReversed()
|
||||
.firstOrNull { it is CodeContext.ClassBody && it.name == qualifier } as? CodeContext.ClassBody
|
||||
if (classCtx != null) {
|
||||
val fieldId = classCtx.memberFieldIds[name]
|
||||
val methodId = classCtx.memberMethodIds[name]
|
||||
if (fieldId != null || methodId != null) return MemberIds(fieldId, methodId)
|
||||
}
|
||||
val info = resolveCompileClassInfo(qualifier)
|
||||
?: if (allowUnresolvedRefs) return MemberIds(null, null) else throw ScriptError(pos, "unknown type $qualifier")
|
||||
val fieldId = info.fieldIds[name]
|
||||
@@ -630,6 +641,14 @@ class Compiler(
|
||||
val ids = resolveMemberIds(name, pos, null)
|
||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, currentImplicitThisTypeName())
|
||||
}
|
||||
if (classCtx != null) {
|
||||
val implicitType = classCtx.name
|
||||
if (hasImplicitThisMember(name, implicitType)) {
|
||||
resolutionSink?.referenceMember(name, pos, implicitType)
|
||||
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
|
||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
|
||||
}
|
||||
}
|
||||
val implicitThisMembers = codeContexts.any { ctx ->
|
||||
(ctx as? CodeContext.Function)?.implicitThisMembers == true
|
||||
}
|
||||
@@ -1190,6 +1209,14 @@ class Compiler(
|
||||
|
||||
private fun resolveImplicitThisMemberIds(name: String, pos: Pos, implicitTypeName: String?): MemberIds {
|
||||
if (implicitTypeName == null) return resolveMemberIds(name, pos, null)
|
||||
val classCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
|
||||
if (classCtx != null && classCtx.name == implicitTypeName) {
|
||||
val fieldId = classCtx.memberFieldIds[name]
|
||||
val methodId = classCtx.memberMethodIds[name]
|
||||
if (fieldId != null || methodId != null) {
|
||||
return MemberIds(fieldId, methodId)
|
||||
}
|
||||
}
|
||||
val info = resolveCompileClassInfo(implicitTypeName)
|
||||
val fieldId = info?.fieldIds?.get(name)
|
||||
val methodId = info?.methodIds?.get(name)
|
||||
@@ -1211,6 +1238,12 @@ class Compiler(
|
||||
|
||||
private fun hasImplicitThisMember(name: String, implicitTypeName: String?): Boolean {
|
||||
if (implicitTypeName == null) return false
|
||||
val classCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
|
||||
if (classCtx != null && classCtx.name == implicitTypeName) {
|
||||
if (classCtx.memberFieldIds.containsKey(name) || classCtx.memberMethodIds.containsKey(name)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
val info = resolveCompileClassInfo(implicitTypeName)
|
||||
if (info != null && (info.fieldIds.containsKey(name) || info.methodIds.containsKey(name))) return true
|
||||
val cls = resolveClassByName(implicitTypeName)
|
||||
@@ -1480,7 +1513,11 @@ class Compiler(
|
||||
is ConditionalRef ->
|
||||
containsUnsupportedRef(ref.condition) || containsUnsupportedRef(ref.ifTrue) || containsUnsupportedRef(ref.ifFalse)
|
||||
is ElvisRef -> containsUnsupportedRef(ref.left) || containsUnsupportedRef(ref.right)
|
||||
is FieldRef -> containsUnsupportedRef(ref.target)
|
||||
is FieldRef -> {
|
||||
val receiverClass = resolveReceiverClassForMember(ref.target)
|
||||
if (receiverClass == ObjDynamic.type) return true
|
||||
containsUnsupportedRef(ref.target)
|
||||
}
|
||||
is IndexRef -> containsUnsupportedRef(ref.targetRef) || containsUnsupportedRef(ref.indexRef)
|
||||
is ListLiteralRef -> ref.entries().any {
|
||||
when (it) {
|
||||
@@ -1495,7 +1532,13 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
is CallRef -> containsUnsupportedRef(ref.target) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||
is MethodCallRef -> containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||
is MethodCallRef -> {
|
||||
val receiverClass = resolveReceiverClassForMember(ref.receiver)
|
||||
if (receiverClass == ObjDynamic.type) return true
|
||||
containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||
}
|
||||
is QualifiedThisMethodSlotCallRef -> true
|
||||
is QualifiedThisFieldSlotRef -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -3255,6 +3298,7 @@ class Compiler(
|
||||
|
||||
private fun inferFieldReturnClass(targetClass: ObjClass?, name: String): ObjClass? {
|
||||
if (targetClass == null) return null
|
||||
if (targetClass == ObjDynamic.type) return ObjDynamic.type
|
||||
classFieldTypesByName[targetClass.className]?.get(name)?.let { return it }
|
||||
enumEntriesByName[targetClass.className]?.let { entries ->
|
||||
return when {
|
||||
@@ -4632,7 +4676,7 @@ class Compiler(
|
||||
return instance
|
||||
}
|
||||
}
|
||||
return ClassDeclStatement(declStatement, startPos)
|
||||
return ClassDeclStatement(declStatement, startPos, className)
|
||||
}
|
||||
|
||||
private suspend fun parseClassDeclaration(isAbstract: Boolean = false, isExtern: Boolean = false): Statement {
|
||||
@@ -4691,6 +4735,7 @@ class Compiler(
|
||||
|
||||
val baseSpecs = mutableListOf<BaseSpec>()
|
||||
pendingTypeParamStack.add(classTypeParams)
|
||||
slotPlanStack.add(classSlotPlan)
|
||||
try {
|
||||
if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
|
||||
do {
|
||||
@@ -4710,6 +4755,7 @@ class Compiler(
|
||||
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
||||
}
|
||||
} finally {
|
||||
slotPlanStack.removeLast()
|
||||
pendingTypeParamStack.removeLast()
|
||||
}
|
||||
|
||||
@@ -5016,7 +5062,7 @@ class Compiler(
|
||||
return newClass
|
||||
}
|
||||
}
|
||||
ClassDeclStatement(classDeclStatement, startPos)
|
||||
ClassDeclStatement(classDeclStatement, startPos, nameToken.value)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5397,12 +5443,10 @@ class Compiler(
|
||||
resolutionSink?.declareSymbol(name, declKind, isMutable = false, pos = nameStartPos, isOverride = isOverride)
|
||||
if (parentContext is CodeContext.ClassBody && extTypeName == null) {
|
||||
parentContext.declaredMembers.add(name)
|
||||
if (!isStatic) {
|
||||
if (!parentContext.memberMethodIds.containsKey(name)) {
|
||||
parentContext.memberMethodIds[name] = parentContext.nextMethodId++
|
||||
}
|
||||
memberMethodId = parentContext.memberMethodIds[name]
|
||||
if (!parentContext.memberMethodIds.containsKey(name)) {
|
||||
parentContext.memberMethodIds[name] = parentContext.nextMethodId++
|
||||
}
|
||||
memberMethodId = parentContext.memberMethodIds[name]
|
||||
}
|
||||
if (declKind != SymbolKind.MEMBER) {
|
||||
declareLocalName(name, isMutable = false)
|
||||
@@ -5494,11 +5538,16 @@ class Compiler(
|
||||
|
||||
miniSink?.onEnterFunction(node)
|
||||
val implicitThisMembers = extTypeName != null || (parentContext is CodeContext.ClassBody && !isStatic)
|
||||
val implicitThisTypeName = when {
|
||||
extTypeName != null -> extTypeName
|
||||
parentContext is CodeContext.ClassBody && !isStatic -> parentContext.name
|
||||
else -> null
|
||||
}
|
||||
return inCodeContext(
|
||||
CodeContext.Function(
|
||||
name,
|
||||
implicitThisMembers = implicitThisMembers,
|
||||
implicitThisTypeName = extTypeName,
|
||||
implicitThisTypeName = implicitThisTypeName,
|
||||
typeParams = typeParams,
|
||||
typeParamDecls = typeParamDecls
|
||||
)
|
||||
@@ -5932,7 +5981,7 @@ class Compiler(
|
||||
}
|
||||
val initRef = (initStmt as? ExpressionStatement)?.ref
|
||||
return when (initRef) {
|
||||
is StatementRef -> (initRef.statement as? ExpressionStatement)?.ref
|
||||
is StatementRef -> (initRef.statement as? ExpressionStatement)?.ref ?: initRef
|
||||
else -> initRef
|
||||
}
|
||||
}
|
||||
@@ -5956,11 +6005,18 @@ class Compiler(
|
||||
else -> Obj.rootObjectType
|
||||
}
|
||||
}
|
||||
if (unwrapped is ClassDeclStatement) {
|
||||
unwrapped.declaredName?.let { return resolveClassByName(it) }
|
||||
}
|
||||
val directRef = unwrapDirectRef(unwrapped)
|
||||
return when (directRef) {
|
||||
is ListLiteralRef -> ObjList.type
|
||||
is MapLiteralRef -> ObjMap.type
|
||||
is RangeRef -> ObjRange.type
|
||||
is StatementRef -> {
|
||||
val decl = directRef.statement as? ClassDeclStatement
|
||||
decl?.declaredName?.let { resolveClassByName(it) }
|
||||
}
|
||||
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
|
||||
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
|
||||
is BinaryOpRef -> inferBinaryOpReturnClass(directRef)
|
||||
@@ -5988,6 +6044,9 @@ class Compiler(
|
||||
when (target.name) {
|
||||
"lazy" -> ObjLazyDelegate.type
|
||||
"iterator" -> ObjIterator
|
||||
"flow" -> ObjFlow.type
|
||||
"launch" -> ObjDeferred.type
|
||||
"dynamic" -> ObjDynamic.type
|
||||
else -> callableReturnTypeByScopeId[target.scopeId]?.get(target.slot)
|
||||
?: resolveClassByName(target.name)
|
||||
}
|
||||
@@ -5996,6 +6055,9 @@ class Compiler(
|
||||
when (target.name) {
|
||||
"lazy" -> ObjLazyDelegate.type
|
||||
"iterator" -> ObjIterator
|
||||
"flow" -> ObjFlow.type
|
||||
"launch" -> ObjDeferred.type
|
||||
"dynamic" -> ObjDynamic.type
|
||||
else -> callableReturnTypeByName[target.name]
|
||||
?: resolveClassByName(target.name)
|
||||
}
|
||||
@@ -6489,7 +6551,7 @@ class Compiler(
|
||||
false
|
||||
}
|
||||
|
||||
if (declaringClassNameCaptured != null && extTypeName == null && !isStatic) {
|
||||
if (declaringClassNameCaptured != null && extTypeName == null) {
|
||||
if (isDelegate || isProperty) {
|
||||
if (classCtx != null) {
|
||||
if (!classCtx.memberMethodIds.containsKey(name)) {
|
||||
|
||||
@@ -343,7 +343,7 @@ class Script(
|
||||
result
|
||||
}
|
||||
|
||||
addFn("dynamic") {
|
||||
addFn("dynamic", callSignature = CallSignature(tailBlockReceiverType = "DelegateContext")) {
|
||||
ObjDynamic.create(this, requireOnlyArg())
|
||||
}
|
||||
|
||||
@@ -438,6 +438,8 @@ class Script(
|
||||
addConst("Mutex", ObjMutex.type)
|
||||
addConst("Flow", ObjFlow.type)
|
||||
addConst("FlowBuilder", ObjFlowBuilder.type)
|
||||
addConst("Delegate", ObjDynamic.type)
|
||||
addConst("DelegateContext", ObjDynamicContext.type)
|
||||
|
||||
addConst("Regex", ObjRegex.type)
|
||||
addConst("RegexMatch", ObjRegexMatch.type)
|
||||
|
||||
@@ -512,7 +512,10 @@ class BytecodeCompiler(
|
||||
val typeObj = ensureObjSlot(typeValue)
|
||||
if (!ref.castIsNullable()) {
|
||||
builder.emit(Opcode.ASSERT_IS, objValue.slot, typeObj.slot)
|
||||
return objValue
|
||||
val resultSlot = allocSlot()
|
||||
builder.emit(Opcode.MAKE_QUALIFIED_VIEW, objValue.slot, typeObj.slot, resultSlot)
|
||||
updateSlotType(resultSlot, SlotType.OBJ)
|
||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
||||
}
|
||||
val checkSlot = allocSlot()
|
||||
builder.emit(Opcode.CHECK_IS, objValue.slot, typeObj.slot, checkSlot)
|
||||
@@ -529,7 +532,7 @@ class BytecodeCompiler(
|
||||
builder.emit(Opcode.MOVE_OBJ, nullSlot, resultSlot)
|
||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||
builder.mark(okLabel)
|
||||
builder.emit(Opcode.MOVE_OBJ, objValue.slot, resultSlot)
|
||||
builder.emit(Opcode.MAKE_QUALIFIED_VIEW, objValue.slot, typeObj.slot, resultSlot)
|
||||
builder.mark(endLabel)
|
||||
updateSlotType(resultSlot, SlotType.OBJ)
|
||||
return CompiledValue(resultSlot, SlotType.OBJ)
|
||||
|
||||
@@ -116,7 +116,7 @@ class CmdBuilder {
|
||||
Opcode.NEG_INT, Opcode.NEG_REAL, Opcode.NOT_BOOL, Opcode.INV_INT,
|
||||
Opcode.ASSERT_IS ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.CHECK_IS ->
|
||||
Opcode.CHECK_IS, Opcode.MAKE_QUALIFIED_VIEW ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.RANGE_INT_BOUNDS ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
@@ -225,6 +225,7 @@ class CmdBuilder {
|
||||
Opcode.MAKE_RANGE -> CmdMakeRange(operands[0], operands[1], operands[2], operands[3])
|
||||
Opcode.CHECK_IS -> CmdCheckIs(operands[0], operands[1], operands[2])
|
||||
Opcode.ASSERT_IS -> CmdAssertIs(operands[0], operands[1])
|
||||
Opcode.MAKE_QUALIFIED_VIEW -> CmdMakeQualifiedView(operands[0], operands[1], operands[2])
|
||||
Opcode.RET_LABEL -> CmdRetLabel(operands[0], operands[1])
|
||||
Opcode.THROW -> CmdThrow(operands[0], operands[1])
|
||||
Opcode.RESOLVE_SCOPE_SLOT -> CmdResolveScopeSlot(operands[0], operands[1])
|
||||
|
||||
@@ -74,6 +74,7 @@ object CmdDisassembler {
|
||||
is CmdObjToBool -> Opcode.OBJ_TO_BOOL to intArrayOf(cmd.src, cmd.dst)
|
||||
is CmdCheckIs -> Opcode.CHECK_IS to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
|
||||
is CmdAssertIs -> Opcode.ASSERT_IS to intArrayOf(cmd.objSlot, cmd.typeSlot)
|
||||
is CmdMakeQualifiedView -> Opcode.MAKE_QUALIFIED_VIEW to intArrayOf(cmd.objSlot, cmd.typeSlot, cmd.dst)
|
||||
is CmdRangeIntBounds -> Opcode.RANGE_INT_BOUNDS to intArrayOf(cmd.src, cmd.startSlot, cmd.endSlot, cmd.okSlot)
|
||||
is CmdMakeRange -> Opcode.MAKE_RANGE to intArrayOf(cmd.startSlot, cmd.endSlot, cmd.inclusiveSlot, cmd.dst)
|
||||
is CmdResolveScopeSlot -> Opcode.RESOLVE_SCOPE_SLOT to intArrayOf(cmd.scopeSlot, cmd.addrSlot)
|
||||
@@ -213,7 +214,7 @@ object CmdDisassembler {
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.OBJ_TO_BOOL, Opcode.ASSERT_IS ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.CHECK_IS ->
|
||||
Opcode.CHECK_IS, Opcode.MAKE_QUALIFIED_VIEW ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.RANGE_INT_BOUNDS, Opcode.MAKE_RANGE ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
|
||||
@@ -232,6 +232,31 @@ class CmdAssertIs(internal val objSlot: Int, internal val typeSlot: Int) : Cmd()
|
||||
}
|
||||
}
|
||||
|
||||
class CmdMakeQualifiedView(
|
||||
internal val objSlot: Int,
|
||||
internal val typeSlot: Int,
|
||||
internal val dst: Int,
|
||||
) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
val obj0 = frame.slotToObj(objSlot)
|
||||
val typeObj = frame.slotToObj(typeSlot)
|
||||
val clazz = typeObj as? ObjClass ?: frame.scope.raiseClassCastError(
|
||||
"${typeObj.inspect(frame.scope)} is not the class instance"
|
||||
)
|
||||
val base = when (obj0) {
|
||||
is ObjQualifiedView -> obj0.instance
|
||||
else -> obj0
|
||||
}
|
||||
val result = if (base is ObjInstance && base.isInstanceOf(clazz)) {
|
||||
ObjQualifiedView(base, clazz)
|
||||
} else {
|
||||
base
|
||||
}
|
||||
frame.storeObjResult(dst, result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdRangeIntBounds(
|
||||
internal val src: Int,
|
||||
internal val startSlot: Int,
|
||||
@@ -1243,6 +1268,11 @@ class CmdGetMemberSlot(
|
||||
} else null
|
||||
} ?: frame.scope.raiseSymbolNotFound("member")
|
||||
val name = rec.memberName ?: "<member>"
|
||||
if (receiver is ObjQualifiedView) {
|
||||
val resolved = receiver.readField(frame.scope, name)
|
||||
frame.storeObjResult(dst, resolved.value)
|
||||
return
|
||||
}
|
||||
val resolved = receiver.resolveRecord(frame.scope, rec, name, rec.declaringClass)
|
||||
frame.storeObjResult(dst, resolved.value)
|
||||
return
|
||||
@@ -1267,6 +1297,10 @@ class CmdSetMemberSlot(
|
||||
} else null
|
||||
} ?: frame.scope.raiseSymbolNotFound("member")
|
||||
val name = rec.memberName ?: "<member>"
|
||||
if (receiver is ObjQualifiedView) {
|
||||
receiver.writeField(frame.scope, name, frame.slotToObj(valueSlot))
|
||||
return
|
||||
}
|
||||
frame.scope.assign(rec, name, frame.slotToObj(valueSlot))
|
||||
return
|
||||
}
|
||||
@@ -1290,6 +1324,14 @@ class CmdCallMemberSlot(
|
||||
?: frame.scope.raiseError("member id $methodId not found on ${receiver.objClass.className}")
|
||||
val callArgs = frame.buildArguments(argBase, argCount)
|
||||
val name = rec.memberName ?: "<member>"
|
||||
if (receiver is ObjQualifiedView) {
|
||||
val result = receiver.invokeInstanceMethod(frame.scope, name, callArgs)
|
||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||
frame.syncScopeToFrame()
|
||||
}
|
||||
frame.storeObjResult(dst, result)
|
||||
return
|
||||
}
|
||||
val decl = rec.declaringClass ?: receiver.objClass
|
||||
val result = when (rec.type) {
|
||||
ObjRecord.Type.Property -> {
|
||||
|
||||
@@ -41,6 +41,7 @@ enum class Opcode(val code: Int) {
|
||||
OBJ_TO_BOOL(0x14),
|
||||
CHECK_IS(0x15),
|
||||
ASSERT_IS(0x16),
|
||||
MAKE_QUALIFIED_VIEW(0x17),
|
||||
|
||||
ADD_INT(0x20),
|
||||
SUB_INT(0x21),
|
||||
|
||||
@@ -122,8 +122,12 @@ open class ObjDynamic(var readCallback: Statement? = null, var writeCallback: St
|
||||
}
|
||||
|
||||
val type = object : ObjClass("Delegate") {}.apply {
|
||||
addFn("getValue") { raiseError("Delegate.getValue is not implemented") }
|
||||
addFn("setValue") { raiseError("Delegate.setValue is not implemented") }
|
||||
addFn("invoke") { raiseError("Delegate.invoke is not implemented") }
|
||||
addFn("bind") { raiseError("Delegate.bind is not implemented") }
|
||||
// addClassConst("IndexGetName", operatorGetName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -191,12 +191,12 @@ 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
|
||||
val scoped = instanceScope.objects[mangled]
|
||||
if (scoped != null) {
|
||||
targetRec = scoped
|
||||
} else {
|
||||
fieldRecordForKey(mangled)?.let {
|
||||
targetRec = it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -598,7 +598,7 @@ 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 ->
|
||||
instance.instanceScope.objects[mangled]?.let { rec ->
|
||||
// Visibility: declaring class is the qualified ancestor for mangled storage
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
@@ -606,7 +606,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
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 ->
|
||||
instance.fieldRecordForKey(mangled)?.let { rec ->
|
||||
// Visibility: declaring class is the qualified ancestor for mangled storage
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
@@ -642,7 +642,7 @@ 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 ->
|
||||
instance.instanceScope.objects[mangled]?.let { f ->
|
||||
val decl = f.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
|
||||
@@ -654,7 +654,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
if (f.value.assign(scope, newValue) == null) f.value = newValue
|
||||
return
|
||||
}
|
||||
instance.instanceScope.objects[mangled]?.let { f ->
|
||||
instance.fieldRecordForKey(mangled)?.let { f ->
|
||||
val decl = f.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
|
||||
@@ -705,7 +705,15 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
val saved = instance.instanceScope.currentClassCtx
|
||||
instance.instanceScope.currentClassCtx = decl
|
||||
try {
|
||||
return rec.value.invoke(instance.instanceScope, instance, args)
|
||||
return when (rec.type) {
|
||||
ObjRecord.Type.Property -> {
|
||||
if (args.isEmpty()) (rec.value as ObjProperty).callGetter(scope, instance, decl)
|
||||
else scope.raiseError("property $name cannot be called with arguments")
|
||||
}
|
||||
ObjRecord.Type.Fun, ObjRecord.Type.Delegated ->
|
||||
rec.value.invoke(instance.instanceScope, instance, args)
|
||||
else -> scope.raiseError("member $name is not callable")
|
||||
}
|
||||
} finally {
|
||||
instance.instanceScope.currentClassCtx = saved
|
||||
}
|
||||
|
||||
@@ -522,6 +522,10 @@ class QualifiedThisFieldSlotRef(
|
||||
fieldId?.let { id ->
|
||||
val rec = inst.fieldRecordForId(id)
|
||||
if (rec != null && (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: inst.objClass
|
||||
if (!canAccessMember(rec.visibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access field ${rec.memberName ?: name} (declared in ${decl.className})"))
|
||||
}
|
||||
return rec
|
||||
}
|
||||
}
|
||||
@@ -529,6 +533,9 @@ class QualifiedThisFieldSlotRef(
|
||||
val rec = inst.methodRecordForId(id)
|
||||
if (rec != null && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: inst.objClass
|
||||
if (!canAccessMember(rec.visibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access member ${rec.memberName ?: name} (declared in ${decl.className})"))
|
||||
}
|
||||
return inst.resolveRecord(scope, rec, rec.memberName ?: name, decl)
|
||||
}
|
||||
}
|
||||
@@ -542,6 +549,10 @@ class QualifiedThisFieldSlotRef(
|
||||
fieldId?.let { id ->
|
||||
val rec = inst.fieldRecordForId(id)
|
||||
if (rec != null) {
|
||||
val decl = rec.declaringClass ?: inst.objClass
|
||||
if (!canAccessMember(rec.effectiveWriteVisibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't assign to field ${rec.memberName ?: name} (declared in ${decl.className})"))
|
||||
}
|
||||
assignToRecord(scope, rec, newValue)
|
||||
return
|
||||
}
|
||||
@@ -549,6 +560,10 @@ class QualifiedThisFieldSlotRef(
|
||||
methodId?.let { id ->
|
||||
val rec = inst.methodRecordForId(id)
|
||||
if (rec != null) {
|
||||
val decl = rec.declaringClass ?: inst.objClass
|
||||
if (!canAccessMember(rec.effectiveWriteVisibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't assign to member ${rec.memberName ?: name} (declared in ${decl.className})"))
|
||||
}
|
||||
scope.assign(rec, rec.memberName ?: name, newValue)
|
||||
return
|
||||
}
|
||||
@@ -597,6 +612,9 @@ class QualifiedThisMethodSlotCallRef(
|
||||
val id = methodId ?: scope.raiseSymbolNotFound(name)
|
||||
val rec = inst.methodRecordForId(id) ?: scope.raiseSymbolNotFound(name)
|
||||
val decl = rec.declaringClass ?: inst.objClass
|
||||
if (!canAccessMember(rec.visibility, decl, scope.currentClassCtx, rec.memberName ?: name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method ${rec.memberName ?: name} (declared in ${decl.className})"))
|
||||
}
|
||||
return when (rec.type) {
|
||||
ObjRecord.Type.Property -> {
|
||||
if (callArgs.isEmpty()) (rec.value as ObjProperty).callGetter(scope, inst, decl)
|
||||
|
||||
Reference in new issue
Block a user