fix wasmJs suspend-lambda generation and add agent guidance
This commit is contained in:
parent
717a79aca2
commit
062f9e7866
8
AGENTS.md
Normal file
8
AGENTS.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# AI Agent Notes
|
||||||
|
|
||||||
|
## Kotlin/Wasm generation guardrails
|
||||||
|
- Avoid creating suspend lambdas for compiler runtime statements. Prefer explicit `object : Statement()` with `override suspend fun execute(...)`.
|
||||||
|
- Do not use `statement { ... }` or other inline suspend lambdas in compiler hot paths (e.g., parsing/var declarations, initializer thunks).
|
||||||
|
- If you need a wrapper for delegated properties, check for `getValue` explicitly and return a concrete `Statement` object when missing; avoid `onNotFoundResult` lambdas.
|
||||||
|
- If wasmJs browser tests hang, first run `:lynglib:wasmJsNodeTest` and look for wasm compilation errors; hangs usually mean module instantiation failed.
|
||||||
|
- Do not increase test timeouts to mask wasm generation errors; fix the invalid IR instead.
|
||||||
@ -45,6 +45,7 @@ fun swapEnds(first, args..., last, f) {
|
|||||||
- [Samples directory](docs/samples)
|
- [Samples directory](docs/samples)
|
||||||
- [Formatter (core + CLI + IDE)](docs/formatter.md)
|
- [Formatter (core + CLI + IDE)](docs/formatter.md)
|
||||||
- [Books directory](docs)
|
- [Books directory](docs)
|
||||||
|
- [AI agent guidance](AGENTS.md)
|
||||||
|
|
||||||
## Integration in Kotlin multiplatform
|
## Integration in Kotlin multiplatform
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -70,9 +70,8 @@ open class Scope(
|
|||||||
|
|
||||||
internal fun findExtension(receiverClass: ObjClass, name: String): ObjRecord? {
|
internal fun findExtension(receiverClass: ObjClass, name: String): ObjRecord? {
|
||||||
var s: Scope? = this
|
var s: Scope? = this
|
||||||
val visited = HashSet<Long>(4)
|
var hops = 0
|
||||||
while (s != null) {
|
while (s != null && hops++ < 1024) {
|
||||||
if (!visited.add(s.frameId)) break
|
|
||||||
// Proximity rule: check all extensions in the current scope before going to parent.
|
// Proximity rule: check all extensions in the current scope before going to parent.
|
||||||
// Priority within scope: more specific class in MRO wins.
|
// Priority within scope: more specific class in MRO wins.
|
||||||
for (cls in receiverClass.mro) {
|
for (cls in receiverClass.mro) {
|
||||||
@ -106,28 +105,38 @@ open class Scope(
|
|||||||
* intertwined closure frames. They traverse the plain parent chain and consult only locals
|
* intertwined closure frames. They traverse the plain parent chain and consult only locals
|
||||||
* and bindings of each frame. Instance/class member fallback must be decided by the caller.
|
* and bindings of each frame. Instance/class member fallback must be decided by the caller.
|
||||||
*/
|
*/
|
||||||
private fun tryGetLocalRecord(s: Scope, name: String, caller: net.sergeych.lyng.obj.ObjClass?): ObjRecord? {
|
internal fun tryGetLocalRecord(s: Scope, name: String, caller: net.sergeych.lyng.obj.ObjClass?): ObjRecord? {
|
||||||
|
caller?.let { ctx ->
|
||||||
|
s.objects[ctx.mangledName(name)]?.let { rec ->
|
||||||
|
if (rec.visibility == Visibility.Private) return rec
|
||||||
|
}
|
||||||
|
}
|
||||||
s.objects[name]?.let { rec ->
|
s.objects[name]?.let { rec ->
|
||||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller, name)) return rec
|
||||||
|
}
|
||||||
|
caller?.let { ctx ->
|
||||||
|
s.localBindings[ctx.mangledName(name)]?.let { rec ->
|
||||||
|
if (rec.visibility == Visibility.Private) return rec
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.localBindings[name]?.let { rec ->
|
s.localBindings[name]?.let { rec ->
|
||||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller, name)) return rec
|
||||||
}
|
}
|
||||||
s.getSlotIndexOf(name)?.let { idx ->
|
s.getSlotIndexOf(name)?.let { idx ->
|
||||||
val rec = s.getSlotRecord(idx)
|
val rec = s.getSlotRecord(idx)
|
||||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller, name)) return rec
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun chainLookupIgnoreClosure(name: String): ObjRecord? {
|
internal fun chainLookupIgnoreClosure(name: String, followClosure: Boolean = false, caller: net.sergeych.lyng.obj.ObjClass? = null): ObjRecord? {
|
||||||
var s: Scope? = this
|
var s: Scope? = this
|
||||||
// use frameId to detect unexpected structural cycles in the parent chain
|
// use hop counter to detect unexpected structural cycles in the parent chain
|
||||||
val visited = HashSet<Long>(4)
|
var hops = 0
|
||||||
while (s != null) {
|
val effectiveCaller = caller ?: currentClassCtx
|
||||||
if (!visited.add(s.frameId)) return null
|
while (s != null && hops++ < 1024) {
|
||||||
tryGetLocalRecord(s, name, currentClassCtx)?.let { return it }
|
tryGetLocalRecord(s, name, effectiveCaller)?.let { return it }
|
||||||
s = s.parent
|
s = if (followClosure && s is ClosureScope) s.closureScope else s.parent
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -144,9 +153,8 @@ open class Scope(
|
|||||||
tryGetLocalRecord(this, name, currentClassCtx)?.let { return it }
|
tryGetLocalRecord(this, name, currentClassCtx)?.let { return it }
|
||||||
// 2) walk parents for plain locals/bindings only
|
// 2) walk parents for plain locals/bindings only
|
||||||
var s = parent
|
var s = parent
|
||||||
val visited = HashSet<Long>(4)
|
var hops = 0
|
||||||
while (s != null) {
|
while (s != null && hops++ < 1024) {
|
||||||
if (!visited.add(s.frameId)) return null
|
|
||||||
tryGetLocalRecord(s, name, currentClassCtx)?.let { return it }
|
tryGetLocalRecord(s, name, currentClassCtx)?.let { return it }
|
||||||
s = s.parent
|
s = s.parent
|
||||||
}
|
}
|
||||||
@ -155,7 +163,7 @@ open class Scope(
|
|||||||
this.extensions[cls]?.get(name)?.let { return it }
|
this.extensions[cls]?.get(name)?.let { return it }
|
||||||
}
|
}
|
||||||
return thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
return thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
||||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) {
|
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx, name)) {
|
||||||
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) null
|
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) null
|
||||||
else rec
|
else rec
|
||||||
} else null
|
} else null
|
||||||
@ -169,23 +177,22 @@ open class Scope(
|
|||||||
* This completely avoids invoking overridden `get` implementations, preventing
|
* This completely avoids invoking overridden `get` implementations, preventing
|
||||||
* ping-pong recursion between `ClosureScope` frames.
|
* ping-pong recursion between `ClosureScope` frames.
|
||||||
*/
|
*/
|
||||||
internal fun chainLookupWithMembers(name: String, caller: net.sergeych.lyng.obj.ObjClass? = currentClassCtx): ObjRecord? {
|
internal fun chainLookupWithMembers(name: String, caller: net.sergeych.lyng.obj.ObjClass? = currentClassCtx, followClosure: Boolean = false): ObjRecord? {
|
||||||
var s: Scope? = this
|
var s: Scope? = this
|
||||||
val visited = HashSet<Long>(4)
|
var hops = 0
|
||||||
while (s != null) {
|
while (s != null && hops++ < 1024) {
|
||||||
if (!visited.add(s.frameId)) return null
|
|
||||||
tryGetLocalRecord(s, name, caller)?.let { return it }
|
tryGetLocalRecord(s, name, caller)?.let { return it }
|
||||||
for (cls in s.thisObj.objClass.mro) {
|
for (cls in s.thisObj.objClass.mro) {
|
||||||
s.extensions[cls]?.get(name)?.let { return it }
|
s.extensions[cls]?.get(name)?.let { return it }
|
||||||
}
|
}
|
||||||
s.thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
s.thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
||||||
if (canAccessMember(rec.visibility, rec.declaringClass, caller)) {
|
if (canAccessMember(rec.visibility, rec.declaringClass, caller, name)) {
|
||||||
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) {
|
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) {
|
||||||
// ignore fields, properties and abstracts here, they will be handled by the caller via readField
|
// ignore fields, properties and abstracts here, they will be handled by the caller via readField
|
||||||
} else return rec
|
} else return rec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = s.parent
|
s = if (followClosure && s is ClosureScope) s.closureScope else s.parent
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -277,16 +284,22 @@ open class Scope(
|
|||||||
raiseError(ObjSymbolNotDefinedException(this, "symbol is not defined: $name"))
|
raiseError(ObjSymbolNotDefinedException(this, "symbol is not defined: $name"))
|
||||||
|
|
||||||
fun raiseError(message: String): Nothing {
|
fun raiseError(message: String): Nothing {
|
||||||
throw ExecutionError(ObjException(this, message))
|
val ex = ObjException(this, message)
|
||||||
|
throw ExecutionError(ex, pos, ex.message.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun raiseError(obj: ObjException): Nothing {
|
fun raiseError(obj: ObjException): Nothing {
|
||||||
throw ExecutionError(obj)
|
throw ExecutionError(obj, obj.scope.pos, obj.message.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun raiseError(obj: Obj, pos: Pos, message: String): Nothing {
|
||||||
|
throw ExecutionError(obj, pos, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun raiseNotFound(message: String = "not found"): Nothing {
|
fun raiseNotFound(message: String = "not found"): Nothing {
|
||||||
throw ExecutionError(ObjNotFoundException(this, message))
|
val ex = ObjNotFoundException(this, message)
|
||||||
|
throw ExecutionError(ex, ex.scope.pos, ex.message.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Obj> requiredArg(index: Int): T {
|
inline fun <reified T : Obj> requiredArg(index: Int): T {
|
||||||
@ -314,37 +327,51 @@ open class Scope(
|
|||||||
|
|
||||||
inline fun <reified T : Obj> thisAs(): T {
|
inline fun <reified T : Obj> thisAs(): T {
|
||||||
var s: Scope? = this
|
var s: Scope? = this
|
||||||
do {
|
while (s != null) {
|
||||||
val t = s!!.thisObj
|
val t = s.thisObj
|
||||||
if (t is T) return t
|
if (t is T) return t
|
||||||
s = s.parent
|
s = s.parent
|
||||||
} while (s != null)
|
}
|
||||||
raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val objects = mutableMapOf<String, ObjRecord>()
|
internal val objects = mutableMapOf<String, ObjRecord>()
|
||||||
|
|
||||||
open operator fun get(name: String): ObjRecord? =
|
open operator fun get(name: String): ObjRecord? {
|
||||||
if (name == "this") thisObj.asReadonly
|
if (name == "this") return thisObj.asReadonly
|
||||||
else {
|
|
||||||
// Prefer direct locals/bindings declared in this frame
|
// 1. Prefer direct locals/bindings declared in this frame
|
||||||
(objects[name]?.let { rec ->
|
tryGetLocalRecord(this, name, currentClassCtx)?.let { return it }
|
||||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) rec else null
|
|
||||||
|
val p = parent
|
||||||
|
|
||||||
|
// 2. If we share thisObj with parent, delegate to parent to maintain
|
||||||
|
// "locals shadow members" priority across the this-context.
|
||||||
|
if (p != null && p.thisObj === thisObj) {
|
||||||
|
return p.get(name)
|
||||||
}
|
}
|
||||||
// Then, check known local bindings in this frame (helps after suspension)
|
|
||||||
?: localBindings[name]?.let { rec ->
|
// 3. Otherwise, we are the "primary" scope for this thisObj (or have no parent),
|
||||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) rec else null
|
// so check members of thisObj before walking up to a different this-context.
|
||||||
|
val receiver = thisObj
|
||||||
|
val effectiveClass = receiver as? ObjClass ?: receiver.objClass
|
||||||
|
for (cls in effectiveClass.mro) {
|
||||||
|
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||||
|
if (rec != null && !rec.isAbstract) {
|
||||||
|
if (canAccessMember(rec.visibility, rec.declaringClass ?: cls, currentClassCtx, name)) {
|
||||||
|
return rec.copy(receiver = receiver)
|
||||||
}
|
}
|
||||||
// Walk up ancestry
|
|
||||||
?: parent?.get(name)
|
|
||||||
// Finally, fallback to class members on thisObj
|
|
||||||
?: thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
|
||||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) {
|
|
||||||
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) null
|
|
||||||
else rec
|
|
||||||
} else null
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
// Finally, root object fallback
|
||||||
|
Obj.rootObjectType.members[name]?.let { rec ->
|
||||||
|
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx, name)) {
|
||||||
|
return rec.copy(receiver = receiver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Finally, walk up ancestry to a scope with a different thisObj context
|
||||||
|
return p?.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slot fast-path API
|
// Slot fast-path API
|
||||||
@ -365,6 +392,20 @@ open class Scope(
|
|||||||
nameToSlot[name]?.let { slots[it] = record }
|
nameToSlot[name]?.let { slots[it] = record }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all references and maps to prevent memory leaks when pooled.
|
||||||
|
*/
|
||||||
|
fun scrub() {
|
||||||
|
this.parent = null
|
||||||
|
this.skipScopeCreation = false
|
||||||
|
this.currentClassCtx = null
|
||||||
|
objects.clear()
|
||||||
|
slots.clear()
|
||||||
|
nameToSlot.clear()
|
||||||
|
localBindings.clear()
|
||||||
|
extensions.clear()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset this scope instance so it can be safely reused as a fresh child frame.
|
* Reset this scope instance so it can be safely reused as a fresh child frame.
|
||||||
* Clears locals and slots, assigns new frameId, and sets parent/args/pos/thisObj.
|
* Clears locals and slots, assigns new frameId, and sets parent/args/pos/thisObj.
|
||||||
@ -374,6 +415,7 @@ open class Scope(
|
|||||||
// that could interact badly with the new parent and produce a cycle.
|
// that could interact badly with the new parent and produce a cycle.
|
||||||
this.parent = null
|
this.parent = null
|
||||||
this.skipScopeCreation = false
|
this.skipScopeCreation = false
|
||||||
|
this.currentClassCtx = parent?.currentClassCtx
|
||||||
// fresh identity for PIC caches
|
// fresh identity for PIC caches
|
||||||
this.frameId = nextFrameId()
|
this.frameId = nextFrameId()
|
||||||
// clear locals and slot maps
|
// clear locals and slot maps
|
||||||
@ -474,7 +516,8 @@ open class Scope(
|
|||||||
declaringClass: net.sergeych.lyng.obj.ObjClass? = currentClassCtx,
|
declaringClass: net.sergeych.lyng.obj.ObjClass? = currentClassCtx,
|
||||||
isAbstract: Boolean = false,
|
isAbstract: Boolean = false,
|
||||||
isClosed: Boolean = false,
|
isClosed: Boolean = false,
|
||||||
isOverride: Boolean = false
|
isOverride: Boolean = false,
|
||||||
|
isTransient: Boolean = false
|
||||||
): ObjRecord {
|
): ObjRecord {
|
||||||
val rec = ObjRecord(
|
val rec = ObjRecord(
|
||||||
value, isMutable, visibility, writeVisibility,
|
value, isMutable, visibility, writeVisibility,
|
||||||
@ -482,7 +525,8 @@ open class Scope(
|
|||||||
type = recordType,
|
type = recordType,
|
||||||
isAbstract = isAbstract,
|
isAbstract = isAbstract,
|
||||||
isClosed = isClosed,
|
isClosed = isClosed,
|
||||||
isOverride = isOverride
|
isOverride = isOverride,
|
||||||
|
isTransient = isTransient
|
||||||
)
|
)
|
||||||
objects[name] = rec
|
objects[name] = rec
|
||||||
// Index this binding within the current frame to help resolve locals across suspension
|
// Index this binding within the current frame to help resolve locals across suspension
|
||||||
@ -501,12 +545,16 @@ open class Scope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Map to a slot for fast local access (ensure consistency)
|
// Map to a slot for fast local access (ensure consistency)
|
||||||
val idx = getSlotIndexOf(name)
|
if (nameToSlot.isEmpty()) {
|
||||||
|
allocateSlotFor(name, rec)
|
||||||
|
} else {
|
||||||
|
val idx = nameToSlot[name]
|
||||||
if (idx == null) {
|
if (idx == null) {
|
||||||
allocateSlotFor(name, rec)
|
allocateSlotFor(name, rec)
|
||||||
} else {
|
} else {
|
||||||
slots[idx] = rec
|
slots[idx] = rec
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return rec
|
return rec
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,31 +670,34 @@ open class Scope(
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun resolve(rec: ObjRecord, name: String): Obj {
|
suspend fun resolve(rec: ObjRecord, name: String): Obj {
|
||||||
if (rec.type == ObjRecord.Type.Delegated) {
|
val receiver = rec.receiver ?: thisObj
|
||||||
val del = rec.delegate ?: raiseError("Internal error: delegated property $name has no delegate")
|
return receiver.resolveRecord(this, rec, name, rec.declaringClass).value
|
||||||
val th = if (thisObj === ObjVoid) ObjNull else thisObj
|
|
||||||
if (del.objClass.getInstanceMemberOrNull("getValue") == null) {
|
|
||||||
return object : Statement() {
|
|
||||||
override val pos: Pos = Pos.builtIn
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
|
||||||
val th2 = if (scope.thisObj === ObjVoid) ObjNull else scope.thisObj
|
|
||||||
val allArgs = (listOf(th2, ObjString(name)) + scope.args.list).toTypedArray()
|
|
||||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return del.invokeInstanceMethod(this, "getValue", Arguments(th, ObjString(name)))
|
|
||||||
}
|
|
||||||
return rec.value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun assign(rec: ObjRecord, name: String, newValue: Obj) {
|
suspend fun assign(rec: ObjRecord, name: String, newValue: Obj) {
|
||||||
if (rec.type == ObjRecord.Type.Delegated) {
|
if (rec.type == ObjRecord.Type.Delegated) {
|
||||||
val del = rec.delegate ?: raiseError("Internal error: delegated property $name has no delegate")
|
val receiver = rec.receiver ?: thisObj
|
||||||
val th = if (thisObj === ObjVoid) ObjNull else thisObj
|
val del = rec.delegate ?: run {
|
||||||
|
if (receiver is ObjInstance) {
|
||||||
|
(receiver as ObjInstance).writeField(this, name, newValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
raiseError("Internal error: delegated property $name has no delegate")
|
||||||
|
}
|
||||||
|
val th = if (receiver === ObjVoid) ObjNull else receiver
|
||||||
del.invokeInstanceMethod(this, "setValue", Arguments(th, ObjString(name), newValue))
|
del.invokeInstanceMethod(this, "setValue", Arguments(th, ObjString(name), newValue))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (rec.value is ObjProperty) {
|
||||||
|
(rec.value as ObjProperty).callSetter(this, rec.receiver ?: thisObj, newValue, rec.declaringClass)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// If it's a member (explicitly tracked by receiver or declaringClass), use writeField.
|
||||||
|
// Important: locals have receiver == null and declaringClass == null (enforced in addItem).
|
||||||
|
if (rec.receiver != null || (rec.declaringClass != null && (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property))) {
|
||||||
|
(rec.receiver ?: thisObj).writeField(this, name, newValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!rec.isMutable && rec.value !== ObjUnset) raiseIllegalAssignment("can't reassign val $name")
|
if (!rec.isMutable && rec.value !== ObjUnset) raiseIllegalAssignment("can't reassign val $name")
|
||||||
rec.value = newValue
|
rec.value = newValue
|
||||||
}
|
}
|
||||||
|
|||||||
@ -609,17 +609,16 @@ open class Obj {
|
|||||||
scope.raiseNotImplemented()
|
scope.raiseNotImplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj {
|
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj =
|
||||||
if (PerfFlags.SCOPE_POOL) {
|
if (PerfFlags.SCOPE_POOL)
|
||||||
return scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
||||||
if (declaringClass != null) child.currentClassCtx = declaringClass
|
if (declaringClass != null) child.currentClassCtx = declaringClass
|
||||||
callOn(child)
|
callOn(child)
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
val child = scope.createChildScope(scope.pos, args = args, newThisObj = thisObj)
|
callOn(scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
||||||
if (declaringClass != null) child.currentClassCtx = declaringClass
|
if (declaringClass != null) it.currentClassCtx = declaringClass
|
||||||
return callOn(child)
|
})
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
||||||
callOn(
|
callOn(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user