better scopeFacade
This commit is contained in:
parent
d82302dd01
commit
66d9a40bb1
@ -114,6 +114,17 @@ scope.eval("val y = inc(41); log('Answer:', y)")
|
|||||||
|
|
||||||
You can register multiple names (aliases) at once: `addFn<ObjInt>("inc", "increment") { ... }`.
|
You can register multiple names (aliases) at once: `addFn<ObjInt>("inc", "increment") { ... }`.
|
||||||
|
|
||||||
|
Scope-backed Kotlin lambdas receive a `ScopeFacade` (not a full `Scope`). For migration and convenience, these utilities are available on the facade:
|
||||||
|
|
||||||
|
- Access: `args`, `pos`, `thisObj`, `get(name)`
|
||||||
|
- Invocation: `call(...)`, `resolve(...)`, `assign(...)`, `toStringOf(...)`, `inspect(...)`, `trace(...)`
|
||||||
|
- Args helpers: `requiredArg<T>()`, `requireOnlyArg<T>()`, `requireExactCount(...)`, `requireNoArgs()`, `thisAs<T>()`
|
||||||
|
- Errors: `raiseError(...)`, `raiseClassCastError(...)`, `raiseIllegalArgument(...)`, `raiseIllegalState(...)`, `raiseNoSuchElement(...)`,
|
||||||
|
`raiseSymbolNotFound(...)`, `raiseNotImplemented(...)`, `raiseNPE()`, `raiseIndexOutOfBounds(...)`, `raiseIllegalAssignment(...)`,
|
||||||
|
`raiseUnset(...)`, `raiseNotFound(...)`, `raiseAssertionFailed(...)`, `raiseIllegalOperation(...)`, `raiseIterationFinished()`
|
||||||
|
|
||||||
|
If you truly need the full `Scope` (e.g., for low-level interop), use `requireScope()` explicitly.
|
||||||
|
|
||||||
### 5) Add Kotlin‑backed fields
|
### 5) Add Kotlin‑backed fields
|
||||||
|
|
||||||
If you need a simple field (with a value) instead of a computed property, use `createField`. This adds a field to the class that will be present in all its instances.
|
If you need a simple field (with a value) instead of a computed property, use `createField`. This adds a field to the class that will be present in all its instances.
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -24,10 +24,10 @@ package net.sergeych.lyng.io.fs
|
|||||||
import net.sergeych.lyng.ModuleScope
|
import net.sergeych.lyng.ModuleScope
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.ScopeFacade
|
import net.sergeych.lyng.ScopeFacade
|
||||||
import net.sergeych.lyng.requireScope
|
|
||||||
import net.sergeych.lyng.miniast.*
|
import net.sergeych.lyng.miniast.*
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.pacman.ImportManager
|
import net.sergeych.lyng.pacman.ImportManager
|
||||||
|
import net.sergeych.lyng.requireScope
|
||||||
import net.sergeych.lyngio.fs.LyngFS
|
import net.sergeych.lyngio.fs.LyngFS
|
||||||
import net.sergeych.lyngio.fs.LyngFs
|
import net.sergeych.lyngio.fs.LyngFs
|
||||||
import net.sergeych.lyngio.fs.LyngPath
|
import net.sergeych.lyngio.fs.LyngPath
|
||||||
@ -478,7 +478,7 @@ private suspend inline fun ScopeFacade.fsGuard(crossinline block: suspend () ->
|
|||||||
return try {
|
return try {
|
||||||
block()
|
block()
|
||||||
} catch (e: AccessDeniedException) {
|
} catch (e: AccessDeniedException) {
|
||||||
raiseError(ObjIllegalOperationException(requireScope(), e.reasonDetail ?: "access denied"))
|
raiseIllegalOperation(e.reasonDetail ?: "access denied")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,10 +21,10 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import net.sergeych.lyng.ModuleScope
|
import net.sergeych.lyng.ModuleScope
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.ScopeFacade
|
import net.sergeych.lyng.ScopeFacade
|
||||||
import net.sergeych.lyng.requireScope
|
|
||||||
import net.sergeych.lyng.miniast.*
|
import net.sergeych.lyng.miniast.*
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.pacman.ImportManager
|
import net.sergeych.lyng.pacman.ImportManager
|
||||||
|
import net.sergeych.lyng.requireScope
|
||||||
import net.sergeych.lyngio.process.*
|
import net.sergeych.lyngio.process.*
|
||||||
import net.sergeych.lyngio.process.security.ProcessAccessDeniedException
|
import net.sergeych.lyngio.process.security.ProcessAccessDeniedException
|
||||||
import net.sergeych.lyngio.process.security.ProcessAccessPolicy
|
import net.sergeych.lyngio.process.security.ProcessAccessPolicy
|
||||||
@ -210,9 +210,9 @@ private suspend inline fun ScopeFacade.processGuard(crossinline block: suspend (
|
|||||||
return try {
|
return try {
|
||||||
block()
|
block()
|
||||||
} catch (e: ProcessAccessDeniedException) {
|
} catch (e: ProcessAccessDeniedException) {
|
||||||
raiseError(ObjIllegalOperationException(requireScope(), e.reasonDetail ?: "process access denied"))
|
raiseIllegalOperation(e.reasonDetail ?: "process access denied")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
raiseError(ObjIllegalOperationException(requireScope(), e.message ?: "process error"))
|
raiseIllegalOperation(e.message ?: "process error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2026 Sergey S. Chernov
|
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -12,13 +12,12 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
|
||||||
import net.sergeych.lyng.obj.ObjString
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limited facade for Kotlin bridge callables.
|
* Limited facade for Kotlin bridge callables.
|
||||||
@ -108,3 +107,29 @@ inline fun <reified T : Obj> ScopeFacade.thisAs(): T {
|
|||||||
|
|
||||||
fun ScopeFacade.requireScope(): Scope =
|
fun ScopeFacade.requireScope(): Scope =
|
||||||
(this as? ScopeBridge)?.scope ?: raiseIllegalState("ScopeFacade requires ScopeBridge")
|
(this as? ScopeBridge)?.scope ?: raiseIllegalState("ScopeFacade requires ScopeBridge")
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseNPE(): Nothing = requireScope().raiseNPE()
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIndexOutOfBounds(message: String = "Index out of bounds"): Nothing =
|
||||||
|
requireScope().raiseIndexOutOfBounds(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIllegalAssignment(message: String): Nothing =
|
||||||
|
requireScope().raiseIllegalAssignment(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseUnset(message: String = "property is unset (not initialized)"): Nothing =
|
||||||
|
requireScope().raiseUnset(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseNotFound(message: String = "not found"): Nothing =
|
||||||
|
requireScope().raiseNotFound(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseError(obj: Obj, pos: Pos = this.pos, message: String): Nothing =
|
||||||
|
requireScope().raiseError(obj, pos, message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseAssertionFailed(message: String): Nothing =
|
||||||
|
raiseError(ObjAssertionFailedException(requireScope(), message))
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIllegalOperation(message: String = "Operation is illegal"): Nothing =
|
||||||
|
raiseError(ObjIllegalOperationException(requireScope(), message))
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIterationFinished(): Nothing =
|
||||||
|
raiseError(ObjIterationFinishedException(requireScope()))
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import net.sergeych.lyng.miniast.*
|
|||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.pacman.ImportManager
|
import net.sergeych.lyng.pacman.ImportManager
|
||||||
import net.sergeych.lyng.stdlib_included.rootLyng
|
import net.sergeych.lyng.stdlib_included.rootLyng
|
||||||
import net.sergeych.lyng.bridge.LyngClassBridge
|
|
||||||
import net.sergeych.lynon.ObjLynonClass
|
import net.sergeych.lynon.ObjLynonClass
|
||||||
import net.sergeych.mp_tools.globalDefer
|
import net.sergeych.mp_tools.globalDefer
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
@ -326,7 +325,7 @@ class Script(
|
|||||||
": " + toStringOf(call(args[1])).value
|
": " + toStringOf(call(args[1])).value
|
||||||
else ""
|
else ""
|
||||||
if (!cond.value == true)
|
if (!cond.value == true)
|
||||||
raiseError(ObjAssertionFailedException(requireScope(), "Assertion failed$message"))
|
raiseAssertionFailed("Assertion failed$message")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unwrapCompareArg(value: Obj): Obj {
|
fun unwrapCompareArg(value: Obj): Obj {
|
||||||
@ -342,12 +341,7 @@ class Script(
|
|||||||
val a = unwrapCompareArg(requiredArg(0))
|
val a = unwrapCompareArg(requiredArg(0))
|
||||||
val b = unwrapCompareArg(requiredArg(1))
|
val b = unwrapCompareArg(requiredArg(1))
|
||||||
if (a.compareTo(requireScope(), b) != 0) {
|
if (a.compareTo(requireScope(), b) != 0) {
|
||||||
raiseError(
|
raiseAssertionFailed("Assertion failed: ${inspect(a)} == ${inspect(b)}")
|
||||||
ObjAssertionFailedException(
|
|
||||||
requireScope(),
|
|
||||||
"Assertion failed: ${inspect(a)} == ${inspect(b)}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// alias used in tests
|
// alias used in tests
|
||||||
@ -355,23 +349,13 @@ class Script(
|
|||||||
val a = unwrapCompareArg(requiredArg(0))
|
val a = unwrapCompareArg(requiredArg(0))
|
||||||
val b = unwrapCompareArg(requiredArg(1))
|
val b = unwrapCompareArg(requiredArg(1))
|
||||||
if (a.compareTo(requireScope(), b) != 0)
|
if (a.compareTo(requireScope(), b) != 0)
|
||||||
raiseError(
|
raiseAssertionFailed("Assertion failed: ${inspect(a)} == ${inspect(b)}")
|
||||||
ObjAssertionFailedException(
|
|
||||||
requireScope(),
|
|
||||||
"Assertion failed: ${inspect(a)} == ${inspect(b)}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
addVoidFn("assertNotEquals") {
|
addVoidFn("assertNotEquals") {
|
||||||
val a = unwrapCompareArg(requiredArg(0))
|
val a = unwrapCompareArg(requiredArg(0))
|
||||||
val b = unwrapCompareArg(requiredArg(1))
|
val b = unwrapCompareArg(requiredArg(1))
|
||||||
if (a.compareTo(requireScope(), b) == 0)
|
if (a.compareTo(requireScope(), b) == 0)
|
||||||
raiseError(
|
raiseAssertionFailed("Assertion failed: ${inspect(a)} != ${inspect(b)}")
|
||||||
ObjAssertionFailedException(
|
|
||||||
requireScope(),
|
|
||||||
"Assertion failed: ${inspect(a)} != ${inspect(b)}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
"assertThrows",
|
"assertThrows",
|
||||||
@ -409,12 +393,7 @@ class Script(
|
|||||||
} catch (_: ScriptError) {
|
} catch (_: ScriptError) {
|
||||||
ObjNull
|
ObjNull
|
||||||
}
|
}
|
||||||
if (result == null) raiseError(
|
if (result == null) raiseAssertionFailed("Expected exception but nothing was thrown")
|
||||||
ObjAssertionFailedException(
|
|
||||||
requireScope(),
|
|
||||||
"Expected exception but nothing was thrown"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
expectedClass?.let {
|
expectedClass?.let {
|
||||||
if (!result.isInstanceOf(it)) {
|
if (!result.isInstanceOf(it)) {
|
||||||
val actual = if (result is ObjException) result.exceptionClass else result.objClass
|
val actual = if (result is ObjException) result.exceptionClass else result.objClass
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -39,7 +39,7 @@ class ObjArrayIterator(val array: Obj) : Obj() {
|
|||||||
val self = thisAs<ObjArrayIterator>()
|
val self = thisAs<ObjArrayIterator>()
|
||||||
if (self.nextIndex < self.lastIndex) {
|
if (self.nextIndex < self.lastIndex) {
|
||||||
self.array.invokeInstanceMethod(requireScope(), "getAt", (self.nextIndex++).toObj())
|
self.array.invokeInstanceMethod(requireScope(), "getAt", (self.nextIndex++).toObj())
|
||||||
} else raiseError(ObjIterationFinishedException(requireScope()))
|
} else raiseIterationFinished()
|
||||||
}
|
}
|
||||||
addFn("hasNext") {
|
addFn("hasNext") {
|
||||||
val self = thisAs<ObjArrayIterator>()
|
val self = thisAs<ObjArrayIterator>()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2026 Sergey S. Chernov
|
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -12,17 +12,28 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.sergeych.lyng.obj
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.ScopeFacade
|
import net.sergeych.lyng.ScopeFacade
|
||||||
|
import net.sergeych.lyng.raiseAssertionFailed as coreRaiseAssertionFailed
|
||||||
|
import net.sergeych.lyng.raiseError as coreRaiseError
|
||||||
|
import net.sergeych.lyng.raiseIllegalAssignment as coreRaiseIllegalAssignment
|
||||||
|
import net.sergeych.lyng.raiseIllegalOperation as coreRaiseIllegalOperation
|
||||||
|
import net.sergeych.lyng.raiseIndexOutOfBounds as coreRaiseIndexOutOfBounds
|
||||||
|
import net.sergeych.lyng.raiseIterationFinished as coreRaiseIterationFinished
|
||||||
|
import net.sergeych.lyng.raiseNPE as coreRaiseNPE
|
||||||
|
import net.sergeych.lyng.raiseNotFound as coreRaiseNotFound
|
||||||
|
import net.sergeych.lyng.raiseUnset as coreRaiseUnset
|
||||||
import net.sergeych.lyng.requireExactCount as coreRequireExactCount
|
import net.sergeych.lyng.requireExactCount as coreRequireExactCount
|
||||||
import net.sergeych.lyng.requireNoArgs as coreRequireNoArgs
|
import net.sergeych.lyng.requireNoArgs as coreRequireNoArgs
|
||||||
import net.sergeych.lyng.requireOnlyArg as coreRequireOnlyArg
|
import net.sergeych.lyng.requireOnlyArg as coreRequireOnlyArg
|
||||||
import net.sergeych.lyng.requiredArg as coreRequiredArg
|
|
||||||
import net.sergeych.lyng.requireScope as coreRequireScope
|
import net.sergeych.lyng.requireScope as coreRequireScope
|
||||||
|
import net.sergeych.lyng.requiredArg as coreRequiredArg
|
||||||
import net.sergeych.lyng.thisAs as coreThisAs
|
import net.sergeych.lyng.thisAs as coreThisAs
|
||||||
|
|
||||||
inline fun <reified T : Obj> ScopeFacade.requiredArg(index: Int): T = coreRequiredArg(index)
|
inline fun <reified T : Obj> ScopeFacade.requiredArg(index: Int): T = coreRequiredArg(index)
|
||||||
@ -36,3 +47,29 @@ fun ScopeFacade.requireNoArgs() = coreRequireNoArgs()
|
|||||||
inline fun <reified T : Obj> ScopeFacade.thisAs(): T = coreThisAs()
|
inline fun <reified T : Obj> ScopeFacade.thisAs(): T = coreThisAs()
|
||||||
|
|
||||||
internal fun ScopeFacade.requireScope(): Scope = coreRequireScope()
|
internal fun ScopeFacade.requireScope(): Scope = coreRequireScope()
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseNPE(): Nothing = coreRaiseNPE()
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIndexOutOfBounds(message: String = "Index out of bounds"): Nothing =
|
||||||
|
coreRaiseIndexOutOfBounds(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIllegalAssignment(message: String): Nothing =
|
||||||
|
coreRaiseIllegalAssignment(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseUnset(message: String = "property is unset (not initialized)"): Nothing =
|
||||||
|
coreRaiseUnset(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseNotFound(message: String = "not found"): Nothing =
|
||||||
|
coreRaiseNotFound(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseError(obj: Obj, pos: Pos = this.pos, message: String): Nothing =
|
||||||
|
coreRaiseError(obj, pos, message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseAssertionFailed(message: String): Nothing =
|
||||||
|
coreRaiseAssertionFailed(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIllegalOperation(message: String = "Operation is illegal"): Nothing =
|
||||||
|
coreRaiseIllegalOperation(message)
|
||||||
|
|
||||||
|
fun ScopeFacade.raiseIterationFinished(): Nothing =
|
||||||
|
coreRaiseIterationFinished()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user