fixed errors
This commit is contained in:
parent
aeeec2d417
commit
6eabcc315f
@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
version = "0.10.3-SNAPSHOT"
|
version = "0.11.1-SNAPSHOT"
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
@ -30,10 +30,11 @@ class ClosureScope(val callScope: Scope, val closureScope: Scope) :
|
|||||||
Scope(callScope, callScope.args, thisObj = closureScope.thisObj) {
|
Scope(callScope, callScope.args, thisObj = closureScope.thisObj) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Preserve the lexical class context from where the lambda was defined (closure),
|
// Preserve the lexical class context of the closure by default. This ensures that lambdas
|
||||||
// so that visibility checks (private/protected) inside lambdas executed within other
|
// created inside a class method keep access to that class's private/protected members even
|
||||||
// methods (e.g., Mutex.withLock) still see the original declaring class context.
|
// when executed from within another object's method (e.g., Mutex.withLock), which may set
|
||||||
this.currentClassCtx = closureScope.currentClassCtx
|
// its own currentClassCtx temporarily. If the closure has no class context, inherit caller's.
|
||||||
|
this.currentClassCtx = closureScope.currentClassCtx ?: callScope.currentClassCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(name: String): ObjRecord? {
|
override fun get(name: String): ObjRecord? {
|
||||||
|
|||||||
@ -224,8 +224,19 @@ class Compiler(
|
|||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
val opToken = cc.next()
|
val opToken = cc.next()
|
||||||
val op = byLevel[level][opToken.type]
|
val op = byLevel[level][opToken.type]
|
||||||
if (op == null) {
|
if (op == null) {
|
||||||
|
// handle ternary conditional at the top precedence level only: a ? b : c
|
||||||
|
if (opToken.type == Token.Type.QUESTION && level == 0) {
|
||||||
|
val thenRef = parseExpressionLevel(level + 1)
|
||||||
|
?: throw ScriptError(opToken.pos, "Expecting expression after '?'")
|
||||||
|
val colon = cc.next()
|
||||||
|
if (colon.type != Token.Type.COLON) colon.raiseSyntax("missing ':'")
|
||||||
|
val elseRef = parseExpressionLevel(level + 1)
|
||||||
|
?: throw ScriptError(colon.pos, "Expecting expression after ':'")
|
||||||
|
lvalue = ConditionalRef(lvalue!!, thenRef, elseRef)
|
||||||
|
continue
|
||||||
|
}
|
||||||
cc.previous()
|
cc.previous()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,10 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
|||||||
val size by byteArray::size
|
val size by byteArray::size
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return byteArray.hashCode()
|
// On some platforms (notably JS), UByteArray.hashCode() is not content-based.
|
||||||
|
// For map/set keys we must ensure hash is consistent with equals(contentEquals).
|
||||||
|
// Convert to ByteArray and use contentHashCode() which is value-based and stable.
|
||||||
|
return byteArray.asByteArray().contentHashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||||
|
|||||||
@ -32,9 +32,15 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
// Direct (unmangled) lookup first
|
// Direct (unmangled) lookup first
|
||||||
instanceScope[name]?.let {
|
instanceScope[name]?.let {
|
||||||
val decl = it.declaringClass ?: objClass.findDeclaringClassOf(name)
|
val decl = it.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||||
val caller = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
// When execution passes through suspension points (e.g., withLock),
|
||||||
val allowed = if (it.visibility == net.sergeych.lyng.Visibility.Private) (decl === objClass) else canAccessMember(it.visibility, decl, caller)
|
// currentClassCtx could be lost. Fall back to the instance scope class ctx
|
||||||
if (!allowed)
|
// to preserve correct visibility semantics for private/protected members
|
||||||
|
// accessed from within the class methods.
|
||||||
|
// Allow unconditional access when accessing through `this` of the same instance
|
||||||
|
if (scope.thisObj === this) return it
|
||||||
|
val caller0 = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
||||||
|
val caller = caller0 // do not default to objClass for outsiders
|
||||||
|
if (!canAccessMember(it.visibility, decl, caller))
|
||||||
scope.raiseError(ObjAccessException(scope, "can't access field $name (declared in ${decl?.className ?: "?"})"))
|
scope.raiseError(ObjAccessException(scope, "can't access field $name (declared in ${decl?.className ?: "?"})"))
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
@ -51,15 +57,15 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
findMangled()?.let { rec ->
|
findMangled()?.let { rec ->
|
||||||
val declName = rec.importedFrom?.packageName // unused; use mangled key instead
|
|
||||||
// derive declaring class by mangled prefix: try self then parents
|
// derive declaring class by mangled prefix: try self then parents
|
||||||
val declaring = when {
|
val declaring = when {
|
||||||
instanceScope.objects.containsKey("${cls.className}::$name") -> cls
|
instanceScope.objects.containsKey("${cls.className}::$name") -> cls
|
||||||
else -> cls.mroParents.firstOrNull { instanceScope.objects.containsKey("${it.className}::$name") }
|
else -> cls.mroParents.firstOrNull { instanceScope.objects.containsKey("${it.className}::$name") }
|
||||||
}
|
}
|
||||||
val caller = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
if (scope.thisObj === this) return rec
|
||||||
val allowed = if (rec.visibility == net.sergeych.lyng.Visibility.Private) (declaring === objClass) else canAccessMember(rec.visibility, declaring, caller)
|
val caller0 = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
||||||
if (!allowed)
|
val caller = caller0 // do not default to objClass for outsiders
|
||||||
|
if (!canAccessMember(rec.visibility, declaring, caller))
|
||||||
scope.raiseError(ObjAccessException(scope, "can't access field $name (declared in ${declaring?.className ?: "?"})"))
|
scope.raiseError(ObjAccessException(scope, "can't access field $name (declared in ${declaring?.className ?: "?"})"))
|
||||||
return rec
|
return rec
|
||||||
}
|
}
|
||||||
@ -71,10 +77,14 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
// Direct (unmangled) first
|
// Direct (unmangled) first
|
||||||
instanceScope[name]?.let { f ->
|
instanceScope[name]?.let { f ->
|
||||||
val decl = f.declaringClass ?: objClass.findDeclaringClassOf(name)
|
val decl = f.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||||
val caller = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
if (scope.thisObj === this) {
|
||||||
val allowed = if (f.visibility == net.sergeych.lyng.Visibility.Private) (decl === objClass) else canAccessMember(f.visibility, decl, caller)
|
// direct self-assignment allowed; enforce mutability below
|
||||||
if (!allowed)
|
} else {
|
||||||
ObjIllegalAssignmentException(scope, "can't assign to field $name (declared in ${decl?.className ?: "?"})").raise()
|
val caller0 = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
||||||
|
val caller = caller0 // do not default to objClass for outsiders
|
||||||
|
if (!canAccessMember(f.visibility, decl, caller))
|
||||||
|
ObjIllegalAssignmentException(scope, "can't assign to field $name (declared in ${decl?.className ?: "?"})").raise()
|
||||||
|
}
|
||||||
if (!f.isMutable) ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
if (!f.isMutable) ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||||
if (f.value.assign(scope, newValue) == null)
|
if (f.value.assign(scope, newValue) == null)
|
||||||
f.value = newValue
|
f.value = newValue
|
||||||
@ -95,10 +105,12 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
instanceScope.objects.containsKey("${cls.className}::$name") -> cls
|
instanceScope.objects.containsKey("${cls.className}::$name") -> cls
|
||||||
else -> cls.mroParents.firstOrNull { instanceScope.objects.containsKey("${it.className}::$name") }
|
else -> cls.mroParents.firstOrNull { instanceScope.objects.containsKey("${it.className}::$name") }
|
||||||
}
|
}
|
||||||
val caller = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
if (scope.thisObj !== this) {
|
||||||
val allowed = if (rec.visibility == net.sergeych.lyng.Visibility.Private) (declaring === objClass) else canAccessMember(rec.visibility, declaring, caller)
|
val caller0 = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
||||||
if (!allowed)
|
val caller = caller0 // do not default to objClass for outsiders
|
||||||
ObjIllegalAssignmentException(scope, "can't assign to field $name (declared in ${declaring?.className ?: "?"})").raise()
|
if (!canAccessMember(rec.visibility, declaring, caller))
|
||||||
|
ObjIllegalAssignmentException(scope, "can't assign to field $name (declared in ${declaring?.className ?: "?"})").raise()
|
||||||
|
}
|
||||||
if (!rec.isMutable) ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
if (!rec.isMutable) ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||||
if (rec.value.assign(scope, newValue) == null)
|
if (rec.value.assign(scope, newValue) == null)
|
||||||
rec.value = newValue
|
rec.value = newValue
|
||||||
@ -111,9 +123,9 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
onNotFoundResult: (()->Obj?)?): Obj =
|
onNotFoundResult: (()->Obj?)?): Obj =
|
||||||
instanceScope[name]?.let { rec ->
|
instanceScope[name]?.let { rec ->
|
||||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||||
val caller = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
val caller0 = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
||||||
val allowed = if (rec.visibility == net.sergeych.lyng.Visibility.Private) (decl === objClass) else canAccessMember(rec.visibility, decl, caller)
|
val caller = caller0 ?: if (scope.thisObj === this) objClass else null
|
||||||
if (!allowed)
|
if (!canAccessMember(rec.visibility, decl, caller))
|
||||||
scope.raiseError(ObjAccessException(scope, "can't invoke method $name (declared in ${decl?.className ?: "?"})"))
|
scope.raiseError(ObjAccessException(scope, "can't invoke method $name (declared in ${decl?.className ?: "?"})"))
|
||||||
// execute with lexical class context propagated to declaring class
|
// execute with lexical class context propagated to declaring class
|
||||||
val saved = instanceScope.currentClassCtx
|
val saved = instanceScope.currentClassCtx
|
||||||
@ -131,7 +143,8 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
// fallback: class-scope function (registered during class body execution)
|
// fallback: class-scope function (registered during class body execution)
|
||||||
objClass.classScope?.objects?.get(name)?.let { rec ->
|
objClass.classScope?.objects?.get(name)?.let { rec ->
|
||||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||||
val caller = scope.currentClassCtx
|
val caller0 = scope.currentClassCtx ?: instanceScope.currentClassCtx
|
||||||
|
val caller = caller0 ?: if (scope.thisObj === this) objClass else null
|
||||||
if (!canAccessMember(rec.visibility, decl, caller))
|
if (!canAccessMember(rec.visibility, decl, caller))
|
||||||
scope.raiseError(ObjAccessException(scope, "can't invoke method $name (declared in ${decl?.className ?: "?"})"))
|
scope.raiseError(ObjAccessException(scope, "can't invoke method $name (declared in ${decl?.className ?: "?"})"))
|
||||||
val saved = instanceScope.currentClassCtx
|
val saved = instanceScope.currentClassCtx
|
||||||
|
|||||||
@ -253,6 +253,24 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Conditional (ternary) operator reference: cond ? a : b */
|
||||||
|
class ConditionalRef(
|
||||||
|
private val condition: ObjRef,
|
||||||
|
private val ifTrue: ObjRef,
|
||||||
|
private val ifFalse: ObjRef
|
||||||
|
) : ObjRef {
|
||||||
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
|
val condVal = if (net.sergeych.lyng.PerfFlags.RVAL_FASTPATH) condition.evalValue(scope) else condition.get(scope).value
|
||||||
|
val condTrue = when (condVal) {
|
||||||
|
is ObjBool -> condVal.value
|
||||||
|
is ObjInt -> condVal.value != 0L
|
||||||
|
else -> condVal.toBool()
|
||||||
|
}
|
||||||
|
val branch = if (condTrue) ifTrue else ifFalse
|
||||||
|
return branch.get(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Cast operator reference: left `as` rightType or `as?` (nullable). */
|
/** Cast operator reference: left `as` rightType or `as?` (nullable). */
|
||||||
class CastRef(
|
class CastRef(
|
||||||
private val valueRef: ObjRef,
|
private val valueRef: ObjRef,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user