Remove interpreter paths and enforce bytecode-only execution
This commit is contained in:
parent
e73fe0d3c5
commit
34678068ac
@ -23,6 +23,8 @@ 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.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
|
||||||
@ -437,7 +439,7 @@ private suspend fun buildFsModule(module: ModuleScope, policy: FsAccessPolicy) {
|
|||||||
moduleName = module.packageName
|
moduleName = module.packageName
|
||||||
) {
|
) {
|
||||||
fsGuard {
|
fsGuard {
|
||||||
val chunkIt = thisObj.invokeInstanceMethod(this, "readUtf8Chunks")
|
val chunkIt = thisObj.invokeInstanceMethod(requireScope(), "readUtf8Chunks")
|
||||||
ObjFsLinesIterator(chunkIt)
|
ObjFsLinesIterator(chunkIt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -463,7 +465,7 @@ private suspend fun buildFsModule(module: ModuleScope, policy: FsAccessPolicy) {
|
|||||||
|
|
||||||
// --- Helper classes and utilities ---
|
// --- Helper classes and utilities ---
|
||||||
|
|
||||||
private fun parsePathArg(scope: Scope, self: ObjPath, arg: Obj): LyngPath {
|
private fun parsePathArg(scope: ScopeFacade, self: ObjPath, arg: Obj): LyngPath {
|
||||||
return when (arg) {
|
return when (arg) {
|
||||||
is ObjString -> arg.value.toPath()
|
is ObjString -> arg.value.toPath()
|
||||||
is ObjPath -> arg.path
|
is ObjPath -> arg.path
|
||||||
@ -472,11 +474,11 @@ private fun parsePathArg(scope: Scope, self: ObjPath, arg: Obj): LyngPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map Fs access denials to Lyng runtime exceptions for script-friendly errors
|
// Map Fs access denials to Lyng runtime exceptions for script-friendly errors
|
||||||
private suspend inline fun Scope.fsGuard(crossinline block: suspend () -> Obj): Obj {
|
private suspend inline fun ScopeFacade.fsGuard(crossinline block: suspend () -> Obj): Obj {
|
||||||
return try {
|
return try {
|
||||||
block()
|
block()
|
||||||
} catch (e: AccessDeniedException) {
|
} catch (e: AccessDeniedException) {
|
||||||
raiseError(ObjIllegalOperationException(this, e.reasonDetail ?: "access denied"))
|
raiseError(ObjIllegalOperationException(requireScope(), e.reasonDetail ?: "access denied"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,16 +670,17 @@ class ObjFsLinesIterator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ensureBufferFilled(scope: Scope) {
|
private suspend fun ensureBufferFilled(scope: ScopeFacade) {
|
||||||
if (buffer.contains('\n') || exhausted) return
|
if (buffer.contains('\n') || exhausted) return
|
||||||
|
val actualScope = scope.requireScope()
|
||||||
// Pull next chunk from the underlying iterator
|
// Pull next chunk from the underlying iterator
|
||||||
val it = chunksIterator.invokeInstanceMethod(scope, "iterator")
|
val it = chunksIterator.invokeInstanceMethod(actualScope, "iterator")
|
||||||
val hasNext = it.invokeInstanceMethod(scope, "hasNext").toBool()
|
val hasNext = it.invokeInstanceMethod(actualScope, "hasNext").toBool()
|
||||||
if (!hasNext) {
|
if (!hasNext) {
|
||||||
exhausted = true
|
exhausted = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val next = it.invokeInstanceMethod(scope, "next")
|
val next = it.invokeInstanceMethod(actualScope, "next")
|
||||||
buffer += next.toString()
|
buffer += next.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,8 @@ package net.sergeych.lyng.io.process
|
|||||||
import kotlinx.coroutines.flow.Flow
|
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.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
|
||||||
@ -204,20 +206,21 @@ class ObjRunningProcess(
|
|||||||
override fun toString(): String = "RunningProcess($process)"
|
override fun toString(): String = "RunningProcess($process)"
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun Scope.processGuard(crossinline block: suspend () -> Obj): Obj {
|
private suspend inline fun ScopeFacade.processGuard(crossinline block: suspend () -> Obj): Obj {
|
||||||
return try {
|
return try {
|
||||||
block()
|
block()
|
||||||
} catch (e: ProcessAccessDeniedException) {
|
} catch (e: ProcessAccessDeniedException) {
|
||||||
raiseError(ObjIllegalOperationException(this, e.reasonDetail ?: "process access denied"))
|
raiseError(ObjIllegalOperationException(requireScope(), e.reasonDetail ?: "process access denied"))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
raiseError(ObjIllegalOperationException(this, e.message ?: "process error"))
|
raiseError(ObjIllegalOperationException(requireScope(), e.message ?: "process error"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Flow<String>.toLyngFlow(flowScope: Scope): ObjFlow {
|
private fun Flow<String>.toLyngFlow(flowScope: ScopeFacade): ObjFlow {
|
||||||
val producer = ObjNativeCallable {
|
val producer = net.sergeych.lyng.obj.ObjExternCallable.fromBridge {
|
||||||
val builder = (this as? net.sergeych.lyng.BytecodeClosureScope)?.callScope?.thisObj as? ObjFlowBuilder
|
val scope = requireScope()
|
||||||
?: this.thisObj as? ObjFlowBuilder
|
val builder = (scope as? net.sergeych.lyng.BytecodeClosureScope)?.callScope?.thisObj as? ObjFlowBuilder
|
||||||
|
?: scope.thisObj as? ObjFlowBuilder
|
||||||
|
|
||||||
this@toLyngFlow.collect {
|
this@toLyngFlow.collect {
|
||||||
try {
|
try {
|
||||||
@ -229,5 +232,5 @@ private fun Flow<String>.toLyngFlow(flowScope: Scope): ObjFlow {
|
|||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
return ObjFlow(producer, flowScope)
|
return ObjFlow(producer, flowScope.requireScope())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class BlockStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "block statement")
|
return bytecodeOnly(scope, "block statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun statements(): List<Statement> = block.debugStatements()
|
fun statements(): List<Statement> = block.debugStatements()
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class ClassInstanceInitDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "class instance init declaration")
|
return bytecodeOnly(scope, "class instance init declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class ClassInstanceFieldDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "class instance field declaration")
|
return bytecodeOnly(scope, "class instance field declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class ClassInstancePropertyDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "class instance property declaration")
|
return bytecodeOnly(scope, "class instance property declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +79,6 @@ class ClassInstanceDelegatedDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "class instance delegated declaration")
|
return bytecodeOnly(scope, "class instance delegated declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import net.sergeych.lyng.obj.ObjRecord
|
|||||||
/**
|
/**
|
||||||
* Bytecode-oriented closure scope that keeps the call scope parent chain for stack traces
|
* Bytecode-oriented closure scope that keeps the call scope parent chain for stack traces
|
||||||
* while carrying the lexical closure for `this` variants and module resolution.
|
* while carrying the lexical closure for `this` variants and module resolution.
|
||||||
* Unlike interpreter closure scopes, it does not override name lookup.
|
* Unlike legacy closure scopes, it does not override name lookup.
|
||||||
*/
|
*/
|
||||||
class BytecodeClosureScope(
|
class BytecodeClosureScope(
|
||||||
val callScope: Scope,
|
val callScope: Scope,
|
||||||
|
|||||||
@ -32,6 +32,6 @@ class DelegatedVarDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
return interpreterDisabled(context, "delegated var declaration")
|
return bytecodeOnly(context, "delegated var declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,6 @@ class DestructuringVarDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
return interpreterDisabled(context, "destructuring declaration")
|
return bytecodeOnly(context, "destructuring declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class EnumDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "enum declaration")
|
return bytecodeOnly(scope, "enum declaration")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
|
|||||||
@ -29,6 +29,6 @@ class ExtensionPropertyDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
return interpreterDisabled(context, "extension property declaration")
|
return bytecodeOnly(context, "extension property declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ package net.sergeych.lyng
|
|||||||
/**
|
/**
|
||||||
* Tiny, size-bounded cache for compiled Regex patterns. Activated only when [PerfFlags.REGEX_CACHE] is true.
|
* Tiny, size-bounded cache for compiled Regex patterns. Activated only when [PerfFlags.REGEX_CACHE] is true.
|
||||||
* This is a very simple FIFO-ish cache sufficient for micro-benchmarks and common repeated patterns.
|
* This is a very simple FIFO-ish cache sufficient for micro-benchmarks and common repeated patterns.
|
||||||
* Not thread-safe by design; the interpreter typically runs scripts on confined executors.
|
* Not thread-safe by design; the runtime typically runs scripts on confined executors.
|
||||||
*/
|
*/
|
||||||
object RegexCache {
|
object RegexCache {
|
||||||
private const val MAX = 64
|
private const val MAX = 64
|
||||||
|
|||||||
@ -725,7 +725,7 @@ open class Scope(
|
|||||||
return ns.objClass
|
return ns.objClass
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun addVoidFn(vararg names: String, crossinline fn: suspend Scope.() -> Unit) {
|
inline fun addVoidFn(vararg names: String, crossinline fn: suspend ScopeFacade.() -> Unit) {
|
||||||
addFn(*names) {
|
addFn(*names) {
|
||||||
fn(this)
|
fn(this)
|
||||||
ObjVoid
|
ObjVoid
|
||||||
@ -741,8 +741,8 @@ open class Scope(
|
|||||||
return CmdDisassembler.disassemble(bytecode)
|
return CmdDisassembler.disassemble(bytecode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addFn(vararg names: String, callSignature: CallSignature? = null, fn: suspend Scope.() -> Obj) {
|
fun addFn(vararg names: String, callSignature: CallSignature? = null, fn: suspend ScopeFacade.() -> Obj) {
|
||||||
val newFn = net.sergeych.lyng.obj.ObjNativeCallable { fn() }
|
val newFn = net.sergeych.lyng.obj.ObjExternCallable.fromBridge { fn() }
|
||||||
for (name in names) {
|
for (name in names) {
|
||||||
addItem(
|
addItem(
|
||||||
name,
|
name,
|
||||||
|
|||||||
@ -18,6 +18,7 @@ package net.sergeych.lyng
|
|||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
import net.sergeych.lyng.obj.ObjRecord
|
||||||
|
import net.sergeych.lyng.obj.ObjString
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limited facade for Kotlin bridge callables.
|
* Limited facade for Kotlin bridge callables.
|
||||||
@ -31,11 +32,20 @@ interface ScopeFacade {
|
|||||||
suspend fun resolve(rec: ObjRecord, name: String): Obj
|
suspend fun resolve(rec: ObjRecord, name: String): Obj
|
||||||
suspend fun assign(rec: ObjRecord, name: String, newValue: Obj)
|
suspend fun assign(rec: ObjRecord, name: String, newValue: Obj)
|
||||||
fun raiseError(message: String): Nothing
|
fun raiseError(message: String): Nothing
|
||||||
|
fun raiseError(obj: net.sergeych.lyng.obj.ObjException): Nothing
|
||||||
|
fun raiseClassCastError(message: String): Nothing
|
||||||
|
fun raiseIllegalArgument(message: String): Nothing
|
||||||
|
fun raiseNoSuchElement(message: String = "No such element"): Nothing
|
||||||
fun raiseSymbolNotFound(name: String): Nothing
|
fun raiseSymbolNotFound(name: String): Nothing
|
||||||
fun raiseIllegalState(message: String = "Illegal argument error"): Nothing
|
fun raiseIllegalState(message: String = "Illegal argument error"): Nothing
|
||||||
|
fun raiseNotImplemented(what: String = "operation"): Nothing
|
||||||
|
suspend fun call(callee: Obj, args: Arguments = Arguments.EMPTY, newThisObj: Obj? = null): Obj
|
||||||
|
suspend fun toStringOf(obj: Obj, forInspect: Boolean = false): ObjString
|
||||||
|
suspend fun inspect(obj: Obj): String
|
||||||
|
fun trace(text: String = "")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ScopeBridge(private val scope: Scope) : ScopeFacade {
|
internal class ScopeBridge(internal val scope: Scope) : ScopeFacade {
|
||||||
override val args: Arguments
|
override val args: Arguments
|
||||||
get() = scope.args
|
get() = scope.args
|
||||||
override var pos: Pos
|
override var pos: Pos
|
||||||
@ -48,6 +58,50 @@ internal class ScopeBridge(private val scope: Scope) : ScopeFacade {
|
|||||||
override suspend fun resolve(rec: ObjRecord, name: String): Obj = scope.resolve(rec, name)
|
override suspend fun resolve(rec: ObjRecord, name: String): Obj = scope.resolve(rec, name)
|
||||||
override suspend fun assign(rec: ObjRecord, name: String, newValue: Obj) = scope.assign(rec, name, newValue)
|
override suspend fun assign(rec: ObjRecord, name: String, newValue: Obj) = scope.assign(rec, name, newValue)
|
||||||
override fun raiseError(message: String): Nothing = scope.raiseError(message)
|
override fun raiseError(message: String): Nothing = scope.raiseError(message)
|
||||||
|
override fun raiseError(obj: net.sergeych.lyng.obj.ObjException): Nothing = scope.raiseError(obj)
|
||||||
|
override fun raiseClassCastError(message: String): Nothing = scope.raiseClassCastError(message)
|
||||||
|
override fun raiseIllegalArgument(message: String): Nothing = scope.raiseIllegalArgument(message)
|
||||||
|
override fun raiseNoSuchElement(message: String): Nothing = scope.raiseNoSuchElement(message)
|
||||||
override fun raiseSymbolNotFound(name: String): Nothing = scope.raiseSymbolNotFound(name)
|
override fun raiseSymbolNotFound(name: String): Nothing = scope.raiseSymbolNotFound(name)
|
||||||
override fun raiseIllegalState(message: String): Nothing = scope.raiseIllegalState(message)
|
override fun raiseIllegalState(message: String): Nothing = scope.raiseIllegalState(message)
|
||||||
|
override fun raiseNotImplemented(what: String): Nothing = scope.raiseNotImplemented(what)
|
||||||
|
override suspend fun call(callee: Obj, args: Arguments, newThisObj: Obj?): Obj {
|
||||||
|
return callee.callOn(scope.createChildScope(scope.pos, args = args, newThisObj = newThisObj))
|
||||||
|
}
|
||||||
|
override suspend fun toStringOf(obj: Obj, forInspect: Boolean): ObjString = obj.toString(scope, forInspect)
|
||||||
|
override suspend fun inspect(obj: Obj): String = obj.inspect(scope)
|
||||||
|
override fun trace(text: String) = scope.trace(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Obj> ScopeFacade.requiredArg(index: Int): T {
|
||||||
|
if (args.list.size <= index) raiseError("Expected at least ${index + 1} argument, got ${args.list.size}")
|
||||||
|
return (args.list[index].byValueCopy() as? T)
|
||||||
|
?: raiseClassCastError("Expected type ${T::class.simpleName}, got ${args.list[index]::class.simpleName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Obj> ScopeFacade.requireOnlyArg(): T {
|
||||||
|
if (args.list.size != 1) raiseError("Expected exactly 1 argument, got ${args.list.size}")
|
||||||
|
return requiredArg(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ScopeFacade.requireExactCount(count: Int) {
|
||||||
|
if (args.list.size != count) {
|
||||||
|
raiseError("Expected exactly $count arguments, got ${args.list.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ScopeFacade.requireNoArgs() {
|
||||||
|
if (args.list.isNotEmpty()) {
|
||||||
|
raiseError("This function does not accept any arguments")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Obj> ScopeFacade.thisAs(): T {
|
||||||
|
val obj = thisObj
|
||||||
|
return (obj as? T) ?: raiseClassCastError(
|
||||||
|
"Cannot cast ${obj.objClass.className} to ${T::class.simpleName}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ScopeFacade.requireScope(): Scope =
|
||||||
|
(this as? ScopeBridge)?.scope ?: raiseIllegalState("ScopeFacade requires ScopeBridge")
|
||||||
|
|||||||
@ -90,7 +90,7 @@ class Script(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (statements.isNotEmpty()) {
|
if (statements.isNotEmpty()) {
|
||||||
scope.raiseIllegalState("interpreter execution is not supported; missing module bytecode")
|
scope.raiseIllegalState("bytecode-only execution is required; missing module bytecode")
|
||||||
}
|
}
|
||||||
return ObjVoid
|
return ObjVoid
|
||||||
}
|
}
|
||||||
@ -212,15 +212,15 @@ class Script(
|
|||||||
addConst("Unset", ObjUnset)
|
addConst("Unset", ObjUnset)
|
||||||
addFn("print") {
|
addFn("print") {
|
||||||
for ((i, a) in args.withIndex()) {
|
for ((i, a) in args.withIndex()) {
|
||||||
if (i > 0) print(' ' + a.toString(this).value)
|
if (i > 0) print(' ' + toStringOf(a).value)
|
||||||
else print(a.toString(this).value)
|
else print(toStringOf(a).value)
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
addFn("println") {
|
addFn("println") {
|
||||||
for ((i, a) in args.withIndex()) {
|
for ((i, a) in args.withIndex()) {
|
||||||
if (i > 0) print(' ' + a.toString(this).value)
|
if (i > 0) print(' ' + toStringOf(a).value)
|
||||||
else print(a.toString(this).value)
|
else print(toStringOf(a).value)
|
||||||
}
|
}
|
||||||
println()
|
println()
|
||||||
ObjVoid
|
ObjVoid
|
||||||
@ -233,7 +233,7 @@ class Script(
|
|||||||
} else {
|
} else {
|
||||||
Arguments.EMPTY
|
Arguments.EMPTY
|
||||||
}
|
}
|
||||||
callee.callOn(createChildScope(pos, args = rest))
|
call(callee, rest)
|
||||||
}
|
}
|
||||||
addFn("floor") {
|
addFn("floor") {
|
||||||
val x = args.firstAndOnly()
|
val x = args.firstAndOnly()
|
||||||
@ -331,12 +331,12 @@ class Script(
|
|||||||
|
|
||||||
var result = value
|
var result = value
|
||||||
if (range.start != null && !range.start.isNull) {
|
if (range.start != null && !range.start.isNull) {
|
||||||
if (result.compareTo(this, range.start) < 0) {
|
if (result.compareTo(requireScope(), range.start) < 0) {
|
||||||
result = range.start
|
result = range.start
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (range.end != null && !range.end.isNull) {
|
if (range.end != null && !range.end.isNull) {
|
||||||
val cmp = range.end.compareTo(this, result)
|
val cmp = range.end.compareTo(requireScope(), result)
|
||||||
if (range.isEndInclusive) {
|
if (range.isEndInclusive) {
|
||||||
if (cmp < 0) result = range.end
|
if (cmp < 0) result = range.end
|
||||||
} else {
|
} else {
|
||||||
@ -359,20 +359,20 @@ class Script(
|
|||||||
addVoidFn("assert") {
|
addVoidFn("assert") {
|
||||||
val cond = requiredArg<ObjBool>(0)
|
val cond = requiredArg<ObjBool>(0)
|
||||||
val message = if (args.size > 1)
|
val message = if (args.size > 1)
|
||||||
": " + (args[1] as Obj).callOn(this).toString(this).value
|
": " + toStringOf(call(args[1] as Obj)).value
|
||||||
else ""
|
else ""
|
||||||
if (!cond.value == true)
|
if (!cond.value == true)
|
||||||
raiseError(ObjAssertionFailedException(this, "Assertion failed$message"))
|
raiseError(ObjAssertionFailedException(requireScope(), "Assertion failed$message"))
|
||||||
}
|
}
|
||||||
|
|
||||||
addVoidFn("assertEquals") {
|
addVoidFn("assertEquals") {
|
||||||
val a = requiredArg<Obj>(0)
|
val a = requiredArg<Obj>(0)
|
||||||
val b = requiredArg<Obj>(1)
|
val b = requiredArg<Obj>(1)
|
||||||
if (a.compareTo(this, b) != 0)
|
if (a.compareTo(requireScope(), b) != 0)
|
||||||
raiseError(
|
raiseError(
|
||||||
ObjAssertionFailedException(
|
ObjAssertionFailedException(
|
||||||
this,
|
requireScope(),
|
||||||
"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"
|
"Assertion failed: ${inspect(a)} == ${inspect(b)}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -380,22 +380,22 @@ class Script(
|
|||||||
addVoidFn("assertEqual") {
|
addVoidFn("assertEqual") {
|
||||||
val a = requiredArg<Obj>(0)
|
val a = requiredArg<Obj>(0)
|
||||||
val b = requiredArg<Obj>(1)
|
val b = requiredArg<Obj>(1)
|
||||||
if (a.compareTo(this, b) != 0)
|
if (a.compareTo(requireScope(), b) != 0)
|
||||||
raiseError(
|
raiseError(
|
||||||
ObjAssertionFailedException(
|
ObjAssertionFailedException(
|
||||||
this,
|
requireScope(),
|
||||||
"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"
|
"Assertion failed: ${inspect(a)} == ${inspect(b)}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
addVoidFn("assertNotEquals") {
|
addVoidFn("assertNotEquals") {
|
||||||
val a = requiredArg<Obj>(0)
|
val a = requiredArg<Obj>(0)
|
||||||
val b = requiredArg<Obj>(1)
|
val b = requiredArg<Obj>(1)
|
||||||
if (a.compareTo(this, b) == 0)
|
if (a.compareTo(requireScope(), b) == 0)
|
||||||
raiseError(
|
raiseError(
|
||||||
ObjAssertionFailedException(
|
ObjAssertionFailedException(
|
||||||
this,
|
requireScope(),
|
||||||
"Assertion failed: ${a.inspect(this)} != ${b.inspect(this)}"
|
"Assertion failed: ${inspect(a)} != ${inspect(b)}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -428,7 +428,7 @@ class Script(
|
|||||||
else -> raiseIllegalArgument("Expected 1 or 2 arguments, got ${args.size}")
|
else -> raiseIllegalArgument("Expected 1 or 2 arguments, got ${args.size}")
|
||||||
}
|
}
|
||||||
val result = try {
|
val result = try {
|
||||||
code.callOn(this)
|
call(code)
|
||||||
null
|
null
|
||||||
} catch (e: ExecutionError) {
|
} catch (e: ExecutionError) {
|
||||||
e.errorObject
|
e.errorObject
|
||||||
@ -437,7 +437,7 @@ class Script(
|
|||||||
}
|
}
|
||||||
if (result == null) raiseError(
|
if (result == null) raiseError(
|
||||||
ObjAssertionFailedException(
|
ObjAssertionFailedException(
|
||||||
this,
|
requireScope(),
|
||||||
"Expected exception but nothing was thrown"
|
"Expected exception but nothing was thrown"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -451,7 +451,7 @@ class Script(
|
|||||||
}
|
}
|
||||||
|
|
||||||
addFn("dynamic", callSignature = CallSignature(tailBlockReceiverType = "DelegateContext")) {
|
addFn("dynamic", callSignature = CallSignature(tailBlockReceiverType = "DelegateContext")) {
|
||||||
ObjDynamic.create(this, requireOnlyArg())
|
ObjDynamic.create(requireScope(), requireOnlyArg())
|
||||||
}
|
}
|
||||||
|
|
||||||
val root = this
|
val root = this
|
||||||
@ -468,7 +468,7 @@ class Script(
|
|||||||
val condition = requiredArg<ObjBool>(0)
|
val condition = requiredArg<ObjBool>(0)
|
||||||
if (!condition.value) {
|
if (!condition.value) {
|
||||||
var message = args.list.getOrNull(1)
|
var message = args.list.getOrNull(1)
|
||||||
if (message is Obj && message.objClass == Statement.type) message = message.callOn(this)
|
if (message is Obj && message.objClass == Statement.type) message = call(message)
|
||||||
raiseIllegalArgument(message?.toString() ?: "requirement not met")
|
raiseIllegalArgument(message?.toString() ?: "requirement not met")
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
@ -477,26 +477,26 @@ class Script(
|
|||||||
val condition = requiredArg<ObjBool>(0)
|
val condition = requiredArg<ObjBool>(0)
|
||||||
if (!condition.value) {
|
if (!condition.value) {
|
||||||
var message = args.list.getOrNull(1)
|
var message = args.list.getOrNull(1)
|
||||||
if (message is Obj && message.objClass == Statement.type) message = message.callOn(this)
|
if (message is Obj && message.objClass == Statement.type) message = call(message)
|
||||||
raiseIllegalState(message?.toString() ?: "check failed")
|
raiseIllegalState(message?.toString() ?: "check failed")
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
addFn("traceScope") {
|
addFn("traceScope") {
|
||||||
this.trace(args.getOrNull(0)?.toString() ?: "")
|
trace(args.getOrNull(0)?.toString() ?: "")
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
addFn("run") {
|
addFn("run") {
|
||||||
requireOnlyArg<Obj>().callOn(this)
|
call(requireOnlyArg())
|
||||||
}
|
}
|
||||||
addFn("cached") {
|
addFn("cached") {
|
||||||
val builder = requireOnlyArg<Obj>()
|
val builder = requireOnlyArg<Obj>()
|
||||||
val capturedScope = this
|
val capturedScope = this
|
||||||
var calculated = false
|
var calculated = false
|
||||||
var cachedValue: Obj = ObjVoid
|
var cachedValue: Obj = ObjVoid
|
||||||
ObjNativeCallable {
|
net.sergeych.lyng.obj.ObjExternCallable.fromBridge {
|
||||||
if (!calculated) {
|
if (!calculated) {
|
||||||
cachedValue = builder.callOn(capturedScope)
|
cachedValue = capturedScope.call(builder)
|
||||||
calculated = true
|
calculated = true
|
||||||
}
|
}
|
||||||
cachedValue
|
cachedValue
|
||||||
@ -504,7 +504,7 @@ class Script(
|
|||||||
}
|
}
|
||||||
addFn("lazy") {
|
addFn("lazy") {
|
||||||
val builder = requireOnlyArg<Obj>()
|
val builder = requireOnlyArg<Obj>()
|
||||||
ObjLazyDelegate(builder, this)
|
ObjLazyDelegate(builder, requireScope())
|
||||||
}
|
}
|
||||||
addVoidFn("delay") {
|
addVoidFn("delay") {
|
||||||
val a = args.firstAndOnly()
|
val a = args.firstAndOnly()
|
||||||
@ -512,7 +512,7 @@ class Script(
|
|||||||
is ObjInt -> delay(a.value)
|
is ObjInt -> delay(a.value)
|
||||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||||
is ObjDuration -> delay(a.duration)
|
is ObjDuration -> delay(a.duration)
|
||||||
else -> raiseIllegalArgument("Expected Int, Real or Duration, got ${a.inspect(this)}")
|
else -> raiseIllegalArgument("Expected Int, Real or Duration, got ${inspect(a)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,8 +551,9 @@ class Script(
|
|||||||
|
|
||||||
addFn("launch") {
|
addFn("launch") {
|
||||||
val callable = requireOnlyArg<Obj>()
|
val callable = requireOnlyArg<Obj>()
|
||||||
|
val captured = this
|
||||||
ObjDeferred(globalDefer {
|
ObjDeferred(globalDefer {
|
||||||
callable.callOn(this@addFn)
|
captured.call(callable)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +565,7 @@ class Script(
|
|||||||
addFn("flow", callSignature = CallSignature(tailBlockReceiverType = "FlowBuilder")) {
|
addFn("flow", callSignature = CallSignature(tailBlockReceiverType = "FlowBuilder")) {
|
||||||
// important is: current context contains closure often used in call;
|
// important is: current context contains closure often used in call;
|
||||||
// we'll need it for the producer
|
// we'll need it for the producer
|
||||||
ObjFlow(requireOnlyArg<Obj>(), this)
|
ObjFlow(requireOnlyArg<Obj>(), requireScope())
|
||||||
}
|
}
|
||||||
|
|
||||||
val pi = ObjReal(PI)
|
val pi = ObjReal(PI)
|
||||||
@ -639,7 +640,7 @@ class Script(
|
|||||||
is ObjInt -> delay(a.value * 1000)
|
is ObjInt -> delay(a.value * 1000)
|
||||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||||
is ObjDuration -> delay(a.duration)
|
is ObjDuration -> delay(a.duration)
|
||||||
else -> raiseIllegalArgument("Expected Duration, Int or Real, got ${a.inspect(this)}")
|
else -> raiseIllegalArgument("Expected Duration, Int or Real, got ${inspect(a)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class TryStatement(
|
|||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "try statement")
|
return bytecodeOnly(scope, "try statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveExceptionClass(scope: Scope, name: String): ObjClass {
|
private fun resolveExceptionClass(scope: Scope, name: String): ObjClass {
|
||||||
|
|||||||
@ -33,6 +33,6 @@ class VarDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
return interpreterDisabled(context, "var declaration")
|
return bytecodeOnly(context, "var declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,8 +19,8 @@ package net.sergeych.lyng
|
|||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
|
|
||||||
sealed class WhenCondition(open val expr: Statement, open val pos: Pos) {
|
sealed class WhenCondition(open val expr: Statement, open val pos: Pos) {
|
||||||
protected fun interpreterDisabled(scope: Scope): Nothing {
|
protected fun bytecodeOnly(scope: Scope): Nothing {
|
||||||
return scope.raiseIllegalState("interpreter execution is not supported; when condition requires bytecode")
|
return scope.raiseIllegalState("bytecode-only execution is required; when condition needs compiled bytecode")
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract suspend fun matches(scope: Scope, value: Obj): Boolean
|
abstract suspend fun matches(scope: Scope, value: Obj): Boolean
|
||||||
@ -31,7 +31,7 @@ class WhenEqualsCondition(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : WhenCondition(expr, pos) {
|
) : WhenCondition(expr, pos) {
|
||||||
override suspend fun matches(scope: Scope, value: Obj): Boolean {
|
override suspend fun matches(scope: Scope, value: Obj): Boolean {
|
||||||
return interpreterDisabled(scope)
|
return bytecodeOnly(scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class WhenInCondition(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : WhenCondition(expr, pos) {
|
) : WhenCondition(expr, pos) {
|
||||||
override suspend fun matches(scope: Scope, value: Obj): Boolean {
|
override suspend fun matches(scope: Scope, value: Obj): Boolean {
|
||||||
return interpreterDisabled(scope)
|
return bytecodeOnly(scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class WhenIsCondition(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : WhenCondition(expr, pos) {
|
) : WhenCondition(expr, pos) {
|
||||||
override suspend fun matches(scope: Scope, value: Obj): Boolean {
|
override suspend fun matches(scope: Scope, value: Obj): Boolean {
|
||||||
return interpreterDisabled(scope)
|
return bytecodeOnly(scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +64,6 @@ class WhenStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "when statement")
|
return bytecodeOnly(scope, "when statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1880,13 +1880,23 @@ private suspend fun assignDestructurePattern(frame: CmdFrame, pattern: ListLiter
|
|||||||
|
|
||||||
private suspend fun assignDestructureTarget(frame: CmdFrame, ref: ObjRef, value: Obj, pos: Pos) {
|
private suspend fun assignDestructureTarget(frame: CmdFrame, ref: ObjRef, value: Obj, pos: Pos) {
|
||||||
when (ref) {
|
when (ref) {
|
||||||
is ListLiteralRef -> assignDestructurePattern(frame, ref, value, pos)
|
is ListLiteralRef -> {
|
||||||
|
assignDestructurePattern(frame, ref, value, pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
is LocalSlotRef -> {
|
is LocalSlotRef -> {
|
||||||
val index = resolveLocalSlotIndex(frame.fn, ref.name, preferCapture = ref.captureOwnerScopeId != null)
|
val index = resolveLocalSlotIndex(frame.fn, ref.name, preferCapture = ref.captureOwnerScopeId != null)
|
||||||
if (index != null) {
|
if (index != null) {
|
||||||
frame.frame.setObj(index, value)
|
frame.frame.setObj(index, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val scopeSlot = frame.fn.scopeSlotNames.indexOfFirst { it == ref.name }
|
||||||
|
if (scopeSlot >= 0) {
|
||||||
|
val target = frame.scopeTarget(scopeSlot)
|
||||||
|
val slotIndex = frame.ensureScopeSlot(target, scopeSlot)
|
||||||
|
target.setSlotValue(slotIndex, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is LocalVarRef -> {
|
is LocalVarRef -> {
|
||||||
val index = resolveLocalSlotIndex(frame.fn, ref.name, preferCapture = false)
|
val index = resolveLocalSlotIndex(frame.fn, ref.name, preferCapture = false)
|
||||||
@ -1894,6 +1904,13 @@ private suspend fun assignDestructureTarget(frame: CmdFrame, ref: ObjRef, value:
|
|||||||
frame.frame.setObj(index, value)
|
frame.frame.setObj(index, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val scopeSlot = frame.fn.scopeSlotNames.indexOfFirst { it == ref.name }
|
||||||
|
if (scopeSlot >= 0) {
|
||||||
|
val target = frame.scopeTarget(scopeSlot)
|
||||||
|
val slotIndex = frame.ensureScopeSlot(target, scopeSlot)
|
||||||
|
target.setSlotValue(slotIndex, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is FastLocalVarRef -> {
|
is FastLocalVarRef -> {
|
||||||
val index = resolveLocalSlotIndex(frame.fn, ref.name, preferCapture = false)
|
val index = resolveLocalSlotIndex(frame.fn, ref.name, preferCapture = false)
|
||||||
@ -1901,6 +1918,13 @@ private suspend fun assignDestructureTarget(frame: CmdFrame, ref: ObjRef, value:
|
|||||||
frame.frame.setObj(index, value)
|
frame.frame.setObj(index, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val scopeSlot = frame.fn.scopeSlotNames.indexOfFirst { it == ref.name }
|
||||||
|
if (scopeSlot >= 0) {
|
||||||
|
val target = frame.scopeTarget(scopeSlot)
|
||||||
|
val slotIndex = frame.ensureScopeSlot(target, scopeSlot)
|
||||||
|
target.setSlotValue(slotIndex, value)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.miniast
|
|||||||
|
|
||||||
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.Visibility
|
import net.sergeych.lyng.Visibility
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjClass
|
import net.sergeych.lyng.obj.ObjClass
|
||||||
@ -40,7 +41,7 @@ inline fun <reified T : Obj> Scope.addFnDoc(
|
|||||||
tags: Map<String, List<String>> = emptyMap(),
|
tags: Map<String, List<String>> = emptyMap(),
|
||||||
moduleName: String? = null,
|
moduleName: String? = null,
|
||||||
callSignature: net.sergeych.lyng.CallSignature? = null,
|
callSignature: net.sergeych.lyng.CallSignature? = null,
|
||||||
crossinline fn: suspend Scope.() -> T
|
crossinline fn: suspend ScopeFacade.() -> T
|
||||||
) {
|
) {
|
||||||
// Register runtime function(s)
|
// Register runtime function(s)
|
||||||
addFn(*names, callSignature = callSignature) { fn() }
|
addFn(*names, callSignature = callSignature) { fn() }
|
||||||
@ -57,7 +58,7 @@ inline fun Scope.addVoidFnDoc(
|
|||||||
doc: String,
|
doc: String,
|
||||||
tags: Map<String, List<String>> = emptyMap(),
|
tags: Map<String, List<String>> = emptyMap(),
|
||||||
moduleName: String? = null,
|
moduleName: String? = null,
|
||||||
crossinline fn: suspend Scope.() -> Unit
|
crossinline fn: suspend ScopeFacade.() -> Unit
|
||||||
) {
|
) {
|
||||||
addFnDoc<ObjVoid>(
|
addFnDoc<ObjVoid>(
|
||||||
*names,
|
*names,
|
||||||
@ -98,7 +99,7 @@ fun ObjClass.addFnDoc(
|
|||||||
visibility: Visibility = Visibility.Public,
|
visibility: Visibility = Visibility.Public,
|
||||||
tags: Map<String, List<String>> = emptyMap(),
|
tags: Map<String, List<String>> = emptyMap(),
|
||||||
moduleName: String? = null,
|
moduleName: String? = null,
|
||||||
code: suspend Scope.() -> Obj
|
code: suspend ScopeFacade.() -> Obj
|
||||||
) {
|
) {
|
||||||
// Register runtime method
|
// Register runtime method
|
||||||
addFn(name, isOpen, visibility, code = code)
|
addFn(name, isOpen, visibility, code = code)
|
||||||
@ -136,7 +137,7 @@ fun ObjClass.addClassFnDoc(
|
|||||||
isOpen: Boolean = false,
|
isOpen: Boolean = false,
|
||||||
tags: Map<String, List<String>> = emptyMap(),
|
tags: Map<String, List<String>> = emptyMap(),
|
||||||
moduleName: String? = null,
|
moduleName: String? = null,
|
||||||
code: suspend Scope.() -> Obj
|
code: suspend ScopeFacade.() -> Obj
|
||||||
) {
|
) {
|
||||||
addClassFn(name, isOpen, code)
|
addClassFn(name, isOpen, code)
|
||||||
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
||||||
@ -152,8 +153,8 @@ fun ObjClass.addPropertyDoc(
|
|||||||
type: TypeDoc? = null,
|
type: TypeDoc? = null,
|
||||||
visibility: Visibility = Visibility.Public,
|
visibility: Visibility = Visibility.Public,
|
||||||
moduleName: String? = null,
|
moduleName: String? = null,
|
||||||
getter: (suspend Scope.() -> Obj)? = null,
|
getter: (suspend ScopeFacade.() -> Obj)? = null,
|
||||||
setter: (suspend Scope.(Obj) -> Unit)? = null
|
setter: (suspend ScopeFacade.(Obj) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
addProperty(name, getter, setter, visibility)
|
addProperty(name, getter, setter, visibility)
|
||||||
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
||||||
|
|||||||
@ -20,7 +20,6 @@ package net.sergeych.lyng.obj
|
|||||||
import net.sergeych.lyng.Compiler
|
import net.sergeych.lyng.Compiler
|
||||||
import net.sergeych.lyng.Pos
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.ScriptError
|
|
||||||
|
|
||||||
// avoid KDOC bug: keep it
|
// avoid KDOC bug: keep it
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@ -37,10 +36,11 @@ private class LambdaRef(
|
|||||||
private val getterFn: suspend (Scope) -> ObjRecord,
|
private val getterFn: suspend (Scope) -> ObjRecord,
|
||||||
private val setterFn: (suspend (Pos, Scope, Obj) -> Unit)? = null
|
private val setterFn: (suspend (Pos, Scope, Obj) -> Unit)? = null
|
||||||
) : ObjRef {
|
) : ObjRef {
|
||||||
override suspend fun get(scope: Scope): ObjRecord = getterFn(scope)
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
|
return scope.raiseIllegalState("bytecode-only execution is required; Accessor evaluation is disabled")
|
||||||
|
}
|
||||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||||
val s = setterFn ?: throw ScriptError(pos, "can't assign value")
|
scope.raiseIllegalState("bytecode-only execution is required; Accessor assignment is disabled")
|
||||||
s(pos, scope, newValue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -562,10 +562,10 @@ open class Obj {
|
|||||||
else -> del.objClass.getInstanceMemberOrNull("getValue")
|
else -> del.objClass.getInstanceMemberOrNull("getValue")
|
||||||
}
|
}
|
||||||
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
||||||
val wrapper = ObjNativeCallable {
|
val wrapper = ObjExternCallable.fromBridge {
|
||||||
val th2 = if (thisObj === ObjVoid) ObjNull else thisObj
|
val th2 = if (thisObj === ObjVoid) ObjNull else thisObj
|
||||||
val allArgs = (listOf(th2, ObjString(name)) + args.list).toTypedArray()
|
val allArgs = (listOf(th2, ObjString(name)) + args.list).toTypedArray()
|
||||||
del.invokeInstanceMethod(this, "invoke", Arguments(*allArgs))
|
del.invokeInstanceMethod(requireScope(), "invoke", Arguments(*allArgs))
|
||||||
}
|
}
|
||||||
return obj.copy(
|
return obj.copy(
|
||||||
value = wrapper,
|
value = wrapper,
|
||||||
@ -740,7 +740,7 @@ open class Obj {
|
|||||||
returns = type("lyng.String"),
|
returns = type("lyng.String"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisObj.toString(this, true)
|
toStringOf(thisObj, true)
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "inspect",
|
name = "inspect",
|
||||||
@ -748,7 +748,7 @@ open class Obj {
|
|||||||
returns = type("lyng.String"),
|
returns = type("lyng.String"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisObj.inspect(this).toObj()
|
inspect(thisObj).toObj()
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "contains",
|
name = "contains",
|
||||||
@ -757,7 +757,7 @@ open class Obj {
|
|||||||
returns = type("lyng.Bool"),
|
returns = type("lyng.Bool"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
ObjBool(thisObj.contains(this, args.firstAndOnly()))
|
ObjBool(thisObj.contains(requireScope(), args.firstAndOnly()))
|
||||||
}
|
}
|
||||||
// utilities
|
// utilities
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
@ -766,7 +766,7 @@ open class Obj {
|
|||||||
params = listOf(ParamDoc("block")),
|
params = listOf(ParamDoc("block")),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
args.firstAndOnly().callOn(createChildScope(Arguments(thisObj)))
|
call(args.firstAndOnly(), Arguments(thisObj))
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "apply",
|
name = "apply",
|
||||||
@ -775,11 +775,12 @@ open class Obj {
|
|||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val body = args.firstAndOnly()
|
val body = args.firstAndOnly()
|
||||||
|
val scope = requireScope()
|
||||||
(thisObj as? ObjInstance)?.let {
|
(thisObj as? ObjInstance)?.let {
|
||||||
body.callOn(ApplyScope(this, it.instanceScope))
|
body.callOn(ApplyScope(scope, it.instanceScope))
|
||||||
} ?: run {
|
} ?: run {
|
||||||
val appliedScope = createChildScope(newThisObj = thisObj)
|
val appliedScope = scope.createChildScope(newThisObj = thisObj)
|
||||||
body.callOn(ApplyScope(this, appliedScope))
|
body.callOn(ApplyScope(scope, appliedScope))
|
||||||
}
|
}
|
||||||
thisObj
|
thisObj
|
||||||
}
|
}
|
||||||
@ -789,7 +790,7 @@ open class Obj {
|
|||||||
params = listOf(ParamDoc("block")),
|
params = listOf(ParamDoc("block")),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
args.firstAndOnly().callOn(createChildScope(Arguments(thisObj)))
|
call(args.firstAndOnly(), Arguments(thisObj))
|
||||||
thisObj
|
thisObj
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
@ -798,16 +799,16 @@ open class Obj {
|
|||||||
params = listOf(ParamDoc("block")),
|
params = listOf(ParamDoc("block")),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
args.firstAndOnly().callOn(this)
|
call(args.firstAndOnly())
|
||||||
}
|
}
|
||||||
addFn("getAt") {
|
addFn("getAt") {
|
||||||
requireExactCount(1)
|
requireExactCount(1)
|
||||||
thisObj.getAt(this, requiredArg<Obj>(0))
|
thisObj.getAt(requireScope(), requiredArg<Obj>(0))
|
||||||
}
|
}
|
||||||
addFn("putAt") {
|
addFn("putAt") {
|
||||||
requireExactCount(2)
|
requireExactCount(2)
|
||||||
val newValue = args[1]
|
val newValue = args[1]
|
||||||
thisObj.putAt(this, requiredArg<Obj>(0), newValue)
|
thisObj.putAt(requireScope(), requiredArg<Obj>(0), newValue)
|
||||||
newValue
|
newValue
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
@ -816,7 +817,7 @@ open class Obj {
|
|||||||
returns = type("lyng.String"),
|
returns = type("lyng.String"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisObj.toJson(this).toString().toObj()
|
thisObj.toJson(requireScope()).toString().toObj()
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "toJsonString",
|
name = "toJsonString",
|
||||||
@ -824,7 +825,7 @@ open class Obj {
|
|||||||
returns = type("lyng.String"),
|
returns = type("lyng.String"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisObj.toJson(this).toString().toObj()
|
thisObj.toJson(requireScope()).toString().toObj()
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "clamp",
|
name = "clamp",
|
||||||
@ -836,12 +837,12 @@ open class Obj {
|
|||||||
|
|
||||||
var result = thisObj
|
var result = thisObj
|
||||||
if (range.start != null && !range.start.isNull) {
|
if (range.start != null && !range.start.isNull) {
|
||||||
if (result.compareTo(this, range.start) < 0) {
|
if (result.compareTo(requireScope(), range.start) < 0) {
|
||||||
result = range.start
|
result = range.start
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (range.end != null && !range.end.isNull) {
|
if (range.end != null && !range.end.isNull) {
|
||||||
val cmp = range.end.compareTo(this, result)
|
val cmp = range.end.compareTo(requireScope(), result)
|
||||||
if (range.isEndInclusive) {
|
if (range.isEndInclusive) {
|
||||||
if (cmp < 0) result = range.end
|
if (cmp < 0) result = range.end
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ val ObjArray by lazy {
|
|||||||
doc = "Iterator over elements of this array using its indexer.",
|
doc = "Iterator over elements of this array using its indexer.",
|
||||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) { ObjArrayIterator(thisObj).also { it.init(this) } }
|
) { ObjArrayIterator(thisObj).also { it.init(requireScope()) } }
|
||||||
|
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "contains",
|
name = "contains",
|
||||||
@ -42,9 +42,10 @@ val ObjArray by lazy {
|
|||||||
isOpen = true,
|
isOpen = true,
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
|
val scope = requireScope()
|
||||||
val obj = args.firstAndOnly()
|
val obj = args.firstAndOnly()
|
||||||
for (i in 0..<thisObj.invokeInstanceMethod(this, "size").toInt()) {
|
for (i in 0..<thisObj.invokeInstanceMethod(scope, "size").toInt()) {
|
||||||
if (thisObj.getAt(this, ObjInt(i.toLong())).compareTo(this, obj) == 0) return@addFnDoc ObjTrue
|
if (thisObj.getAt(scope, ObjInt(i.toLong())).compareTo(scope, obj) == 0) return@addFnDoc ObjTrue
|
||||||
}
|
}
|
||||||
ObjFalse
|
ObjFalse
|
||||||
}
|
}
|
||||||
@ -55,10 +56,11 @@ val ObjArray by lazy {
|
|||||||
type = type("lyng.Any"),
|
type = type("lyng.Any"),
|
||||||
moduleName = "lyng.stdlib",
|
moduleName = "lyng.stdlib",
|
||||||
getter = {
|
getter = {
|
||||||
|
val scope = requireScope()
|
||||||
this.thisObj.invokeInstanceMethod(
|
this.thisObj.invokeInstanceMethod(
|
||||||
this,
|
scope,
|
||||||
"getAt",
|
"getAt",
|
||||||
(this.thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj()
|
(this.thisObj.invokeInstanceMethod(scope, "size").toInt() - 1).toObj()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -68,7 +70,10 @@ val ObjArray by lazy {
|
|||||||
doc = "Index of the last element (size - 1).",
|
doc = "Index of the last element (size - 1).",
|
||||||
type = type("lyng.Int"),
|
type = type("lyng.Int"),
|
||||||
moduleName = "lyng.stdlib",
|
moduleName = "lyng.stdlib",
|
||||||
getter = { (this.thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj() }
|
getter = {
|
||||||
|
val scope = requireScope()
|
||||||
|
(this.thisObj.invokeInstanceMethod(scope, "size").toInt() - 1).toObj()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
addPropertyDoc(
|
addPropertyDoc(
|
||||||
@ -76,7 +81,10 @@ val ObjArray by lazy {
|
|||||||
doc = "Range of valid indices for this array.",
|
doc = "Range of valid indices for this array.",
|
||||||
type = type("lyng.Range"),
|
type = type("lyng.Range"),
|
||||||
moduleName = "lyng.stdlib",
|
moduleName = "lyng.stdlib",
|
||||||
getter = { ObjRange(0.toObj(), this.thisObj.invokeInstanceMethod(this, "size"), false) }
|
getter = {
|
||||||
|
val scope = requireScope()
|
||||||
|
ObjRange(0.toObj(), this.thisObj.invokeInstanceMethod(scope, "size"), false)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
@ -86,15 +94,16 @@ val ObjArray by lazy {
|
|||||||
returns = type("lyng.Int"),
|
returns = type("lyng.Int"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
|
val scope = requireScope()
|
||||||
val target = args.firstAndOnly()
|
val target = args.firstAndOnly()
|
||||||
var low = 0
|
var low = 0
|
||||||
var high = thisObj.invokeInstanceMethod(this, "size").toInt() - 1
|
var high = thisObj.invokeInstanceMethod(scope, "size").toInt() - 1
|
||||||
|
|
||||||
while (low <= high) {
|
while (low <= high) {
|
||||||
val mid = (low + high) / 2
|
val mid = (low + high) / 2
|
||||||
val midVal = thisObj.getAt(this, ObjInt(mid.toLong()))
|
val midVal = thisObj.getAt(scope, ObjInt(mid.toLong()))
|
||||||
|
|
||||||
val cmp = midVal.compareTo(this, target)
|
val cmp = midVal.compareTo(scope, target)
|
||||||
when {
|
when {
|
||||||
cmp == 0 -> return@addFnDoc (mid).toObj()
|
cmp == 0 -> return@addFnDoc (mid).toObj()
|
||||||
cmp > 0 -> high = mid - 1
|
cmp > 0 -> high = mid - 1
|
||||||
|
|||||||
@ -38,8 +38,8 @@ class ObjArrayIterator(val array: Obj) : Obj() {
|
|||||||
addFn("next") {
|
addFn("next") {
|
||||||
val self = thisAs<ObjArrayIterator>()
|
val self = thisAs<ObjArrayIterator>()
|
||||||
if (self.nextIndex < self.lastIndex) {
|
if (self.nextIndex < self.lastIndex) {
|
||||||
self.array.invokeInstanceMethod(this, "getAt", (self.nextIndex++).toObj())
|
self.array.invokeInstanceMethod(requireScope(), "getAt", (self.nextIndex++).toObj())
|
||||||
} else raiseError(ObjIterationFinishedException(this))
|
} else raiseError(ObjIterationFinishedException(requireScope()))
|
||||||
}
|
}
|
||||||
addFn("hasNext") {
|
addFn("hasNext") {
|
||||||
val self = thisAs<ObjArrayIterator>()
|
val self = thisAs<ObjArrayIterator>()
|
||||||
|
|||||||
@ -930,9 +930,9 @@ open class ObjClass(
|
|||||||
isOverride: Boolean = false,
|
isOverride: Boolean = false,
|
||||||
pos: Pos = Pos.builtIn,
|
pos: Pos = Pos.builtIn,
|
||||||
methodId: Int? = null,
|
methodId: Int? = null,
|
||||||
code: (suspend Scope.() -> Obj)? = null
|
code: (suspend net.sergeych.lyng.ScopeFacade.() -> Obj)? = null
|
||||||
) {
|
) {
|
||||||
val stmt = code?.let { ObjNativeCallable { it() } } ?: ObjNull
|
val stmt = code?.let { ObjExternCallable.fromBridge { it() } } ?: ObjNull
|
||||||
createField(
|
createField(
|
||||||
name, stmt, isMutable, visibility, writeVisibility, pos, declaringClass,
|
name, stmt, isMutable, visibility, writeVisibility, pos, declaringClass,
|
||||||
isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride,
|
isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride,
|
||||||
@ -945,8 +945,8 @@ open class ObjClass(
|
|||||||
|
|
||||||
fun addProperty(
|
fun addProperty(
|
||||||
name: String,
|
name: String,
|
||||||
getter: (suspend Scope.() -> Obj)? = null,
|
getter: (suspend net.sergeych.lyng.ScopeFacade.() -> Obj)? = null,
|
||||||
setter: (suspend Scope.(Obj) -> Unit)? = null,
|
setter: (suspend net.sergeych.lyng.ScopeFacade.(Obj) -> Unit)? = null,
|
||||||
visibility: Visibility = Visibility.Public,
|
visibility: Visibility = Visibility.Public,
|
||||||
writeVisibility: Visibility? = null,
|
writeVisibility: Visibility? = null,
|
||||||
declaringClass: ObjClass? = this,
|
declaringClass: ObjClass? = this,
|
||||||
@ -957,8 +957,8 @@ open class ObjClass(
|
|||||||
prop: ObjProperty? = null,
|
prop: ObjProperty? = null,
|
||||||
methodId: Int? = null
|
methodId: Int? = null
|
||||||
) {
|
) {
|
||||||
val g = getter?.let { ObjNativeCallable { it() } }
|
val g = getter?.let { ObjExternCallable.fromBridge { it() } }
|
||||||
val s = setter?.let { ObjNativeCallable { it(requiredArg(0)); ObjVoid } }
|
val s = setter?.let { ObjExternCallable.fromBridge { it(requiredArg(0)); ObjVoid } }
|
||||||
val finalProp = prop ?: if (isAbstract) ObjNull else ObjProperty(name, g, s)
|
val finalProp = prop ?: if (isAbstract) ObjNull else ObjProperty(name, g, s)
|
||||||
createField(
|
createField(
|
||||||
name, finalProp, false, visibility, writeVisibility, pos, declaringClass,
|
name, finalProp, false, visibility, writeVisibility, pos, declaringClass,
|
||||||
@ -969,8 +969,8 @@ open class ObjClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addClassConst(name: String, value: Obj) = createClassField(name, value)
|
fun addClassConst(name: String, value: Obj) = createClassField(name, value)
|
||||||
fun addClassFn(name: String, isOpen: Boolean = false, code: suspend Scope.() -> Obj) {
|
fun addClassFn(name: String, isOpen: Boolean = false, code: suspend net.sergeych.lyng.ScopeFacade.() -> Obj) {
|
||||||
createClassField(name, ObjNativeCallable { code() }, isOpen, type = ObjRecord.Type.Fun)
|
createClassField(name, ObjExternCallable.fromBridge { code() }, isOpen, type = ObjRecord.Type.Fun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -53,9 +53,8 @@ class ObjDateTime(val instant: Instant, val timeZone: TimeZone) : Obj() {
|
|||||||
if (rec.type == ObjRecord.Type.Fun) {
|
if (rec.type == ObjRecord.Type.Fun) {
|
||||||
val target = rec.value
|
val target = rec.value
|
||||||
return ObjRecord(
|
return ObjRecord(
|
||||||
ObjNativeCallable {
|
ObjExternCallable.fromBridge {
|
||||||
val callScope = createChildScope(args = args, newThisObj = this@ObjDateTime)
|
call(target, args, newThisObj = this@ObjDateTime)
|
||||||
target.callOn(callScope)
|
|
||||||
},
|
},
|
||||||
rec.isMutable
|
rec.isMutable
|
||||||
)
|
)
|
||||||
|
|||||||
@ -139,7 +139,7 @@ open class ObjException(
|
|||||||
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
||||||
init {
|
init {
|
||||||
constructorMeta = ArgsDeclaration(
|
constructorMeta = ArgsDeclaration(
|
||||||
listOf(ArgsDeclaration.Item("message", defaultValue = ObjNativeCallable { ObjString(name) })),
|
listOf(ArgsDeclaration.Item("message", defaultValue = ObjExternCallable.fromBridge { ObjString(name) })),
|
||||||
Token.Type.RPAREN
|
Token.Type.RPAREN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -177,17 +177,17 @@ open class ObjException(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val Root = ExceptionClass("Exception").apply {
|
val Root = ExceptionClass("Exception").apply {
|
||||||
instanceInitializers.add(ObjNativeCallable {
|
instanceInitializers.add(ObjExternCallable.fromBridge {
|
||||||
if (thisObj is ObjInstance) {
|
if (thisObj is ObjInstance) {
|
||||||
val msg = get("message")?.value ?: ObjString("Exception")
|
val msg = get("message")?.value ?: ObjString("Exception")
|
||||||
(thisObj as ObjInstance).instanceScope.addItem("Exception::message", false, msg)
|
(thisObj as ObjInstance).instanceScope.addItem("Exception::message", false, msg)
|
||||||
|
|
||||||
val stack = captureStackTrace(this)
|
val stack = captureStackTrace(requireScope())
|
||||||
(thisObj as ObjInstance).instanceScope.addItem("Exception::stackTrace", false, stack)
|
(thisObj as ObjInstance).instanceScope.addItem("Exception::stackTrace", false, stack)
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
})
|
})
|
||||||
instanceConstructor = ObjNativeCallable { ObjVoid }
|
instanceConstructor = ObjExternCallable.fromBridge { ObjVoid }
|
||||||
addPropertyDoc(
|
addPropertyDoc(
|
||||||
name = "message",
|
name = "message",
|
||||||
doc = "Human‑readable error message.",
|
doc = "Human‑readable error message.",
|
||||||
@ -244,7 +244,7 @@ open class ObjException(
|
|||||||
is ObjInstance -> t.instanceScope.get("Exception::stackTrace")?.value as? ObjList ?: ObjList()
|
is ObjInstance -> t.instanceScope.get("Exception::stackTrace")?.value as? ObjList ?: ObjList()
|
||||||
else -> ObjList()
|
else -> ObjList()
|
||||||
}
|
}
|
||||||
val at = stack.list.firstOrNull()?.toString(this) ?: ObjString("(unknown)")
|
val at = stack.list.firstOrNull()?.let { toStringOf(it) } ?: ObjString("(unknown)")
|
||||||
ObjString("${thisObj.objClass.className}: $msg at $at")
|
ObjString("${thisObj.objClass.className}: $msg at $at")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,8 +106,8 @@ class ObjFlow(val producer: Obj, val scope: Scope) : Obj() {
|
|||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val objFlow = thisAs<ObjFlow>()
|
val objFlow = thisAs<ObjFlow>()
|
||||||
ObjFlowIterator(ObjNativeCallable {
|
ObjFlowIterator(ObjExternCallable.fromBridge {
|
||||||
objFlow.producer.callOn(this)
|
call(objFlow.producer)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ class ObjFlowIterator(val producer: Obj) : Obj() {
|
|||||||
doc = "Whether another element is available from the flow.",
|
doc = "Whether another element is available from the flow.",
|
||||||
returns = type("lyng.Bool"),
|
returns = type("lyng.Bool"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) { thisAs<ObjFlowIterator>().hasNext(this).toObj() }
|
) { thisAs<ObjFlowIterator>().hasNext(requireScope()).toObj() }
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "next",
|
name = "next",
|
||||||
doc = "Receive the next element from the flow or throw if completed.",
|
doc = "Receive the next element from the flow or throw if completed.",
|
||||||
@ -172,7 +172,7 @@ class ObjFlowIterator(val producer: Obj) : Obj() {
|
|||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val x = thisAs<ObjFlowIterator>()
|
val x = thisAs<ObjFlowIterator>()
|
||||||
x.next(this)
|
x.next(requireScope())
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "cancelIteration",
|
name = "cancelIteration",
|
||||||
|
|||||||
@ -177,10 +177,10 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
else -> del.objClass.getInstanceMemberOrNull("getValue")
|
else -> del.objClass.getInstanceMemberOrNull("getValue")
|
||||||
}
|
}
|
||||||
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
||||||
val wrapper = ObjNativeCallable {
|
val wrapper = ObjExternCallable.fromBridge {
|
||||||
val th2 = if (thisObj === ObjVoid) ObjNull else thisObj
|
val th2 = if (thisObj === ObjVoid) ObjNull else thisObj
|
||||||
val allArgs = (listOf(th2, ObjString(name)) + args.list).toTypedArray()
|
val allArgs = (listOf(th2, ObjString(name)) + args.list).toTypedArray()
|
||||||
del.invokeInstanceMethod(this, "invoke", Arguments(*allArgs))
|
del.invokeInstanceMethod(requireScope(), "invoke", Arguments(*allArgs))
|
||||||
}
|
}
|
||||||
return obj.copy(value = wrapper, type = ObjRecord.Type.Other)
|
return obj.copy(value = wrapper, type = ObjRecord.Type.Other)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,10 +41,11 @@ val ObjIterable by lazy {
|
|||||||
returns = type("lyng.List"),
|
returns = type("lyng.List"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
|
val scope = requireScope()
|
||||||
val result = mutableListOf<Obj>()
|
val result = mutableListOf<Obj>()
|
||||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
val it = thisObj.invokeInstanceMethod(scope, "iterator")
|
||||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
while (it.invokeInstanceMethod(scope, "hasNext").toBool()) {
|
||||||
result.add(it.invokeInstanceMethod(this, "next"))
|
result.add(it.invokeInstanceMethod(scope, "next"))
|
||||||
}
|
}
|
||||||
ObjList(result)
|
ObjList(result)
|
||||||
}
|
}
|
||||||
@ -58,10 +59,11 @@ val ObjIterable by lazy {
|
|||||||
isOpen = true,
|
isOpen = true,
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
|
val scope = requireScope()
|
||||||
val obj = args.firstAndOnly()
|
val obj = args.firstAndOnly()
|
||||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
val it = thisObj.invokeInstanceMethod(scope, "iterator")
|
||||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
while (it.invokeInstanceMethod(scope, "hasNext").toBool()) {
|
||||||
if (obj.equals(this, it.invokeInstanceMethod(this, "next")))
|
if (obj.equals(scope, it.invokeInstanceMethod(scope, "next")))
|
||||||
return@addFnDoc ObjTrue
|
return@addFnDoc ObjTrue
|
||||||
}
|
}
|
||||||
ObjFalse
|
ObjFalse
|
||||||
@ -75,11 +77,12 @@ val ObjIterable by lazy {
|
|||||||
isOpen = true,
|
isOpen = true,
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
|
val scope = requireScope()
|
||||||
val obj = args.firstAndOnly()
|
val obj = args.firstAndOnly()
|
||||||
var index = 0
|
var index = 0
|
||||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
val it = thisObj.invokeInstanceMethod(scope, "iterator")
|
||||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
while (it.invokeInstanceMethod(scope, "hasNext").toBool()) {
|
||||||
if (obj.equals(this, it.invokeInstanceMethod(this, "next")))
|
if (obj.equals(scope, it.invokeInstanceMethod(scope, "next")))
|
||||||
return@addFnDoc ObjInt(index.toLong())
|
return@addFnDoc ObjInt(index.toLong())
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
@ -96,9 +99,10 @@ val ObjIterable by lazy {
|
|||||||
this.thisObj
|
this.thisObj
|
||||||
else {
|
else {
|
||||||
val result = mutableSetOf<Obj>()
|
val result = mutableSetOf<Obj>()
|
||||||
val it = this.thisObj.invokeInstanceMethod(this, "iterator")
|
val scope = requireScope()
|
||||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
val it = this.thisObj.invokeInstanceMethod(scope, "iterator")
|
||||||
result.add(it.invokeInstanceMethod(this, "next"))
|
while (it.invokeInstanceMethod(scope, "hasNext").toBool()) {
|
||||||
|
result.add(it.invokeInstanceMethod(scope, "next"))
|
||||||
}
|
}
|
||||||
ObjSet(result)
|
ObjSet(result)
|
||||||
}
|
}
|
||||||
@ -112,10 +116,11 @@ val ObjIterable by lazy {
|
|||||||
moduleName = "lyng.stdlib",
|
moduleName = "lyng.stdlib",
|
||||||
getter = {
|
getter = {
|
||||||
val result = mutableMapOf<Obj, Obj>()
|
val result = mutableMapOf<Obj, Obj>()
|
||||||
this.thisObj.enumerate(this) { pair ->
|
val scope = requireScope()
|
||||||
|
this.thisObj.enumerate(scope) { pair ->
|
||||||
when (pair) {
|
when (pair) {
|
||||||
is ObjMapEntry -> result[pair.key] = pair.value
|
is ObjMapEntry -> result[pair.key] = pair.value
|
||||||
else -> result[pair.getAt(this, 0)] = pair.getAt(this, 1)
|
else -> result[pair.getAt(scope, 0)] = pair.getAt(scope, 1)
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -132,9 +137,8 @@ val ObjIterable by lazy {
|
|||||||
) {
|
) {
|
||||||
val association = requireOnlyArg<Obj>()
|
val association = requireOnlyArg<Obj>()
|
||||||
val result = ObjMap()
|
val result = ObjMap()
|
||||||
thisObj.toFlow(this).collect {
|
thisObj.toFlow(requireScope()).collect {
|
||||||
val callScope = createChildScope(args = Arguments(it))
|
result.map[call(association, Arguments(it))] = it
|
||||||
result.map[association.callOn(callScope)] = it
|
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -146,11 +150,12 @@ val ObjIterable by lazy {
|
|||||||
isOpen = true,
|
isOpen = true,
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
val scope = requireScope()
|
||||||
|
val it = thisObj.invokeInstanceMethod(scope, "iterator")
|
||||||
val fn = requiredArg<Obj>(0)
|
val fn = requiredArg<Obj>(0)
|
||||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
while (it.invokeInstanceMethod(scope, "hasNext").toBool()) {
|
||||||
val x = it.invokeInstanceMethod(this, "next")
|
val x = it.invokeInstanceMethod(scope, "next")
|
||||||
fn.callOn(this.createChildScope(Arguments(listOf(x))))
|
call(fn, Arguments(listOf(x)))
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
@ -165,9 +170,8 @@ val ObjIterable by lazy {
|
|||||||
) {
|
) {
|
||||||
val fn = requiredArg<Obj>(0)
|
val fn = requiredArg<Obj>(0)
|
||||||
val result = mutableListOf<Obj>()
|
val result = mutableListOf<Obj>()
|
||||||
thisObj.toFlow(this).collect {
|
thisObj.toFlow(requireScope()).collect {
|
||||||
val callScope = createChildScope(args = Arguments(it))
|
result.add(call(fn, Arguments(it)))
|
||||||
result.add(fn.callOn(callScope))
|
|
||||||
}
|
}
|
||||||
ObjList(result)
|
ObjList(result)
|
||||||
}
|
}
|
||||||
@ -182,9 +186,8 @@ val ObjIterable by lazy {
|
|||||||
) {
|
) {
|
||||||
val fn = requiredArg<Obj>(0)
|
val fn = requiredArg<Obj>(0)
|
||||||
val result = mutableListOf<Obj>()
|
val result = mutableListOf<Obj>()
|
||||||
thisObj.toFlow(this).collect {
|
thisObj.toFlow(requireScope()).collect {
|
||||||
val callScope = createChildScope(args = Arguments(it))
|
val transformed = call(fn, Arguments(it))
|
||||||
val transformed = fn.callOn(callScope)
|
|
||||||
if( transformed != ObjNull) result.add(transformed)
|
if( transformed != ObjNull) result.add(transformed)
|
||||||
}
|
}
|
||||||
ObjList(result)
|
ObjList(result)
|
||||||
@ -200,7 +203,7 @@ val ObjIterable by lazy {
|
|||||||
var n = requireOnlyArg<ObjInt>().value.toInt()
|
var n = requireOnlyArg<ObjInt>().value.toInt()
|
||||||
val result = mutableListOf<Obj>()
|
val result = mutableListOf<Obj>()
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
thisObj.enumerate(this) {
|
thisObj.enumerate(requireScope()) {
|
||||||
result.add(it)
|
result.add(it)
|
||||||
--n > 0
|
--n > 0
|
||||||
}
|
}
|
||||||
@ -215,8 +218,8 @@ val ObjIterable by lazy {
|
|||||||
moduleName = "lyng.stdlib",
|
moduleName = "lyng.stdlib",
|
||||||
getter = {
|
getter = {
|
||||||
ObjBool(
|
ObjBool(
|
||||||
this.thisObj.invokeInstanceMethod(this, "iterator")
|
this.thisObj.invokeInstanceMethod(requireScope(), "iterator")
|
||||||
.invokeInstanceMethod(this, "hasNext").toBool()
|
.invokeInstanceMethod(requireScope(), "hasNext").toBool()
|
||||||
.not()
|
.not()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -229,11 +232,10 @@ val ObjIterable by lazy {
|
|||||||
returns = type("lyng.List"),
|
returns = type("lyng.List"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val list = thisObj.callMethod<ObjList>(this, "toList")
|
val list = thisObj.callMethod<ObjList>(requireScope(), "toList")
|
||||||
val comparator = requireOnlyArg<Obj>()
|
val comparator = requireOnlyArg<Obj>()
|
||||||
list.quicksort { a, b ->
|
list.quicksort { a, b ->
|
||||||
val callScope = createChildScope(args = Arguments(a, b))
|
call(comparator, Arguments(a, b)).toInt()
|
||||||
comparator.callOn(callScope).toInt()
|
|
||||||
}
|
}
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
@ -244,7 +246,7 @@ val ObjIterable by lazy {
|
|||||||
returns = type("lyng.List"),
|
returns = type("lyng.List"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val list = thisObj.callMethod<ObjList>(this, "toList")
|
val list = thisObj.callMethod<ObjList>(requireScope(), "toList")
|
||||||
list.list.reverse()
|
list.list.reverse()
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,13 +69,12 @@ val ObjIterator by lazy {
|
|||||||
) {
|
) {
|
||||||
val out = mutableListOf<Obj>()
|
val out = mutableListOf<Obj>()
|
||||||
while (true) {
|
while (true) {
|
||||||
val has = thisObj.invokeInstanceMethod(this, "hasNext").toBool()
|
val has = thisObj.invokeInstanceMethod(requireScope(), "hasNext").toBool()
|
||||||
if (!has) break
|
if (!has) break
|
||||||
val v = thisObj.invokeInstanceMethod(this, "next")
|
val v = thisObj.invokeInstanceMethod(requireScope(), "next")
|
||||||
out += v
|
out += v
|
||||||
}
|
}
|
||||||
ObjList(out.toMutableList())
|
ObjList(out.toMutableList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -373,8 +373,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
) {
|
) {
|
||||||
val comparator = requireOnlyArg<Obj>()
|
val comparator = requireOnlyArg<Obj>()
|
||||||
thisAs<ObjList>().quicksort { a, b ->
|
thisAs<ObjList>().quicksort { a, b ->
|
||||||
val callScope = createChildScope(args = Arguments(a, b))
|
call(comparator, Arguments(a, b)).toInt()
|
||||||
comparator.callOn(callScope).toInt()
|
|
||||||
}
|
}
|
||||||
ObjVoid
|
ObjVoid
|
||||||
}
|
}
|
||||||
@ -394,6 +393,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
val self = thisAs<ObjList>()
|
val self = thisAs<ObjList>()
|
||||||
val l = self.list
|
val l = self.list
|
||||||
if (l.isEmpty()) return@addFnDoc ObjNull
|
if (l.isEmpty()) return@addFnDoc ObjNull
|
||||||
|
val scope = requireScope()
|
||||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||||
// Fast path: all ints → accumulate as long
|
// Fast path: all ints → accumulate as long
|
||||||
var i = 0
|
var i = 0
|
||||||
@ -407,7 +407,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
// Fallback to generic dynamic '+' accumulation starting from current acc
|
// Fallback to generic dynamic '+' accumulation starting from current acc
|
||||||
var res: Obj = ObjInt(acc)
|
var res: Obj = ObjInt(acc)
|
||||||
while (i < l.size) {
|
while (i < l.size) {
|
||||||
res = res.plus(this, l[i])
|
res = res.plus(scope, l[i])
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return@addFnDoc res
|
return@addFnDoc res
|
||||||
@ -419,7 +419,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
var res: Obj = l[0]
|
var res: Obj = l[0]
|
||||||
var k = 1
|
var k = 1
|
||||||
while (k < l.size) {
|
while (k < l.size) {
|
||||||
res = res.plus(this, l[k])
|
res = res.plus(scope, l[k])
|
||||||
k++
|
k++
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
@ -431,6 +431,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
) {
|
) {
|
||||||
val l = thisAs<ObjList>().list
|
val l = thisAs<ObjList>().list
|
||||||
if (l.isEmpty()) return@addFnDoc ObjNull
|
if (l.isEmpty()) return@addFnDoc ObjNull
|
||||||
|
val scope = requireScope()
|
||||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||||
var i = 0
|
var i = 0
|
||||||
var hasOnlyInts = true
|
var hasOnlyInts = true
|
||||||
@ -451,7 +452,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
var i = 1
|
var i = 1
|
||||||
while (i < l.size) {
|
while (i < l.size) {
|
||||||
val v = l[i]
|
val v = l[i]
|
||||||
if (v.compareTo(this, res) < 0) res = v
|
if (v.compareTo(scope, res) < 0) res = v
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
@ -463,6 +464,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
) {
|
) {
|
||||||
val l = thisAs<ObjList>().list
|
val l = thisAs<ObjList>().list
|
||||||
if (l.isEmpty()) return@addFnDoc ObjNull
|
if (l.isEmpty()) return@addFnDoc ObjNull
|
||||||
|
val scope = requireScope()
|
||||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||||
var i = 0
|
var i = 0
|
||||||
var hasOnlyInts = true
|
var hasOnlyInts = true
|
||||||
@ -483,7 +485,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
var i = 1
|
var i = 1
|
||||||
while (i < l.size) {
|
while (i < l.size) {
|
||||||
val v = l[i]
|
val v = l[i]
|
||||||
if (v.compareTo(this, res) > 0) res = v
|
if (v.compareTo(scope, res) > 0) res = v
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
@ -497,6 +499,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
) {
|
) {
|
||||||
val l = thisAs<ObjList>().list
|
val l = thisAs<ObjList>().list
|
||||||
val needle = args.firstAndOnly()
|
val needle = args.firstAndOnly()
|
||||||
|
val scope = requireScope()
|
||||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS && needle is ObjInt) {
|
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS && needle is ObjInt) {
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < l.size) {
|
while (i < l.size) {
|
||||||
@ -508,7 +511,7 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
|||||||
}
|
}
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < l.size) {
|
while (i < l.size) {
|
||||||
if (l[i].compareTo(this, needle) == 0) return@addFnDoc ObjInt(i.toLong())
|
if (l[i].compareTo(scope, needle) == 0) return@addFnDoc ObjInt(i.toLong())
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
ObjInt((-1).toLong())
|
ObjInt((-1).toLong())
|
||||||
|
|||||||
@ -261,7 +261,7 @@ class ObjMap(val map: MutableMap<Obj, Obj> = mutableMapOf()) : Obj() {
|
|||||||
val key = requiredArg<Obj>(0)
|
val key = requiredArg<Obj>(0)
|
||||||
thisAs<ObjMap>().map.getOrPut(key) {
|
thisAs<ObjMap>().map.getOrPut(key) {
|
||||||
val lambda = requiredArg<Obj>(1)
|
val lambda = requiredArg<Obj>(1)
|
||||||
lambda.callOn(this)
|
call(lambda)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addPropertyDoc(
|
addPropertyDoc(
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class ObjMutex(val mutex: Mutex): Obj() {
|
|||||||
// Execute user lambda directly in the current scope to preserve the active scope
|
// Execute user lambda directly in the current scope to preserve the active scope
|
||||||
// ancestry across suspension points. The lambda still constructs a closure scope
|
// ancestry across suspension points. The lambda still constructs a closure scope
|
||||||
// on top of this frame, and parseLambdaExpression sets skipScopeCreation for its body.
|
// on top of this frame, and parseLambdaExpression sets skipScopeCreation for its body.
|
||||||
thisAs<ObjMutex>().mutex.withLock { f.callOn(this) }
|
thisAs<ObjMutex>().mutex.withLock { call(f) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2026 Sergey S. Chernov
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.sergeych.lyng.obj
|
|
||||||
|
|
||||||
import net.sergeych.lyng.Scope
|
|
||||||
import net.sergeych.lyng.Statement
|
|
||||||
|
|
||||||
class ObjNativeCallable(
|
|
||||||
private val fn: suspend Scope.() -> Obj
|
|
||||||
) : Obj() {
|
|
||||||
|
|
||||||
override val objClass: ObjClass
|
|
||||||
get() = Statement.type
|
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj = scope.fn()
|
|
||||||
|
|
||||||
override fun toString(): String = "NativeCallable@${hashCode()}"
|
|
||||||
}
|
|
||||||
@ -270,7 +270,7 @@ class ObjRange(
|
|||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
val self = thisAs<ObjRange>()
|
val self = thisAs<ObjRange>()
|
||||||
self.buildIterator(this)
|
self.buildIterator(requireScope())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,10 +65,10 @@ class ObjRangeIterator(
|
|||||||
companion object {
|
companion object {
|
||||||
val type = ObjClass("RangeIterator", ObjIterator).apply {
|
val type = ObjClass("RangeIterator", ObjIterator).apply {
|
||||||
addFn("hasNext") {
|
addFn("hasNext") {
|
||||||
thisAs<ObjRangeIterator>().hasNext(this).toObj()
|
thisAs<ObjRangeIterator>().hasNext(requireScope()).toObj()
|
||||||
}
|
}
|
||||||
addFn("next") {
|
addFn("next") {
|
||||||
thisAs<ObjRangeIterator>().next(this)
|
thisAs<ObjRangeIterator>().next(requireScope())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ class ObjFastIntRangeIterator(private val start: Int, private val endExclusive:
|
|||||||
companion object {
|
companion object {
|
||||||
val type = ObjClass("FastIntRangeIterator", ObjIterator).apply {
|
val type = ObjClass("FastIntRangeIterator", ObjIterator).apply {
|
||||||
addFn("hasNext") { thisAs<ObjFastIntRangeIterator>().hasNext().toObj() }
|
addFn("hasNext") { thisAs<ObjFastIntRangeIterator>().hasNext().toObj() }
|
||||||
addFn("next") { thisAs<ObjFastIntRangeIterator>().next(this) }
|
addFn("next") { thisAs<ObjFastIntRangeIterator>().next(requireScope()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,7 +125,7 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
|||||||
// roundToInt: number rounded to the nearest integer
|
// roundToInt: number rounded to the nearest integer
|
||||||
addConstDoc(
|
addConstDoc(
|
||||||
name = "roundToInt",
|
name = "roundToInt",
|
||||||
value = ObjNativeCallable {
|
value = ObjExternCallable.fromBridge {
|
||||||
(thisObj as ObjReal).value.roundToLong().toObj()
|
(thisObj as ObjReal).value.roundToLong().toObj()
|
||||||
},
|
},
|
||||||
doc = "This real number rounded to the nearest integer.",
|
doc = "This real number rounded to the nearest integer.",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@ import net.sergeych.lyng.PerfFlags
|
|||||||
import net.sergeych.lyng.Pos
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.RegexCache
|
import net.sergeych.lyng.RegexCache
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
|
import net.sergeych.lyng.requireScope
|
||||||
import net.sergeych.lyng.miniast.*
|
import net.sergeych.lyng.miniast.*
|
||||||
|
|
||||||
class ObjRegex(val regex: Regex) : Obj() {
|
class ObjRegex(val regex: Regex) : Obj() {
|
||||||
@ -75,9 +76,10 @@ class ObjRegex(val regex: Regex) : Obj() {
|
|||||||
}
|
}
|
||||||
createField(
|
createField(
|
||||||
name = "operatorMatch",
|
name = "operatorMatch",
|
||||||
initialValue = ObjNativeCallable {
|
initialValue = ObjExternCallable.fromBridge {
|
||||||
val other = args.firstAndOnly(Pos.builtIn)
|
val other = args.firstAndOnly(Pos.builtIn)
|
||||||
val targetScope = parent ?: this
|
val scope = requireScope()
|
||||||
|
val targetScope = scope.parent ?: scope
|
||||||
(thisObj as ObjRegex).operatorMatch(targetScope, other)
|
(thisObj as ObjRegex).operatorMatch(targetScope, other)
|
||||||
},
|
},
|
||||||
type = ObjRecord.Type.Fun
|
type = ObjRecord.Type.Fun
|
||||||
|
|||||||
@ -175,7 +175,7 @@ class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
|
|||||||
returns = type("lyng.Set"),
|
returns = type("lyng.Set"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisAs<ObjSet>().mul(this, args.firstAndOnly())
|
thisAs<ObjSet>().mul(requireScope(), args.firstAndOnly())
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "iterator",
|
name = "iterator",
|
||||||
@ -192,7 +192,7 @@ class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
|
|||||||
returns = type("lyng.Set"),
|
returns = type("lyng.Set"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisAs<ObjSet>().plus(this, args.firstAndOnly())
|
thisAs<ObjSet>().plus(requireScope(), args.firstAndOnly())
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "subtract",
|
name = "subtract",
|
||||||
@ -201,7 +201,7 @@ class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
|
|||||||
returns = type("lyng.Set"),
|
returns = type("lyng.Set"),
|
||||||
moduleName = "lyng.stdlib"
|
moduleName = "lyng.stdlib"
|
||||||
) {
|
) {
|
||||||
thisAs<ObjSet>().minus(this, args.firstAndOnly())
|
thisAs<ObjSet>().minus(requireScope(), args.firstAndOnly())
|
||||||
}
|
}
|
||||||
addFnDoc(
|
addFnDoc(
|
||||||
name = "remove",
|
name = "remove",
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import net.sergeych.lyng.PerfFlags
|
|||||||
import net.sergeych.lyng.Pos
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.RegexCache
|
import net.sergeych.lyng.RegexCache
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
|
import net.sergeych.lyng.requireScope
|
||||||
import net.sergeych.lyng.miniast.*
|
import net.sergeych.lyng.miniast.*
|
||||||
import net.sergeych.lynon.LynonDecoder
|
import net.sergeych.lynon.LynonDecoder
|
||||||
import net.sergeych.lynon.LynonEncoder
|
import net.sergeych.lynon.LynonEncoder
|
||||||
@ -343,7 +344,7 @@ data class ObjString(val value: String) : Obj() {
|
|||||||
name = "re",
|
name = "re",
|
||||||
initialValue = ObjProperty(
|
initialValue = ObjProperty(
|
||||||
name = "re",
|
name = "re",
|
||||||
getter = ObjNativeCallable {
|
getter = ObjExternCallable.fromBridge {
|
||||||
val pattern = (thisObj as ObjString).value
|
val pattern = (thisObj as ObjString).value
|
||||||
val re = if (PerfFlags.REGEX_CACHE) RegexCache.get(pattern) else pattern.toRegex()
|
val re = if (PerfFlags.REGEX_CACHE) RegexCache.get(pattern) else pattern.toRegex()
|
||||||
ObjRegex(re)
|
ObjRegex(re)
|
||||||
@ -354,9 +355,10 @@ data class ObjString(val value: String) : Obj() {
|
|||||||
)
|
)
|
||||||
createField(
|
createField(
|
||||||
name = "operatorMatch",
|
name = "operatorMatch",
|
||||||
initialValue = ObjNativeCallable {
|
initialValue = ObjExternCallable.fromBridge {
|
||||||
val other = args.firstAndOnly(Pos.builtIn)
|
val other = args.firstAndOnly(Pos.builtIn)
|
||||||
val targetScope = parent ?: this
|
val scope = requireScope()
|
||||||
|
val targetScope = scope.parent ?: scope
|
||||||
(thisObj as ObjString).operatorMatch(targetScope, other)
|
(thisObj as ObjString).operatorMatch(targetScope, other)
|
||||||
},
|
},
|
||||||
type = ObjRecord.Type.Fun
|
type = ObjRecord.Type.Fun
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Sergey S. Chernov
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
|
import net.sergeych.lyng.Scope
|
||||||
|
import net.sergeych.lyng.ScopeFacade
|
||||||
|
import net.sergeych.lyng.requireExactCount as coreRequireExactCount
|
||||||
|
import net.sergeych.lyng.requireNoArgs as coreRequireNoArgs
|
||||||
|
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.thisAs as coreThisAs
|
||||||
|
|
||||||
|
inline fun <reified T : Obj> ScopeFacade.requiredArg(index: Int): T = coreRequiredArg(index)
|
||||||
|
|
||||||
|
inline fun <reified T : Obj> ScopeFacade.requireOnlyArg(): T = coreRequireOnlyArg()
|
||||||
|
|
||||||
|
fun ScopeFacade.requireExactCount(count: Int) = coreRequireExactCount(count)
|
||||||
|
|
||||||
|
fun ScopeFacade.requireNoArgs() = coreRequireNoArgs()
|
||||||
|
|
||||||
|
inline fun <reified T : Obj> ScopeFacade.thisAs(): T = coreThisAs()
|
||||||
|
|
||||||
|
internal fun ScopeFacade.requireScope(): Scope = coreRequireScope()
|
||||||
@ -60,8 +60,8 @@ abstract class Statement(
|
|||||||
|
|
||||||
suspend fun call(scope: Scope, vararg args: Obj) = execute(scope.createChildScope(args = Arguments(*args)))
|
suspend fun call(scope: Scope, vararg args: Obj) = execute(scope.createChildScope(args = Arguments(*args)))
|
||||||
|
|
||||||
protected fun interpreterDisabled(scope: Scope, label: String): Nothing {
|
protected fun bytecodeOnly(scope: Scope, label: String): Nothing {
|
||||||
return scope.raiseIllegalState("interpreter execution is not supported; $label requires bytecode")
|
return scope.raiseIllegalState("bytecode-only execution is required; $label needs compiled bytecode")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class IfStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "if statement")
|
return bytecodeOnly(scope, "if statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ class ForInStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "for-in statement")
|
return bytecodeOnly(scope, "for-in statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ class WhileStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "while statement")
|
return bytecodeOnly(scope, "while statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ class DoWhileStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "do-while statement")
|
return bytecodeOnly(scope, "do-while statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ class BreakStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "break statement")
|
return bytecodeOnly(scope, "break statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ class ContinueStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "continue statement")
|
return bytecodeOnly(scope, "continue statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ class ReturnStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "return statement")
|
return bytecodeOnly(scope, "return statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ class ThrowStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return interpreterDisabled(scope, "throw statement")
|
return bytecodeOnly(scope, "throw statement")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ class ExpressionStatement(
|
|||||||
val ref: net.sergeych.lyng.obj.ObjRef,
|
val ref: net.sergeych.lyng.obj.ObjRef,
|
||||||
override val pos: Pos
|
override val pos: Pos
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj = interpreterDisabled(scope, "expression statement")
|
override suspend fun execute(scope: Scope): Obj = bytecodeOnly(scope, "expression statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Statement.raise(text: String): Nothing {
|
fun Statement.raise(text: String): Nothing {
|
||||||
@ -180,5 +180,5 @@ fun Statement.require(cond: Boolean, message: () -> String) {
|
|||||||
object NopStatement: Statement(true, true, ObjType.Void) {
|
object NopStatement: Statement(true, true, ObjType.Void) {
|
||||||
override val pos: Pos = Pos.builtIn
|
override val pos: Pos = Pos.builtIn
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj = interpreterDisabled(scope, "nop statement")
|
override suspend fun execute(scope: Scope): Obj = bytecodeOnly(scope, "nop statement")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@
|
|||||||
package net.sergeych.lynon
|
package net.sergeych.lynon
|
||||||
|
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
|
import net.sergeych.lyng.requireOnlyArg
|
||||||
|
import net.sergeych.lyng.requireScope
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
|
|
||||||
// Most often used types:
|
// Most often used types:
|
||||||
@ -42,10 +44,10 @@ object ObjLynonClass : ObjClass("Lynon") {
|
|||||||
init {
|
init {
|
||||||
addClassConst("test", ObjString("test_const"))
|
addClassConst("test", ObjString("test_const"))
|
||||||
addClassFn("encode") {
|
addClassFn("encode") {
|
||||||
encodeAny(this, requireOnlyArg<Obj>())
|
encodeAny(requireScope(), requireOnlyArg<Obj>())
|
||||||
}
|
}
|
||||||
addClassFn("decode") {
|
addClassFn("decode") {
|
||||||
decodeAny(this, requireOnlyArg<Obj>())
|
decodeAny(requireScope(), requireOnlyArg<Obj>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import kotlinx.serialization.json.JsonPrimitive
|
|||||||
import kotlinx.serialization.json.encodeToJsonElement
|
import kotlinx.serialization.json.encodeToJsonElement
|
||||||
import net.sergeych.lyng.*
|
import net.sergeych.lyng.*
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
|
import net.sergeych.lyng.thisAs
|
||||||
import net.sergeych.lyng.pacman.InlineSourcesImportProvider
|
import net.sergeych.lyng.pacman.InlineSourcesImportProvider
|
||||||
import net.sergeych.mp_tools.globalDefer
|
import net.sergeych.mp_tools.globalDefer
|
||||||
import net.sergeych.tools.bm
|
import net.sergeych.tools.bm
|
||||||
|
|||||||
@ -178,11 +178,11 @@ suspend fun DocTest.test(_scope: Scope? = null) {
|
|||||||
scope.apply {
|
scope.apply {
|
||||||
addFn("println") {
|
addFn("println") {
|
||||||
if( bookMode ) {
|
if( bookMode ) {
|
||||||
println("${currentTest.fileNamePart}:${currentTest.line}> ${args.map{it.toString(this).value}.joinToString(" ")}")
|
println("${currentTest.fileNamePart}:${currentTest.line}> ${args.map{toStringOf(it).value}.joinToString(" ")}")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for ((i, a) in args.withIndex()) {
|
for ((i, a) in args.withIndex()) {
|
||||||
if (i > 0) collectedOutput.append(' '); collectedOutput.append(a.toString(this).value)
|
if (i > 0) collectedOutput.append(' '); collectedOutput.append(toStringOf(a).value)
|
||||||
collectedOutput.append('\n')
|
collectedOutput.append('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user