Compare commits
1 Commits
master
...
heroic_att
| Author | SHA1 | Date | |
|---|---|---|---|
| f9ae00b7f4 |
@ -1,8 +0,0 @@
|
||||
# AI Agent Notes
|
||||
|
||||
## Kotlin/Wasm generation guardrails
|
||||
- Avoid creating suspend lambdas for compiler runtime statements. Prefer explicit `object : Statement()` with `override suspend fun execute(...)`.
|
||||
- Do not use `statement { ... }` or other inline suspend lambdas in compiler hot paths (e.g., parsing/var declarations, initializer thunks).
|
||||
- If you need a wrapper for delegated properties, check for `getValue` explicitly and return a concrete `Statement` object when missing; avoid `onNotFoundResult` lambdas.
|
||||
- If wasmJs browser tests hang, first run `:lynglib:wasmJsNodeTest` and look for wasm compilation errors; hangs usually mean module instantiation failed.
|
||||
- Do not increase test timeouts to mask wasm generation errors; fix the invalid IR instead.
|
||||
@ -45,7 +45,6 @@ fun swapEnds(first, args..., last, f) {
|
||||
- [Samples directory](docs/samples)
|
||||
- [Formatter (core + CLI + IDE)](docs/formatter.md)
|
||||
- [Books directory](docs)
|
||||
- [AI agent guidance](AGENTS.md)
|
||||
|
||||
## Integration in Kotlin multiplatform
|
||||
|
||||
@ -232,4 +231,4 @@ __Sergey Chernov__ @sergeych: Initial idea and architecture, language concept, d
|
||||
|
||||
__Yulia Nezhinskaya__ @AlterEgoJuliaN: System analysis, math and features design.
|
||||
|
||||
[parallelism]: docs/parallelism.md
|
||||
[parallelism]: docs/parallelism.md
|
||||
@ -1,15 +0,0 @@
|
||||
# AI notes: avoid Kotlin/Wasm invalid IR with suspend lambdas
|
||||
|
||||
## Do
|
||||
- Prefer explicit `object : Statement()` with `override suspend fun execute(...)` when building compiler statements.
|
||||
- Keep `Statement` objects non-lambda, especially in compiler hot paths like parsing/var declarations.
|
||||
- If you need conditional behavior, return early in `execute` instead of wrapping `parseExpression()` with `statement(...) { ... }`.
|
||||
- When wasmJs tests hang in the browser, first check `wasmJsNodeTest` for a compile error; hangs often mean module instantiation failed.
|
||||
|
||||
## Don't
|
||||
- Do not create suspend lambdas inside `Statement` factories (`statement { ... }`) for wasm targets.
|
||||
- Do not "fix" hangs by increasing browser timeouts; it masks invalid wasm generation.
|
||||
|
||||
## Debugging tips
|
||||
- Look for `$invokeCOROUTINE$` in wasm function names when mapping failures.
|
||||
- If node test logs a wasm compile error, the browser hang is likely the same root cause.
|
||||
@ -1,27 +0,0 @@
|
||||
# Wasm generation hang in wasmJs browser tests
|
||||
|
||||
## Summary
|
||||
The wasmJs browser test runner hung after commit 5f819dc. The root cause was invalid WebAssembly generated by the Kotlin/Wasm backend when certain compiler paths emitted suspend lambdas for `Statement` execution. The invalid module failed to instantiate in the browser, and Karma kept the browser connected but never ran tests.
|
||||
|
||||
## Symptoms
|
||||
- `:lynglib:wasmJsBrowserTest` hangs indefinitely in ChromeHeadless.
|
||||
- `:lynglib:wasmJsNodeTest` fails with a WebAssembly compile error similar to:
|
||||
- `struct.set expected type (ref null XXXX), found global.get of type (ref null YYYY)`
|
||||
- The failing function name in the wasm name section looks like:
|
||||
- `net.sergeych.lyng.$invokeCOROUTINE$.doResume`
|
||||
|
||||
## Root cause
|
||||
The delegation/var-declaration changes introduced compiler-generated suspend lambdas inside `Statement` construction (e.g., `statement { ... }` wrappers). Kotlin/Wasm generates extra coroutine state for those suspend lambdas, which in this case produced invalid wasm IR (mismatched GC reference types). The browser loader then waits forever because the module fails to instantiate.
|
||||
|
||||
## Fix
|
||||
Avoid suspend-lambda `Statement` construction in compiler code paths. Replace `statement { ... }` and other anonymous suspend lambdas with explicit `object : Statement()` implementations and move logic into `override suspend fun execute(...)`. This keeps the resulting wasm IR valid while preserving behavior.
|
||||
|
||||
## Where it was fixed
|
||||
- `lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt`
|
||||
- `lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt`
|
||||
|
||||
## Verification
|
||||
- `./gradlew :lynglib:wasmJsNodeTest --info`
|
||||
- `./gradlew :lynglib:wasmJsBrowserTest --info`
|
||||
|
||||
Both tests finish quickly after the change.
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
# Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
#
|
||||
|
||||
#Gradle
|
||||
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
|
||||
org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
|
||||
org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
#Kotlin
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -23,9 +23,11 @@ package net.sergeych.lyng.io.fs
|
||||
|
||||
import net.sergeych.lyng.ModuleScope
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportManager
|
||||
import net.sergeych.lyng.pacman.ModuleBuilder
|
||||
import net.sergeych.lyngio.fs.LyngFS
|
||||
import net.sergeych.lyngio.fs.LyngFs
|
||||
import net.sergeych.lyngio.fs.LyngPath
|
||||
@ -50,9 +52,11 @@ fun createFsModule(policy: FsAccessPolicy, manager: ImportManager): Boolean {
|
||||
// Avoid re-registering in this ImportManager
|
||||
if (manager.packageNames.contains(name)) return false
|
||||
|
||||
manager.addPackage(name) { module ->
|
||||
buildFsModule(module, policy)
|
||||
}
|
||||
manager.addPackage(name, object : ModuleBuilder {
|
||||
override suspend fun build(module: ModuleScope) {
|
||||
buildFsModule(module, policy)
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
@ -78,322 +82,394 @@ private suspend fun buildFsModule(module: ModuleScope, policy: FsAccessPolicy) {
|
||||
name = "name",
|
||||
doc = "Base name of the path (last segment).",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
val self = thisAs<ObjPath>()
|
||||
self.path.name.toObj()
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjPath>()
|
||||
return self.path.name.toObj()
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "parent",
|
||||
doc = "Parent directory as a Path or null if none.",
|
||||
returns = type("Path", nullable = true),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
val self = thisAs<ObjPath>()
|
||||
self.path.parent?.let {
|
||||
ObjPath( this@apply, self.secured, it)
|
||||
} ?: ObjNull
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjPath>()
|
||||
return self.path.parent?.let {
|
||||
ObjPath(this@apply, self.secured, it)
|
||||
} ?: ObjNull
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "segments",
|
||||
doc = "List of path segments.",
|
||||
// returns: List<String>
|
||||
returns = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.String"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
val self = thisAs<ObjPath>()
|
||||
ObjList(self.path.segments.map { ObjString(it) }.toMutableList())
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjPath>()
|
||||
return ObjList(self.path.segments.map { ObjString(it) }.toMutableList())
|
||||
}
|
||||
}
|
||||
)
|
||||
// exists(): Bool
|
||||
addFnDoc(
|
||||
name = "exists",
|
||||
doc = "Check whether this path exists.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
(self.secured.exists(self.path)).toObj()
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
(self.secured.exists(self.path)).toObj()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// isFile(): Bool — cached metadata
|
||||
addFnDoc(
|
||||
name = "isFile",
|
||||
doc = "True if this path is a regular file (based on cached metadata).",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
self.ensureMetadata().let { ObjBool(it.isRegularFile) }
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
self.ensureMetadata().let { ObjBool(it.isRegularFile) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// isDirectory(): Bool — cached metadata
|
||||
addFnDoc(
|
||||
name = "isDirectory",
|
||||
doc = "True if this path is a directory (based on cached metadata).",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
self.ensureMetadata().let { ObjBool(it.isDirectory) }
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
self.ensureMetadata().let { ObjBool(it.isDirectory) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// size(): Int? — null when unavailable
|
||||
addFnDoc(
|
||||
name = "size",
|
||||
doc = "File size in bytes, or null when unavailable.",
|
||||
returns = type("lyng.Int", nullable = true),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.size?.let { ObjInt(it) } ?: ObjNull
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.size?.let { ObjInt(it) } ?: ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// createdAt(): Instant? — Lyng Instant, null when unavailable
|
||||
addFnDoc(
|
||||
name = "createdAt",
|
||||
doc = "Creation time as `Instant`, or null when unavailable.",
|
||||
returns = type("lyng.Instant", nullable = true),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.createdAtMillis?.let { ObjInstant(kotlin.time.Instant.fromEpochMilliseconds(it)) } ?: ObjNull
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.createdAtMillis?.let { ObjInstant(kotlin.time.Instant.fromEpochMilliseconds(it)) } ?: ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// createdAtMillis(): Int? — milliseconds since epoch or null
|
||||
addFnDoc(
|
||||
name = "createdAtMillis",
|
||||
doc = "Creation time in milliseconds since epoch, or null when unavailable.",
|
||||
returns = type("lyng.Int", nullable = true),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.createdAtMillis?.let { ObjInt(it) } ?: ObjNull
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.createdAtMillis?.let { ObjInt(it) } ?: ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// modifiedAt(): Instant? — Lyng Instant, null when unavailable
|
||||
addFnDoc(
|
||||
name = "modifiedAt",
|
||||
doc = "Last modification time as `Instant`, or null when unavailable.",
|
||||
returns = type("lyng.Instant", nullable = true),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.modifiedAtMillis?.let { ObjInstant(kotlinx.datetime.Instant.fromEpochMilliseconds(it)) } ?: ObjNull
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.modifiedAtMillis?.let { ObjInstant(kotlinx.datetime.Instant.fromEpochMilliseconds(it)) } ?: ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// modifiedAtMillis(): Int? — milliseconds since epoch or null
|
||||
addFnDoc(
|
||||
name = "modifiedAtMillis",
|
||||
doc = "Last modification time in milliseconds since epoch, or null when unavailable.",
|
||||
returns = type("lyng.Int", nullable = true),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.modifiedAtMillis?.let { ObjInt(it) } ?: ObjNull
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val m = self.ensureMetadata()
|
||||
m.modifiedAtMillis?.let { ObjInt(it) } ?: ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// list(): List<Path>
|
||||
addFnDoc(
|
||||
name = "list",
|
||||
doc = "List directory entries as `Path` objects.",
|
||||
returns = TypeGenericDoc(type("lyng.List"), listOf(type("Path"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val items = self.secured.list(self.path).map { ObjPath(self.objClass, self.secured, it) }
|
||||
ObjList(items.toMutableList())
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val items = self.secured.list(self.path).map { ObjPath(self.objClass, self.secured, it) }
|
||||
ObjList(items.toMutableList())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// readBytes(): Buffer
|
||||
addFnDoc(
|
||||
name = "readBytes",
|
||||
doc = "Read the file into a binary buffer.",
|
||||
returns = type("lyng.Buffer"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val bytes = self.secured.readBytes(self.path)
|
||||
ObjBuffer(bytes.asUByteArray())
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val bytes = self.secured.readBytes(self.path)
|
||||
ObjBuffer(bytes.asUByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// writeBytes(bytes: Buffer)
|
||||
addFnDoc(
|
||||
name = "writeBytes",
|
||||
doc = "Write a binary buffer to the file, replacing content.",
|
||||
params = listOf(ParamDoc("bytes", type("lyng.Buffer"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val buf = requiredArg<ObjBuffer>(0)
|
||||
self.secured.writeBytes(self.path, buf.byteArray.asByteArray(), append = false)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val buf = scp.requiredArg<ObjBuffer>(0)
|
||||
self.secured.writeBytes(self.path, buf.byteArray.asByteArray(), append = false)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// appendBytes(bytes: Buffer)
|
||||
addFnDoc(
|
||||
name = "appendBytes",
|
||||
doc = "Append a binary buffer to the end of the file.",
|
||||
params = listOf(ParamDoc("bytes", type("lyng.Buffer"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val buf = requiredArg<ObjBuffer>(0)
|
||||
self.secured.writeBytes(self.path, buf.byteArray.asByteArray(), append = true)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val buf = scp.requiredArg<ObjBuffer>(0)
|
||||
self.secured.writeBytes(self.path, buf.byteArray.asByteArray(), append = true)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// readUtf8(): String
|
||||
addFnDoc(
|
||||
name = "readUtf8",
|
||||
doc = "Read the file as a UTF-8 string.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
self.secured.readUtf8(self.path).toObj()
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
self.secured.readUtf8(self.path).toObj()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// writeUtf8(text: String)
|
||||
addFnDoc(
|
||||
name = "writeUtf8",
|
||||
doc = "Write a UTF-8 string to the file, replacing content.",
|
||||
params = listOf(ParamDoc("text", type("lyng.String"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val text = requireOnlyArg<ObjString>().value
|
||||
self.secured.writeUtf8(self.path, text, append = false)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val text = scp.requireOnlyArg<ObjString>().value
|
||||
self.secured.writeUtf8(self.path, text, append = false)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// appendUtf8(text: String)
|
||||
addFnDoc(
|
||||
name = "appendUtf8",
|
||||
doc = "Append UTF-8 text to the end of the file.",
|
||||
params = listOf(ParamDoc("text", type("lyng.String"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val text = requireOnlyArg<ObjString>().value
|
||||
self.secured.writeUtf8(self.path, text, append = true)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val text = scp.requireOnlyArg<ObjString>().value
|
||||
self.secured.writeUtf8(self.path, text, append = true)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// metadata(): Map
|
||||
addFnDoc(
|
||||
name = "metadata",
|
||||
doc = "Fetch cached metadata as a map of fields: `isFile`, `isDirectory`, `size`, `createdAtMillis`, `modifiedAtMillis`, `isSymlink`.",
|
||||
returns = TypeGenericDoc(type("lyng.Map"), listOf(type("lyng.String"), type("lyng.Any"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val m = self.secured.metadata(self.path)
|
||||
ObjMap(mutableMapOf(
|
||||
ObjString("isFile") to ObjBool(m.isRegularFile),
|
||||
ObjString("isDirectory") to ObjBool(m.isDirectory),
|
||||
ObjString("size") to (m.size?.toLong() ?: 0L).toObj(),
|
||||
ObjString("createdAtMillis") to ((m.createdAtMillis ?: 0L)).toObj(),
|
||||
ObjString("modifiedAtMillis") to ((m.modifiedAtMillis ?: 0L)).toObj(),
|
||||
ObjString("isSymlink") to ObjBool(m.isSymlink),
|
||||
))
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val m = self.secured.metadata(self.path)
|
||||
ObjMap(mutableMapOf(
|
||||
ObjString("isFile") to ObjBool(m.isRegularFile),
|
||||
ObjString("isDirectory") to ObjBool(m.isDirectory),
|
||||
ObjString("size") to (m.size?.toLong() ?: 0L).toObj(),
|
||||
ObjString("createdAtMillis") to ((m.createdAtMillis ?: 0L)).toObj(),
|
||||
ObjString("modifiedAtMillis") to ((m.modifiedAtMillis ?: 0L)).toObj(),
|
||||
ObjString("isSymlink") to ObjBool(m.isSymlink),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// mkdirs(mustCreate: Bool=false)
|
||||
addFnDoc(
|
||||
name = "mkdirs",
|
||||
doc = "Create directories (like `mkdir -p`). If `mustCreate` is true and the path already exists, the call fails. Otherwise it is a no‑op when the directory exists.",
|
||||
params = listOf(ParamDoc("mustCreate", type("lyng.Bool"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val mustCreate = args.list.getOrNull(0)?.toBool() ?: false
|
||||
self.secured.createDirectories(self.path, mustCreate)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val mustCreate = scp.args.list.getOrNull(0)?.toBool() ?: false
|
||||
self.secured.createDirectories(self.path, mustCreate)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// move(to: Path|String, overwrite: Bool=false)
|
||||
addFnDoc(
|
||||
name = "move",
|
||||
doc = "Move this path to a new location. `to` may be a `Path` or `String`. When `overwrite` is false and the target exists, the operation fails (provider may throw `AccessDeniedException`).",
|
||||
// types vary; keep generic description in doc
|
||||
params = listOf(ParamDoc("to"), ParamDoc("overwrite", type("lyng.Bool"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val toPath = parsePathArg(this, self, requiredArg<Obj>(0))
|
||||
val overwrite = args.list.getOrNull(1)?.toBool() ?: false
|
||||
self.secured.move(self.path, toPath, overwrite)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val toPath = parsePathArg(scp, self, scp.requiredArg<Obj>(0))
|
||||
val overwrite = scp.args.list.getOrNull(1)?.toBool() ?: false
|
||||
self.secured.move(self.path, toPath, overwrite)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// delete(mustExist: Bool=false, recursively: Bool=false)
|
||||
addFnDoc(
|
||||
name = "delete",
|
||||
doc = "Delete this path. `mustExist=true` causes failure if the path does not exist. `recursively=true` removes directories with their contents. Providers can throw `AccessDeniedException` on policy violations.",
|
||||
params = listOf(ParamDoc("mustExist", type("lyng.Bool")), ParamDoc("recursively", type("lyng.Bool"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val mustExist = args.list.getOrNull(0)?.toBool() ?: false
|
||||
val recursively = args.list.getOrNull(1)?.toBool() ?: false
|
||||
self.secured.delete(self.path, mustExist, recursively)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val mustExist = scp.args.list.getOrNull(0)?.toBool() ?: false
|
||||
val recursively = scp.args.list.getOrNull(1)?.toBool() ?: false
|
||||
self.secured.delete(self.path, mustExist, recursively)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// copy(to: Path|String, overwrite: Bool=false)
|
||||
addFnDoc(
|
||||
name = "copy",
|
||||
doc = "Copy this path to a new location. `to` may be a `Path` or `String`. When `overwrite` is false and the target exists, the operation fails (provider may throw `AccessDeniedException`).",
|
||||
params = listOf(ParamDoc("to"), ParamDoc("overwrite", type("lyng.Bool"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val toPath = parsePathArg(this, self, requiredArg<Obj>(0))
|
||||
val overwrite = args.list.getOrNull(1)?.toBool() ?: false
|
||||
self.secured.copy(self.path, toPath, overwrite)
|
||||
ObjVoid
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val toPath = parsePathArg(scp, self, scp.requiredArg<Obj>(0))
|
||||
val overwrite = scp.args.list.getOrNull(1)?.toBool() ?: false
|
||||
self.secured.copy(self.path, toPath, overwrite)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
// glob(pattern: String): List<Path>
|
||||
addFnDoc(
|
||||
name = "glob",
|
||||
doc = "List entries matching a glob pattern (no recursion).",
|
||||
params = listOf(ParamDoc("pattern", type("lyng.String"))),
|
||||
returns = TypeGenericDoc(type("lyng.List"), listOf(type("Path"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val pattern = requireOnlyArg<ObjString>().value
|
||||
val matches = self.secured.glob(self.path, pattern)
|
||||
ObjList(matches.map { ObjPath(self.objClass, self.secured, it) }.toMutableList())
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val pattern = scp.requireOnlyArg<ObjString>().value
|
||||
val matches = self.secured.glob(self.path, pattern)
|
||||
ObjList(matches.map { ObjPath(self.objClass, self.secured, it) }.toMutableList())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// --- streaming readers (initial version: chunk from whole content, API stable) ---
|
||||
|
||||
@ -403,15 +479,18 @@ private suspend fun buildFsModule(module: ModuleScope, policy: FsAccessPolicy) {
|
||||
doc = "Read file in fixed-size chunks as an iterator of `Buffer`.",
|
||||
params = listOf(ParamDoc("size", type("lyng.Int"))),
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Buffer"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val size = args.list.getOrNull(0)?.toInt() ?: 65536
|
||||
val bytes = self.secured.readBytes(self.path)
|
||||
ObjFsBytesIterator(bytes, size)
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val size = scp.args.list.getOrNull(0)?.toInt() ?: 65536
|
||||
val bytes = self.secured.readBytes(self.path)
|
||||
ObjFsBytesIterator(bytes, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// readUtf8Chunks(size: Int = 65536) -> Iterator<String>
|
||||
addFnDoc(
|
||||
@ -419,28 +498,34 @@ private suspend fun buildFsModule(module: ModuleScope, policy: FsAccessPolicy) {
|
||||
doc = "Read UTF-8 text in fixed-size chunks as an iterator of `String`.",
|
||||
params = listOf(ParamDoc("size", type("lyng.Int"))),
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.String"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val self = this.thisObj as ObjPath
|
||||
val size = args.list.getOrNull(0)?.toInt() ?: 65536
|
||||
val text = self.secured.readUtf8(self.path)
|
||||
ObjFsStringChunksIterator(text, size)
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val self = scp.thisObj as ObjPath
|
||||
val size = scp.args.list.getOrNull(0)?.toInt() ?: 65536
|
||||
val text = self.secured.readUtf8(self.path)
|
||||
ObjFsStringChunksIterator(text, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// lines() -> Iterator<String>, implemented via readUtf8Chunks
|
||||
addFnDoc(
|
||||
name = "lines",
|
||||
doc = "Iterate lines of the file as `String` values.",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.String"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
fsGuard {
|
||||
val chunkIt = thisObj.invokeInstanceMethod(this, "readUtf8Chunks")
|
||||
ObjFsLinesIterator(chunkIt)
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.fsGuard {
|
||||
val chunkIt = scp.thisObj.invokeInstanceMethod(scp, "readUtf8Chunks")
|
||||
ObjFsLinesIterator(chunkIt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Export into the module scope with docs
|
||||
@ -518,39 +603,51 @@ class ObjFsBytesIterator(
|
||||
name = "iterator",
|
||||
doc = "Return this iterator instance (enables `for` loops).",
|
||||
returns = type("BytesIterator"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) { thisObj }
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisObj
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "hasNext",
|
||||
doc = "Whether there is another chunk available.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsBytesIterator>()
|
||||
(self.pos < self.data.size).toObj()
|
||||
}
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsBytesIterator>()
|
||||
return (self.pos < self.data.size).toObj()
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "next",
|
||||
doc = "Return the next chunk as a `Buffer`.",
|
||||
returns = type("lyng.Buffer"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsBytesIterator>()
|
||||
if (self.pos >= self.data.size) raiseIllegalState("iterator exhausted")
|
||||
val end = minOf(self.pos + self.chunkSize, self.data.size)
|
||||
val chunk = self.data.copyOfRange(self.pos, end)
|
||||
self.pos = end
|
||||
ObjBuffer(chunk.asUByteArray())
|
||||
}
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsBytesIterator>()
|
||||
if (self.pos >= self.data.size) scp.raiseIllegalState("iterator exhausted")
|
||||
val end = minOf(self.pos + self.chunkSize, self.data.size)
|
||||
val chunk = self.data.copyOfRange(self.pos, end)
|
||||
self.pos = end
|
||||
return ObjBuffer(chunk.asUByteArray())
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "cancelIteration",
|
||||
doc = "Stop the iteration early; subsequent `hasNext` returns false.",
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsBytesIterator>()
|
||||
self.pos = self.data.size
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsBytesIterator>()
|
||||
self.pos = self.data.size
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -573,35 +670,47 @@ class ObjFsStringChunksIterator(
|
||||
name = "iterator",
|
||||
doc = "Return this iterator instance (enables `for` loops).",
|
||||
returns = type("StringChunksIterator"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) { thisObj }
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisObj
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "hasNext",
|
||||
doc = "Whether there is another chunk available.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsStringChunksIterator>()
|
||||
(self.pos < self.text.length).toObj()
|
||||
}
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsStringChunksIterator>()
|
||||
return (self.pos < self.text.length).toObj()
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "next",
|
||||
doc = "Return the next UTF-8 chunk as a `String`.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsStringChunksIterator>()
|
||||
if (self.pos >= self.text.length) raiseIllegalState("iterator exhausted")
|
||||
val end = minOf(self.pos + self.chunkChars, self.text.length)
|
||||
val chunk = self.text.substring(self.pos, end)
|
||||
self.pos = end
|
||||
ObjString(chunk)
|
||||
}
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsStringChunksIterator>()
|
||||
if (self.pos >= self.text.length) scp.raiseIllegalState("iterator exhausted")
|
||||
val end = minOf(self.pos + self.chunkChars, self.text.length)
|
||||
val chunk = self.text.substring(self.pos, end)
|
||||
self.pos = end
|
||||
return ObjString(chunk)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "cancelIteration",
|
||||
doc = "Stop the iteration early; subsequent `hasNext` returns false.",
|
||||
moduleName = "lyng.io.fs"
|
||||
) { ObjVoid }
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjVoid
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -624,46 +733,58 @@ class ObjFsLinesIterator(
|
||||
name = "iterator",
|
||||
doc = "Return this iterator instance (enables `for` loops).",
|
||||
returns = type("LinesIterator"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) { thisObj }
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisObj
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "hasNext",
|
||||
doc = "Whether another line is available.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsLinesIterator>()
|
||||
self.ensureBufferFilled(this)
|
||||
(self.buffer.isNotEmpty() || !self.exhausted).toObj()
|
||||
}
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsLinesIterator>()
|
||||
self.ensureBufferFilled(scp)
|
||||
return (self.buffer.isNotEmpty() || !self.exhausted).toObj()
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "next",
|
||||
doc = "Return the next line as `String`.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.io.fs"
|
||||
) {
|
||||
val self = thisAs<ObjFsLinesIterator>()
|
||||
self.ensureBufferFilled(this)
|
||||
if (self.buffer.isEmpty() && self.exhausted) raiseIllegalState("iterator exhausted")
|
||||
val idx = self.buffer.indexOf('\n')
|
||||
val line = if (idx >= 0) {
|
||||
val l = self.buffer.substring(0, idx)
|
||||
self.buffer = self.buffer.substring(idx + 1)
|
||||
l
|
||||
} else {
|
||||
// last line without trailing newline
|
||||
val l = self.buffer
|
||||
self.buffer = ""
|
||||
self.exhausted = true
|
||||
l
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjFsLinesIterator>()
|
||||
self.ensureBufferFilled(scp)
|
||||
if (self.buffer.isEmpty() && self.exhausted) scp.raiseIllegalState("iterator exhausted")
|
||||
val idx = self.buffer.indexOf('\n')
|
||||
val line = if (idx >= 0) {
|
||||
val l = self.buffer.substring(0, idx)
|
||||
self.buffer = self.buffer.substring(idx + 1)
|
||||
l
|
||||
} else {
|
||||
// last line without trailing newline
|
||||
val l = self.buffer
|
||||
self.buffer = ""
|
||||
self.exhausted = true
|
||||
l
|
||||
}
|
||||
return ObjString(line)
|
||||
}
|
||||
}
|
||||
ObjString(line)
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "cancelIteration",
|
||||
doc = "Stop the iteration early; subsequent `hasNext` returns false.",
|
||||
moduleName = "lyng.io.fs"
|
||||
) { ObjVoid }
|
||||
moduleName = "lyng.io.fs",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjVoid
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,9 +20,11 @@ package net.sergeych.lyng.io.process
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import net.sergeych.lyng.ModuleScope
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportManager
|
||||
import net.sergeych.lyng.pacman.ModuleBuilder
|
||||
import net.sergeych.lyng.statement
|
||||
import net.sergeych.lyngio.process.*
|
||||
import net.sergeych.lyngio.process.security.ProcessAccessDeniedException
|
||||
@ -39,9 +41,11 @@ fun createProcessModule(policy: ProcessAccessPolicy, manager: ImportManager): Bo
|
||||
val name = "lyng.io.process"
|
||||
if (manager.packageNames.contains(name)) return false
|
||||
|
||||
manager.addPackage(name) { module ->
|
||||
buildProcessModule(module, policy)
|
||||
}
|
||||
manager.addPackage(name, object : ModuleBuilder {
|
||||
override suspend fun build(module: ModuleScope) {
|
||||
buildProcessModule(module, policy)
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
@ -59,59 +63,74 @@ private suspend fun buildProcessModule(module: ModuleScope, policy: ProcessAcces
|
||||
name = "stdout",
|
||||
doc = "Get standard output stream as a Flow of lines.",
|
||||
returns = type("lyng.Flow"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
val self = thisAs<ObjRunningProcess>()
|
||||
self.process.stdout.toLyngFlow(this)
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjRunningProcess>()
|
||||
return self.process.stdout.toLyngFlow(scp)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "stderr",
|
||||
doc = "Get standard error stream as a Flow of lines.",
|
||||
returns = type("lyng.Flow"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
val self = thisAs<ObjRunningProcess>()
|
||||
self.process.stderr.toLyngFlow(this)
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjRunningProcess>()
|
||||
return self.process.stderr.toLyngFlow(scp)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "signal",
|
||||
doc = "Send a signal to the process (e.g. 'SIGINT', 'SIGTERM', 'SIGKILL').",
|
||||
params = listOf(ParamDoc("signal", type("lyng.String"))),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
processGuard {
|
||||
val sigStr = requireOnlyArg<ObjString>().value.uppercase()
|
||||
val sig = try {
|
||||
ProcessSignal.valueOf(sigStr)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
ProcessSignal.valueOf("SIG$sigStr")
|
||||
} catch (e2: Exception) {
|
||||
raiseIllegalArgument("Unknown signal: $sigStr")
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.processGuard {
|
||||
val sigStr = scp.requireOnlyArg<ObjString>().value.uppercase()
|
||||
val sig = try {
|
||||
ProcessSignal.valueOf(sigStr)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
ProcessSignal.valueOf("SIG$sigStr")
|
||||
} catch (e2: Exception) {
|
||||
scp.raiseIllegalArgument("Unknown signal: $sigStr")
|
||||
}
|
||||
}
|
||||
scp.thisAs<ObjRunningProcess>().process.sendSignal(sig)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
thisAs<ObjRunningProcess>().process.sendSignal(sig)
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "waitFor",
|
||||
doc = "Wait for the process to exit and return its exit code.",
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
processGuard {
|
||||
thisAs<ObjRunningProcess>().process.waitFor().toObj()
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.processGuard {
|
||||
scp.thisAs<ObjRunningProcess>().process.waitFor().toObj()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "destroy",
|
||||
doc = "Forcefully terminate the process.",
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
thisAs<ObjRunningProcess>().process.destroy()
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.thisAs<ObjRunningProcess>().process.destroy()
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val processType = object : ObjClass("Process") {}
|
||||
@ -122,30 +141,36 @@ private suspend fun buildProcessModule(module: ModuleScope, policy: ProcessAcces
|
||||
doc = "Execute a process with arguments.",
|
||||
params = listOf(ParamDoc("executable", type("lyng.String")), ParamDoc("args", type("lyng.List"))),
|
||||
returns = type("RunningProcess"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
if (runner == null) raiseError("Processes are not supported on this platform")
|
||||
processGuard {
|
||||
val executable = requiredArg<ObjString>(0).value
|
||||
val args = requiredArg<ObjList>(1).list.map { it.toString() }
|
||||
val lp = runner.execute(executable, args)
|
||||
ObjRunningProcess(runningProcessType, lp)
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
if (runner == null) scp.raiseError("Processes are not supported on this platform")
|
||||
return scp.processGuard {
|
||||
val executable = scp.requiredArg<ObjString>(0).value
|
||||
val args = scp.requiredArg<ObjList>(1).list.map { it.toString() }
|
||||
val lp = runner.execute(executable, args)
|
||||
ObjRunningProcess(runningProcessType, lp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
addClassFnDoc(
|
||||
name = "shell",
|
||||
doc = "Execute a command via system shell.",
|
||||
params = listOf(ParamDoc("command", type("lyng.String"))),
|
||||
returns = type("RunningProcess"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
if (runner == null) raiseError("Processes are not supported on this platform")
|
||||
processGuard {
|
||||
val command = requireOnlyArg<ObjString>().value
|
||||
val lp = runner.shell(command)
|
||||
ObjRunningProcess(runningProcessType, lp)
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
if (runner == null) scp.raiseError("Processes are not supported on this platform")
|
||||
return scp.processGuard {
|
||||
val command = scp.requireOnlyArg<ObjString>().value
|
||||
val lp = runner.shell(command)
|
||||
ObjRunningProcess(runningProcessType, lp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val platformType = object : ObjClass("Platform") {}
|
||||
@ -155,24 +180,28 @@ private suspend fun buildProcessModule(module: ModuleScope, policy: ProcessAcces
|
||||
name = "details",
|
||||
doc = "Get platform core details.",
|
||||
returns = type("lyng.Map"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
val d = getPlatformDetails()
|
||||
ObjMap(mutableMapOf(
|
||||
ObjString("name") to ObjString(d.name),
|
||||
ObjString("version") to ObjString(d.version),
|
||||
ObjString("arch") to ObjString(d.arch),
|
||||
ObjString("kernelVersion") to (d.kernelVersion?.toObj() ?: ObjNull)
|
||||
))
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val d = getPlatformDetails()
|
||||
return ObjMap(mutableMapOf(
|
||||
ObjString("name") to ObjString(d.name),
|
||||
ObjString("version") to ObjString(d.version),
|
||||
ObjString("arch") to ObjString(d.arch),
|
||||
ObjString("kernelVersion") to (d.kernelVersion?.toObj() ?: ObjNull)
|
||||
))
|
||||
}
|
||||
}
|
||||
)
|
||||
addClassFnDoc(
|
||||
name = "isSupported",
|
||||
doc = "Check if processes are supported on this platform.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = module.packageName
|
||||
) {
|
||||
isProcessSupported().toObj()
|
||||
}
|
||||
moduleName = module.packageName,
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = isProcessSupported().toObj()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
module.addConstDoc(
|
||||
@ -216,19 +245,21 @@ private suspend inline fun Scope.processGuard(crossinline block: suspend () -> O
|
||||
}
|
||||
|
||||
private fun Flow<String>.toLyngFlow(flowScope: Scope): ObjFlow {
|
||||
val producer = statement {
|
||||
val builder = (this as? net.sergeych.lyng.ClosureScope)?.callScope?.thisObj as? ObjFlowBuilder
|
||||
?: this.thisObj as? ObjFlowBuilder
|
||||
val producer = statement(f = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val builder = (scp as? net.sergeych.lyng.ClosureScope)?.callScope?.thisObj as? ObjFlowBuilder
|
||||
?: scp.thisObj as? ObjFlowBuilder
|
||||
|
||||
this@toLyngFlow.collect {
|
||||
try {
|
||||
builder?.output?.send(ObjString(it))
|
||||
} catch (e: Exception) {
|
||||
// Channel closed or other error, stop collecting
|
||||
return@collect
|
||||
this@toLyngFlow.collect {
|
||||
try {
|
||||
builder?.output?.send(ObjString(it))
|
||||
} catch (e: Exception) {
|
||||
// Channel closed or other error, stop collecting
|
||||
return@collect
|
||||
}
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
})
|
||||
return ObjFlow(producer, flowScope)
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "1.2.1"
|
||||
version = "1.2.1-SNAPSHOT"
|
||||
|
||||
// Removed legacy buildscript classpath declarations; plugins are applied via the plugins DSL below
|
||||
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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
|
||||
|
||||
actual object Benchmarks {
|
||||
actual val enabled: Boolean = run {
|
||||
val p = System.getProperty("LYNG_BENCHMARKS")?.lowercase()
|
||||
val e = System.getenv("BENCHMARKS")?.lowercase()
|
||||
fun parse(v: String?): Boolean =
|
||||
v == "true" || v == "1" || v == "yes"
|
||||
parse(p) || parse(e)
|
||||
}
|
||||
}
|
||||
@ -154,69 +154,73 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: assign head part, consuming from headPos; stop at ellipsis
|
||||
suspend fun processHead(index: Int, headPos: Int): Pair<Int, Int> {
|
||||
var i = index
|
||||
var hp = headPos
|
||||
// Locate ellipsis index within considered parameters
|
||||
val ellipsisIndex = params.subList(0, paramsSize).indexOfFirst { it.isEllipsis }
|
||||
|
||||
var headPos = 0
|
||||
var tailPos = callArgs.size - 1
|
||||
|
||||
if (ellipsisIndex >= 0) {
|
||||
// Assign head first to know how many positionals are consumed from the start
|
||||
var i = 0
|
||||
while (i < paramsSize) {
|
||||
val a = params[i]
|
||||
if (a.isEllipsis) break
|
||||
if (assignedByName[i]) {
|
||||
assign(a, namedValues[i]!!)
|
||||
} else {
|
||||
val value = if (hp < callArgs.size) callArgs[hp++]
|
||||
val value = if (headPos < callArgs.size) callArgs[headPos++]
|
||||
else a.defaultValue?.execute(scope)
|
||||
?: scope.raiseIllegalArgument("too few arguments for the call (missing ${a.name})")
|
||||
assign(a, value)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return i to hp
|
||||
}
|
||||
val afterHead = i
|
||||
val headConsumedTo = headPos
|
||||
|
||||
// Helper: assign tail part from the end, consuming from tailPos; stop before ellipsis index
|
||||
// Do not consume elements below headPosBound to avoid overlap with head consumption
|
||||
suspend fun processTail(startExclusive: Int, tailStart: Int, headPosBound: Int): Int {
|
||||
var i = paramsSize - 1
|
||||
var tp = tailStart
|
||||
while (i > startExclusive) {
|
||||
// Then assign tail consuming from the end down to headConsumedTo boundary
|
||||
i = paramsSize - 1
|
||||
var tp = tailPos
|
||||
while (i > ellipsisIndex) {
|
||||
val a = params[i]
|
||||
if (a.isEllipsis) break
|
||||
if (i < assignedByName.size && assignedByName[i]) {
|
||||
assign(a, namedValues[i]!!)
|
||||
} else {
|
||||
val value = if (tp >= headPosBound) callArgs[tp--]
|
||||
val value = if (tp >= headConsumedTo) callArgs[tp--]
|
||||
else a.defaultValue?.execute(scope)
|
||||
?: scope.raiseIllegalArgument("too few arguments for the call")
|
||||
assign(a, value)
|
||||
}
|
||||
i--
|
||||
}
|
||||
return tp
|
||||
}
|
||||
val tailConsumedFrom = tp
|
||||
|
||||
fun processEllipsis(index: Int, headPos: Int, tailPos: Int) {
|
||||
val a = params[index]
|
||||
val from = headPos
|
||||
val to = tailPos
|
||||
// Assign ellipsis list from remaining positionals between headConsumedTo..tailConsumedFrom
|
||||
val a = params[ellipsisIndex]
|
||||
val from = headConsumedTo
|
||||
val to = tailConsumedFrom
|
||||
val l = if (from > to) ObjList()
|
||||
else ObjList(callArgs.subList(from, to + 1).toMutableList())
|
||||
assign(a, l)
|
||||
}
|
||||
|
||||
// Locate ellipsis index within considered parameters
|
||||
val ellipsisIndex = params.subList(0, paramsSize).indexOfFirst { it.isEllipsis }
|
||||
|
||||
if (ellipsisIndex >= 0) {
|
||||
// Assign head first to know how many positionals are consumed from the start
|
||||
val (afterHead, headConsumedTo) = processHead(0, 0)
|
||||
// Then assign tail consuming from the end down to headConsumedTo boundary
|
||||
val tailConsumedFrom = processTail(ellipsisIndex, callArgs.size - 1, headConsumedTo)
|
||||
// Assign ellipsis list from remaining positionals between headConsumedTo..tailConsumedFrom
|
||||
processEllipsis(ellipsisIndex, headConsumedTo, tailConsumedFrom)
|
||||
} else {
|
||||
// No ellipsis: assign head only; any leftover positionals → error
|
||||
val (_, headConsumedTo) = processHead(0, 0)
|
||||
var i = 0
|
||||
while (i < paramsSize) {
|
||||
val a = params[i]
|
||||
if (a.isEllipsis) break
|
||||
if (assignedByName[i]) {
|
||||
assign(a, namedValues[i]!!)
|
||||
} else {
|
||||
val value = if (headPos < callArgs.size) callArgs[headPos++]
|
||||
else a.defaultValue?.execute(scope)
|
||||
?: scope.raiseIllegalArgument("too few arguments for the call (missing ${a.name})")
|
||||
assign(a, value)
|
||||
}
|
||||
i++
|
||||
}
|
||||
val headConsumedTo = headPos
|
||||
if (headConsumedTo != callArgs.size)
|
||||
scope.raiseIllegalArgument("too many arguments for the call")
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -37,7 +37,7 @@ data class ParsedArgument(
|
||||
count++
|
||||
if (count > limit) break
|
||||
}
|
||||
if (!hasSplatOrNamed && count == this.size) {
|
||||
if (!hasSplatOrNamed && count == this.size) {
|
||||
val quick = when (count) {
|
||||
0 -> Arguments.EMPTY
|
||||
1 -> Arguments(listOf(this.elementAt(0).value.execute(scope)), tailBlockMode)
|
||||
@ -154,11 +154,11 @@ data class ParsedArgument(
|
||||
else -> null
|
||||
}
|
||||
if (quick != null) return quick
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// General path: build positional list and named map, enforcing ordering rules
|
||||
val positional: MutableList<Obj> = mutableListOf()
|
||||
val positional: MutableList<Obj> = mutableListOf()
|
||||
var named: MutableMap<String, Obj>? = null
|
||||
var namedSeen = false
|
||||
for ((idx, x) in this.withIndex()) {
|
||||
@ -244,13 +244,20 @@ data class ParsedArgument(
|
||||
* Convert to list of kotlin objects, see [Obj.toKotlin].
|
||||
*/
|
||||
suspend fun toKotlinList(scope: Scope): List<Any?> {
|
||||
return list.map { it.toKotlin(scope) }
|
||||
val res = ArrayList<Any?>(list.size)
|
||||
for (i in list) res.add(i.toKotlin(scope))
|
||||
return res
|
||||
}
|
||||
|
||||
suspend fun inspect(scope: Scope): String {
|
||||
val res = ArrayList<String>(list.size)
|
||||
for (i in list) res.add(i.inspect(scope))
|
||||
return res.joinToString(",")
|
||||
}
|
||||
|
||||
suspend fun inspect(scope: Scope): String = list.map{ it.inspect(scope)}.joinToString(",")
|
||||
|
||||
companion object {
|
||||
val EMPTY = Arguments(emptyList())
|
||||
fun from(values: Collection<Obj>) = Arguments(values.toList())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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
|
||||
|
||||
expect object Benchmarks {
|
||||
val enabled: Boolean
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,23 @@ import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportManager
|
||||
import net.sergeych.lyng.pacman.ImportProvider
|
||||
|
||||
interface ScopeCallable {
|
||||
suspend fun call(scope: Scope): Obj
|
||||
}
|
||||
|
||||
interface VoidScopeCallable {
|
||||
suspend fun call(scope: Scope)
|
||||
}
|
||||
|
||||
interface ScopeBlock<R> {
|
||||
suspend fun call(scope: Scope): R
|
||||
}
|
||||
|
||||
private class FnStatement(val fn: ScopeCallable) : Statement() {
|
||||
override val pos: Pos = Pos.builtIn
|
||||
override suspend fun execute(scope: Scope): Obj = fn.call(scope)
|
||||
}
|
||||
|
||||
// Simple per-frame id generator for perf caches (not thread-safe, fine for scripts)
|
||||
object FrameIdGen { var c: Long = 1L; fun nextId(): Long = c++ }
|
||||
fun nextFrameId(): Long = FrameIdGen.nextId()
|
||||
@ -392,24 +409,6 @@ open class Scope(
|
||||
nameToSlot[name]?.let { slots[it] = record }
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a precomputed slot plan (name -> slot index) for this scope.
|
||||
* This enables direct slot references to bypass name-based lookup.
|
||||
*/
|
||||
fun applySlotPlan(plan: Map<String, Int>) {
|
||||
if (plan.isEmpty()) return
|
||||
val maxIndex = plan.values.maxOrNull() ?: return
|
||||
if (slots.size <= maxIndex) {
|
||||
val targetSize = maxIndex + 1
|
||||
while (slots.size < targetSize) {
|
||||
slots.add(ObjRecord(ObjUnset, isMutable = true))
|
||||
}
|
||||
}
|
||||
for ((name, idx) in plan) {
|
||||
nameToSlot[name] = idx
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all references and maps to prevent memory leaks when pooled.
|
||||
*/
|
||||
@ -465,17 +464,17 @@ open class Scope(
|
||||
* Execute a block inside a child frame. Guarded for future pooling via [PerfFlags.SCOPE_POOL].
|
||||
* Currently always creates a fresh child scope to preserve unique frameId semantics.
|
||||
*/
|
||||
inline suspend fun <R> withChildFrame(args: Arguments = Arguments.EMPTY, newThisObj: Obj? = null, crossinline block: suspend (Scope) -> R): R {
|
||||
suspend fun <R> withChildFrame(args: Arguments = Arguments.EMPTY, newThisObj: Obj? = null, block: ScopeBlock<R>): R {
|
||||
if (PerfFlags.SCOPE_POOL) {
|
||||
val child = ScopePool.borrow(this, args, pos, newThisObj ?: thisObj)
|
||||
try {
|
||||
return block(child)
|
||||
return block.call(child)
|
||||
} finally {
|
||||
ScopePool.release(child)
|
||||
}
|
||||
} else {
|
||||
val child = createChildScope(args, newThisObj)
|
||||
return block(child)
|
||||
return block.call(child)
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,7 +520,6 @@ open class Scope(
|
||||
if (this is ClosureScope) {
|
||||
callScope.localBindings[name] = it
|
||||
}
|
||||
bumpClassLayoutIfNeeded(name, value, recordType)
|
||||
it
|
||||
} ?: addItem(name, true, value, visibility, writeVisibility, recordType, isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride)
|
||||
|
||||
@ -548,24 +546,6 @@ open class Scope(
|
||||
isTransient = isTransient
|
||||
)
|
||||
objects[name] = rec
|
||||
bumpClassLayoutIfNeeded(name, value, recordType)
|
||||
if (recordType == ObjRecord.Type.Field || recordType == ObjRecord.Type.ConstructorField) {
|
||||
val inst = thisObj as? net.sergeych.lyng.obj.ObjInstance
|
||||
if (inst != null) {
|
||||
val slot = inst.objClass.fieldSlotForKey(name)
|
||||
if (slot != null) inst.setFieldSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
if (value is Statement ||
|
||||
recordType == ObjRecord.Type.Fun ||
|
||||
recordType == ObjRecord.Type.Delegated ||
|
||||
recordType == ObjRecord.Type.Property) {
|
||||
val inst = thisObj as? net.sergeych.lyng.obj.ObjInstance
|
||||
if (inst != null) {
|
||||
val slot = inst.objClass.methodSlotForKey(name)
|
||||
if (slot != null) inst.setMethodSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
// Index this binding within the current frame to help resolve locals across suspension
|
||||
localBindings[name] = rec
|
||||
// If we are a ClosureScope, mirror binding into the caller frame to keep it discoverable
|
||||
@ -595,33 +575,22 @@ open class Scope(
|
||||
return rec
|
||||
}
|
||||
|
||||
private fun bumpClassLayoutIfNeeded(name: String, value: Obj, recordType: ObjRecord.Type) {
|
||||
val cls = thisObj as? net.sergeych.lyng.obj.ObjClass ?: return
|
||||
if (cls.classScope !== this) return
|
||||
if (!(value is Statement || recordType == ObjRecord.Type.Fun || recordType == ObjRecord.Type.Delegated)) return
|
||||
if (cls.members.containsKey(name)) return
|
||||
cls.layoutVersion += 1
|
||||
}
|
||||
|
||||
fun getOrCreateNamespace(name: String): ObjClass {
|
||||
val ns = objects.getOrPut(name) { ObjRecord(ObjNamespace(name), isMutable = false) }.value
|
||||
return ns.objClass
|
||||
}
|
||||
|
||||
inline fun addVoidFn(vararg names: String, crossinline fn: suspend Scope.() -> Unit) {
|
||||
addFn(*names) {
|
||||
fn(this)
|
||||
ObjVoid
|
||||
}
|
||||
fun addVoidFn(vararg names: String, fn: VoidScopeCallable) {
|
||||
addFn(*names, fn = object : ScopeCallable {
|
||||
override suspend fun call(scope: Scope): Obj {
|
||||
fn.call(scope)
|
||||
return ObjVoid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun addFn(vararg names: String, fn: suspend Scope.() -> Obj) {
|
||||
val newFn = object : Statement() {
|
||||
override val pos: Pos = Pos.builtIn
|
||||
|
||||
override suspend fun execute(scope: Scope): Obj = scope.fn()
|
||||
|
||||
}
|
||||
fun addFn(vararg names: String, fn: ScopeCallable) {
|
||||
val newFn = FnStatement(fn)
|
||||
for (name in names) {
|
||||
addItem(
|
||||
name,
|
||||
|
||||
@ -18,14 +18,13 @@
|
||||
package net.sergeych.lyng
|
||||
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.yield
|
||||
import net.sergeych.lyng.Script.Companion.defaultImportManager
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportManager
|
||||
import net.sergeych.lyng.pacman.ModuleBuilder
|
||||
import net.sergeych.lyng.stdlib_included.rootLyng
|
||||
import net.sergeych.lynon.ObjLynonClass
|
||||
import net.sergeych.mp_tools.globalDefer
|
||||
import kotlin.math.*
|
||||
|
||||
@Suppress("TYPE_INTERSECTION_AS_REIFIED_WARNING")
|
||||
@ -59,186 +58,173 @@ class Script(
|
||||
internal val rootScope: Scope = Scope(null).apply {
|
||||
ObjException.addExceptionsToContext(this)
|
||||
addConst("Unset", ObjUnset)
|
||||
addFn("print") {
|
||||
for ((i, a) in args.withIndex()) {
|
||||
if (i > 0) print(' ' + a.toString(this).value)
|
||||
else print(a.toString(this).value)
|
||||
addFn("print", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
for ((i, a) in scp.args.withIndex()) {
|
||||
if (i > 0) print(' ' + a.toString(scp).value)
|
||||
else print(a.toString(scp).value)
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
addFn("println") {
|
||||
for ((i, a) in args.withIndex()) {
|
||||
if (i > 0) print(' ' + a.toString(this).value)
|
||||
else print(a.toString(this).value)
|
||||
})
|
||||
addFn("println", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
for ((i, a) in scp.args.withIndex()) {
|
||||
if (i > 0) print(' ' + a.toString(scp).value)
|
||||
else print(a.toString(scp).value)
|
||||
}
|
||||
println()
|
||||
return ObjVoid
|
||||
}
|
||||
println()
|
||||
ObjVoid
|
||||
}
|
||||
addFn("floor") {
|
||||
val x = args.firstAndOnly()
|
||||
(if (x is ObjInt) x
|
||||
else ObjReal(floor(x.toDouble())))
|
||||
}
|
||||
addFn("ceil") {
|
||||
val x = args.firstAndOnly()
|
||||
(if (x is ObjInt) x
|
||||
else ObjReal(ceil(x.toDouble())))
|
||||
}
|
||||
addFn("round") {
|
||||
val x = args.firstAndOnly()
|
||||
(if (x is ObjInt) x
|
||||
else ObjReal(round(x.toDouble())))
|
||||
}
|
||||
})
|
||||
addFn("floor", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val x = scp.args.firstAndOnly()
|
||||
return (if (x is ObjInt) x
|
||||
else ObjReal(floor(x.toDouble())))
|
||||
}
|
||||
})
|
||||
addFn("ceil", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val x = scp.args.firstAndOnly()
|
||||
return (if (x is ObjInt) x
|
||||
else ObjReal(ceil(x.toDouble())))
|
||||
}
|
||||
})
|
||||
addFn("round", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val x = scp.args.firstAndOnly()
|
||||
return (if (x is ObjInt) x
|
||||
else ObjReal(round(x.toDouble())))
|
||||
}
|
||||
})
|
||||
|
||||
addFn("sin") {
|
||||
ObjReal(sin(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("cos") {
|
||||
ObjReal(cos(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("tan") {
|
||||
ObjReal(tan(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("asin") {
|
||||
ObjReal(asin(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("acos") {
|
||||
ObjReal(acos(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("atan") {
|
||||
ObjReal(atan(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("sin", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(sin(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("cos", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(cos(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("tan", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(tan(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("asin", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(asin(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("acos", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(acos(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("atan", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(atan(scp.args.firstAndOnly().toDouble())) })
|
||||
|
||||
addFn("sinh") {
|
||||
ObjReal(sinh(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("cosh") {
|
||||
ObjReal(cosh(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("tanh") {
|
||||
ObjReal(tanh(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("asinh") {
|
||||
ObjReal(asinh(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("acosh") {
|
||||
ObjReal(acosh(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("atanh") {
|
||||
ObjReal(atanh(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("sinh", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(sinh(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("cosh", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(cosh(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("tanh", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(tanh(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("asinh", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(asinh(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("acosh", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(acosh(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("atanh", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(atanh(scp.args.firstAndOnly().toDouble())) })
|
||||
|
||||
addFn("exp") {
|
||||
ObjReal(exp(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("ln") {
|
||||
ObjReal(ln(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("exp", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(exp(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("ln", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(ln(scp.args.firstAndOnly().toDouble())) })
|
||||
|
||||
addFn("log10") {
|
||||
ObjReal(log10(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("log10", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(log10(scp.args.firstAndOnly().toDouble())) })
|
||||
|
||||
addFn("log2") {
|
||||
ObjReal(log2(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("log2", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(log2(scp.args.firstAndOnly().toDouble())) })
|
||||
|
||||
addFn("pow") {
|
||||
requireExactCount(2)
|
||||
ObjReal(
|
||||
(args[0].toDouble()).pow(args[1].toDouble())
|
||||
)
|
||||
}
|
||||
addFn("sqrt") {
|
||||
ObjReal(
|
||||
sqrt(args.firstAndOnly().toDouble())
|
||||
)
|
||||
}
|
||||
addFn("abs") {
|
||||
val x = args.firstAndOnly()
|
||||
if (x is ObjInt) ObjInt(x.value.absoluteValue) else ObjReal(x.toDouble().absoluteValue)
|
||||
}
|
||||
addFn("pow", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireExactCount(2)
|
||||
return ObjReal((scp.args[0].toDouble()).pow(scp.args[1].toDouble()))
|
||||
}
|
||||
})
|
||||
addFn("sqrt", fn = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjReal(sqrt(scp.args.firstAndOnly().toDouble())) })
|
||||
addFn("abs", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val x = scp.args.firstAndOnly()
|
||||
return if (x is ObjInt) ObjInt(x.value.absoluteValue) else ObjReal(x.toDouble().absoluteValue)
|
||||
}
|
||||
})
|
||||
|
||||
addFnDoc(
|
||||
addFnDoc<Obj>(
|
||||
"clamp",
|
||||
doc = "Clamps the value within the specified range. If the value is outside the range, it is set to the nearest boundary. Respects inclusive/exclusive range ends.",
|
||||
params = listOf(ParamDoc("value"), ParamDoc("range")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val value = requiredArg<Obj>(0)
|
||||
val range = requiredArg<ObjRange>(1)
|
||||
|
||||
var result = value
|
||||
if (range.start != null && !range.start.isNull) {
|
||||
if (result.compareTo(this, range.start) < 0) {
|
||||
result = range.start
|
||||
}
|
||||
}
|
||||
if (range.end != null && !range.end.isNull) {
|
||||
val cmp = range.end.compareTo(this, result)
|
||||
if (range.isEndInclusive) {
|
||||
if (cmp < 0) result = range.end
|
||||
} else {
|
||||
if (cmp <= 0) {
|
||||
if (range.end is ObjInt) {
|
||||
result = ObjInt.of(range.end.value - 1)
|
||||
} else if (range.end is ObjChar) {
|
||||
result = ObjChar((range.end.value.code - 1).toChar())
|
||||
} else {
|
||||
// For types where we can't easily find "previous" value (like Real),
|
||||
// we just return the exclusive boundary as a fallback.
|
||||
result = range.end
|
||||
moduleName = "lyng.stdlib",
|
||||
fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val value = scp.requiredArg<Obj>(0)
|
||||
val range = scp.requiredArg<ObjRange>(1)
|
||||
|
||||
var result = value
|
||||
if (range.start != null && !range.start.isNull) {
|
||||
if (result.compareTo(scp, range.start) < 0) {
|
||||
result = range.start
|
||||
}
|
||||
}
|
||||
if (range.end != null && !range.end.isNull) {
|
||||
val cmp = range.end.compareTo(scp, result)
|
||||
if (range.isEndInclusive) {
|
||||
if (cmp < 0) result = range.end
|
||||
} else {
|
||||
if (cmp <= 0) {
|
||||
if (range.end is ObjInt) {
|
||||
result = ObjInt.of(range.end.value - 1)
|
||||
} else if (range.end is ObjChar) {
|
||||
result = ObjChar((range.end.value.code - 1).toChar())
|
||||
} else {
|
||||
// For types where we can't easily find "previous" value (like Real),
|
||||
// we just return the exclusive boundary as a fallback.
|
||||
result = range.end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
)
|
||||
|
||||
addVoidFn("assert") {
|
||||
val cond = requiredArg<ObjBool>(0)
|
||||
val message = if (args.size > 1)
|
||||
": " + (args[1] as Statement).execute(this).toString(this).value
|
||||
else ""
|
||||
if (!cond.value == true)
|
||||
raiseError(ObjAssertionFailedException(this, "Assertion failed$message"))
|
||||
}
|
||||
addVoidFn("assert", fn = object : VoidScopeCallable {
|
||||
override suspend fun call(scp: Scope) {
|
||||
val cond = scp.requiredArg<ObjBool>(0)
|
||||
val message = if (scp.args.size > 1)
|
||||
": " + (scp.args[1] as Statement).execute(scp).toString(scp).value
|
||||
else ""
|
||||
if (!cond.value == true)
|
||||
scp.raiseError(ObjAssertionFailedException(scp, "Assertion failed$message"))
|
||||
}
|
||||
})
|
||||
|
||||
addVoidFn("assertEquals") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if (a.compareTo(this, b) != 0)
|
||||
raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"
|
||||
addVoidFn("assertEquals", fn = object : VoidScopeCallable {
|
||||
override suspend fun call(scp: Scope) {
|
||||
val a = scp.requiredArg<Obj>(0)
|
||||
val b = scp.requiredArg<Obj>(1)
|
||||
if (a.compareTo(scp, b) != 0)
|
||||
scp.raiseError(
|
||||
ObjAssertionFailedException(
|
||||
scp,
|
||||
"Assertion failed: ${a.inspect(scp)} == ${b.inspect(scp)}"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
// alias used in tests
|
||||
addVoidFn("assertEqual") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if (a.compareTo(this, b) != 0)
|
||||
raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"
|
||||
addVoidFn("assertEqual", fn = object : VoidScopeCallable {
|
||||
override suspend fun call(scp: Scope) {
|
||||
val a = scp.requiredArg<Obj>(0)
|
||||
val b = scp.requiredArg<Obj>(1)
|
||||
if (a.compareTo(scp, b) != 0)
|
||||
scp.raiseError(
|
||||
ObjAssertionFailedException(
|
||||
scp,
|
||||
"Assertion failed: ${a.inspect(scp)} == ${b.inspect(scp)}"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
addVoidFn("assertNotEquals") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if (a.compareTo(this, b) == 0)
|
||||
raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Assertion failed: ${a.inspect(this)} != ${b.inspect(this)}"
|
||||
}
|
||||
})
|
||||
addVoidFn("assertNotEquals", fn = object : VoidScopeCallable {
|
||||
override suspend fun call(scp: Scope) {
|
||||
val a = scp.requiredArg<Obj>(0)
|
||||
val b = scp.requiredArg<Obj>(1)
|
||||
if (a.compareTo(scp, b) == 0)
|
||||
scp.raiseError(
|
||||
ObjAssertionFailedException(
|
||||
scp,
|
||||
"Assertion failed: ${a.inspect(scp)} != ${b.inspect(scp)}"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
addFnDoc(
|
||||
}
|
||||
})
|
||||
addFnDoc<Obj>(
|
||||
"assertThrows",
|
||||
doc = """
|
||||
Asserts that the provided code block throws an exception, with or without exception:
|
||||
@ -249,83 +235,97 @@ class Script(
|
||||
If an expected exception class is provided,
|
||||
it checks that the thrown exception is of that class. If no expected class is provided, any exception
|
||||
will be accepted.
|
||||
""".trimIndent()
|
||||
) {
|
||||
val code: Statement
|
||||
val expectedClass: ObjClass?
|
||||
when (args.size) {
|
||||
1 -> {
|
||||
code = requiredArg<Statement>(0)
|
||||
expectedClass = null
|
||||
}
|
||||
""".trimIndent(),
|
||||
fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val code: Statement
|
||||
val expectedClass: ObjClass?
|
||||
when (scp.args.size) {
|
||||
1 -> {
|
||||
code = scp.requiredArg<Statement>(0)
|
||||
expectedClass = null
|
||||
}
|
||||
|
||||
2 -> {
|
||||
code = requiredArg<Statement>(1)
|
||||
expectedClass = requiredArg<ObjClass>(0)
|
||||
}
|
||||
2 -> {
|
||||
code = scp.requiredArg<Statement>(1)
|
||||
expectedClass = scp.requiredArg<ObjClass>(0)
|
||||
}
|
||||
|
||||
else -> raiseIllegalArgument("Expected 1 or 2 arguments, got ${args.size}")
|
||||
}
|
||||
val result = try {
|
||||
code.execute(this)
|
||||
null
|
||||
} catch (e: ExecutionError) {
|
||||
e.errorObject
|
||||
} catch (_: ScriptError) {
|
||||
ObjNull
|
||||
}
|
||||
if (result == null) raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Expected exception but nothing was thrown"
|
||||
)
|
||||
)
|
||||
expectedClass?.let {
|
||||
if (!result.isInstanceOf(it)) {
|
||||
val actual = if (result is ObjException) result.exceptionClass else result.objClass
|
||||
raiseError("Expected $it, got $actual")
|
||||
else -> scp.raiseIllegalArgument("Expected 1 or 2 arguments, got ${scp.args.size}")
|
||||
}
|
||||
val result = try {
|
||||
code.execute(scp)
|
||||
null
|
||||
} catch (e: ExecutionError) {
|
||||
e.errorObject
|
||||
} catch (_: ScriptError) {
|
||||
ObjNull
|
||||
}
|
||||
if (result == null) scp.raiseError(
|
||||
ObjAssertionFailedException(
|
||||
scp,
|
||||
"Expected exception but nothing was thrown"
|
||||
)
|
||||
)
|
||||
expectedClass?.let {
|
||||
if (!result.isInstanceOf(it)) {
|
||||
val actual = if (result is ObjException) result.exceptionClass else result.objClass
|
||||
scp.raiseError("Expected $it, got $actual")
|
||||
}
|
||||
}
|
||||
return result ?: ObjNull
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
)
|
||||
|
||||
addFn("dynamic") {
|
||||
ObjDynamic.create(this, requireOnlyArg())
|
||||
}
|
||||
addFn("dynamic", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjDynamic.create(scp, scp.requireOnlyArg())
|
||||
}
|
||||
})
|
||||
|
||||
val root = this
|
||||
val mathClass = ObjClass("Math").apply {
|
||||
addFn("sqrt") {
|
||||
ObjReal(sqrt(args.firstAndOnly().toDouble()))
|
||||
}
|
||||
addFn("sqrt", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjReal(sqrt(scp.args.firstAndOnly().toDouble()))
|
||||
}
|
||||
})
|
||||
}
|
||||
addItem("Math", false, ObjInstance(mathClass).apply {
|
||||
instanceScope = Scope(root, thisObj = this)
|
||||
})
|
||||
|
||||
addFn("require") {
|
||||
val condition = requiredArg<ObjBool>(0)
|
||||
if (!condition.value) {
|
||||
var message = args.list.getOrNull(1)
|
||||
if (message is Statement) message = message.execute(this)
|
||||
raiseIllegalArgument(message?.toString() ?: "requirement not met")
|
||||
addFn("require", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val condition = scp.requiredArg<ObjBool>(0)
|
||||
if (!condition.value) {
|
||||
var message = scp.args.list.getOrNull(1)
|
||||
if (message is Statement) message = message.execute(scp)
|
||||
scp.raiseIllegalArgument(message?.toString() ?: "requirement not met")
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
addFn("check") {
|
||||
val condition = requiredArg<ObjBool>(0)
|
||||
if (!condition.value) {
|
||||
var message = args.list.getOrNull(1)
|
||||
if (message is Statement) message = message.execute(this)
|
||||
raiseIllegalState(message?.toString() ?: "check failed")
|
||||
})
|
||||
addFn("check", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val condition = scp.requiredArg<ObjBool>(0)
|
||||
if (!condition.value) {
|
||||
var message = scp.args.list.getOrNull(1)
|
||||
if (message is Statement) message = message.execute(scp)
|
||||
scp.raiseIllegalState(message?.toString() ?: "check failed")
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
addFn("traceScope") {
|
||||
this.trace(args.getOrNull(0)?.toString() ?: "")
|
||||
ObjVoid
|
||||
}
|
||||
})
|
||||
addFn("traceScope", fn = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.trace(scp.args.getOrNull(0)?.toString() ?: "")
|
||||
return ObjVoid
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
addVoidFn("delay") {
|
||||
val a = args.firstAndOnly()
|
||||
when (a) {
|
||||
@ -335,7 +335,7 @@ class Script(
|
||||
else -> raiseIllegalArgument("Expected Int, Real or Duration, got ${a.inspect(this)}")
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
addConst("Object", rootObjectType)
|
||||
addConst("Real", ObjReal.type)
|
||||
addConst("String", ObjString.type)
|
||||
@ -362,7 +362,7 @@ class Script(
|
||||
addConst("Flow", ObjFlow.type)
|
||||
|
||||
addConst("Regex", ObjRegex.type)
|
||||
|
||||
/*
|
||||
addFn("launch") {
|
||||
val callable = requireOnlyArg<Statement>()
|
||||
ObjDeferred(globalDefer {
|
||||
@ -380,7 +380,7 @@ class Script(
|
||||
// we'll need it for the producer
|
||||
ObjFlow(requireOnlyArg<Statement>(), this)
|
||||
}
|
||||
|
||||
*/
|
||||
val pi = ObjReal(PI)
|
||||
addConstDoc(
|
||||
name = "π",
|
||||
@ -403,60 +403,69 @@ class Script(
|
||||
addTextPackages(
|
||||
rootLyng
|
||||
)
|
||||
addPackage("lyng.buffer") {
|
||||
it.addConstDoc(
|
||||
name = "Buffer",
|
||||
value = ObjBuffer.type,
|
||||
doc = "Immutable sequence of bytes. Use for binary data and IO.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
it.addConstDoc(
|
||||
name = "MutableBuffer",
|
||||
value = ObjMutableBuffer.type,
|
||||
doc = "Mutable byte buffer. Supports in-place modifications.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
}
|
||||
addPackage("lyng.serialization") {
|
||||
it.addConstDoc(
|
||||
name = "Lynon",
|
||||
value = ObjLynonClass,
|
||||
doc = "Lynon serialization utilities: encode/decode data structures to a portable binary/text form.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
}
|
||||
addPackage("lyng.time") {
|
||||
it.addConstDoc(
|
||||
name = "Instant",
|
||||
value = ObjInstant.type,
|
||||
doc = "Point in time (epoch-based).",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
it.addConstDoc(
|
||||
name = "DateTime",
|
||||
value = ObjDateTime.type,
|
||||
doc = "Point in time in a specific time zone.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
it.addConstDoc(
|
||||
name = "Duration",
|
||||
value = ObjDuration.type,
|
||||
doc = "Time duration with millisecond precision.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
it.addVoidFnDoc(
|
||||
"delay",
|
||||
doc = "Suspend for the given time. Accepts Duration, Int seconds, or Real seconds."
|
||||
) {
|
||||
val a = args.firstAndOnly()
|
||||
when (a) {
|
||||
is ObjInt -> delay(a.value * 1000)
|
||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||
is ObjDuration -> delay(a.duration)
|
||||
else -> raiseIllegalArgument("Expected Duration, Int or Real, got ${a.inspect(this)}")
|
||||
}
|
||||
addPackage("lyng.buffer", object : ModuleBuilder {
|
||||
override suspend fun build(ms: ModuleScope) {
|
||||
ms.addConstDoc(
|
||||
name = "Buffer",
|
||||
value = ObjBuffer.type,
|
||||
doc = "Immutable sequence of bytes. Use for binary data and IO.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
ms.addConstDoc(
|
||||
name = "MutableBuffer",
|
||||
value = ObjMutableBuffer.type,
|
||||
doc = "Mutable byte buffer. Supports in-place modifications.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
addPackage("lyng.serialization", object : ModuleBuilder {
|
||||
override suspend fun build(ms: ModuleScope) {
|
||||
ms.addConstDoc(
|
||||
name = "Lynon",
|
||||
value = ObjLynonClass,
|
||||
doc = "Lynon serialization utilities: encode/decode data structures to a portable binary/text form.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
}
|
||||
})
|
||||
addPackage("lyng.time", object : ModuleBuilder {
|
||||
override suspend fun build(ms: ModuleScope) {
|
||||
ms.addConstDoc(
|
||||
name = "Instant",
|
||||
value = ObjInstant.type,
|
||||
doc = "Point in time (epoch-based).",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
ms.addConstDoc(
|
||||
name = "DateTime",
|
||||
value = ObjDateTime.type,
|
||||
doc = "Point in time in a specific time zone.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
ms.addConstDoc(
|
||||
name = "Duration",
|
||||
value = ObjDuration.type,
|
||||
doc = "Time duration with millisecond precision.",
|
||||
type = type("lyng.Class")
|
||||
)
|
||||
ms.addVoidFnDoc(
|
||||
"delay",
|
||||
doc = "Suspend for the given time. Accepts Duration, Int seconds, or Real seconds.",
|
||||
fn = object : VoidScopeCallable {
|
||||
override suspend fun call(scp: Scope) {
|
||||
val a = scp.args.firstAndOnly()
|
||||
when (a) {
|
||||
is ObjInt -> delay(a.value * 1000)
|
||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||
is ObjDuration -> delay(a.duration)
|
||||
else -> scp.raiseIllegalArgument("Expected Duration, Int or Real, got ${a.inspect(scp)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,9 +17,7 @@
|
||||
|
||||
package net.sergeych.lyng.miniast
|
||||
|
||||
import net.sergeych.lyng.ModuleScope
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Visibility
|
||||
import net.sergeych.lyng.*
|
||||
import net.sergeych.lyng.obj.Obj
|
||||
import net.sergeych.lyng.obj.ObjClass
|
||||
import net.sergeych.lyng.obj.ObjVoid
|
||||
@ -39,10 +37,10 @@ inline fun <reified T : Obj> Scope.addFnDoc(
|
||||
returns: TypeDoc? = null,
|
||||
tags: Map<String, List<String>> = emptyMap(),
|
||||
moduleName: String? = null,
|
||||
crossinline fn: suspend Scope.() -> T
|
||||
fn: ScopeCallable
|
||||
) {
|
||||
// Register runtime function(s)
|
||||
addFn(*names) { fn() }
|
||||
addFn(*names, fn = fn)
|
||||
// Determine module
|
||||
val mod = moduleName ?: findModuleNameOrUnknown()
|
||||
// Register docs once per name
|
||||
@ -56,7 +54,7 @@ inline fun Scope.addVoidFnDoc(
|
||||
doc: String,
|
||||
tags: Map<String, List<String>> = emptyMap(),
|
||||
moduleName: String? = null,
|
||||
crossinline fn: suspend Scope.() -> Unit
|
||||
fn: VoidScopeCallable
|
||||
) {
|
||||
addFnDoc<ObjVoid>(
|
||||
*names,
|
||||
@ -64,11 +62,14 @@ inline fun Scope.addVoidFnDoc(
|
||||
params = emptyList(),
|
||||
returns = null,
|
||||
tags = tags,
|
||||
moduleName = moduleName
|
||||
) {
|
||||
fn(this)
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = moduleName,
|
||||
fn = object : ScopeCallable {
|
||||
override suspend fun call(sc: Scope): Obj {
|
||||
fn.call(sc)
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun Scope.addConstDoc(
|
||||
@ -97,7 +98,7 @@ fun ObjClass.addFnDoc(
|
||||
visibility: Visibility = Visibility.Public,
|
||||
tags: Map<String, List<String>> = emptyMap(),
|
||||
moduleName: String? = null,
|
||||
code: suspend Scope.() -> Obj
|
||||
code: ScopeCallable
|
||||
) {
|
||||
// Register runtime method
|
||||
addFn(name, isOpen, visibility, code = code)
|
||||
@ -135,7 +136,7 @@ fun ObjClass.addClassFnDoc(
|
||||
isOpen: Boolean = false,
|
||||
tags: Map<String, List<String>> = emptyMap(),
|
||||
moduleName: String? = null,
|
||||
code: suspend Scope.() -> Obj
|
||||
code: ScopeCallable
|
||||
) {
|
||||
addClassFn(name, isOpen, code)
|
||||
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
||||
@ -151,8 +152,8 @@ fun ObjClass.addPropertyDoc(
|
||||
type: TypeDoc? = null,
|
||||
visibility: Visibility = Visibility.Public,
|
||||
moduleName: String? = null,
|
||||
getter: (suspend Scope.() -> Obj)? = null,
|
||||
setter: (suspend Scope.(Obj) -> Unit)? = null
|
||||
getter: ScopeCallable? = null,
|
||||
setter: ScopeCallable? = null
|
||||
) {
|
||||
addProperty(name, getter, setter, visibility)
|
||||
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -32,29 +32,41 @@ typealias DocCompiler = Compiler
|
||||
*/
|
||||
typealias Accessor = ObjRef
|
||||
|
||||
interface AccessorGetter {
|
||||
suspend fun call(scope: Scope): ObjRecord
|
||||
}
|
||||
|
||||
interface AccessorSetter {
|
||||
suspend fun call(scope: Scope, value: Obj)
|
||||
}
|
||||
|
||||
/** Lambda-based reference for edge cases that still construct access via lambdas. */
|
||||
private class LambdaRef(
|
||||
private val getterFn: suspend (Scope) -> ObjRecord,
|
||||
private val setterFn: (suspend (Pos, Scope, Obj) -> Unit)? = null
|
||||
private val getterFn: AccessorGetter,
|
||||
private val setterFn: AccessorSetter? = null
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord = getterFn(scope)
|
||||
override suspend fun get(scope: Scope): ObjRecord = getterFn.call(scope)
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
val s = setterFn ?: throw ScriptError(pos, "can't assign value")
|
||||
s(pos, scope, newValue)
|
||||
s.call(scope, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
// Factory functions to preserve current call sites like `Accessor { ... }`
|
||||
fun Accessor(getter: suspend (Scope) -> ObjRecord): Accessor = LambdaRef(getter)
|
||||
fun Accessor(getter: AccessorGetter): Accessor = LambdaRef(getter)
|
||||
fun Accessor(
|
||||
getter: suspend (Scope) -> ObjRecord,
|
||||
setter: suspend (Scope, Obj) -> Unit
|
||||
): Accessor = LambdaRef(getter) { _, scope, value -> setter(scope, value) }
|
||||
getter: AccessorGetter,
|
||||
setter: AccessorSetter
|
||||
): Accessor = LambdaRef(getter, setter)
|
||||
|
||||
// Compatibility shims used throughout Compiler: `.getter(...)` and `.setter(pos)`
|
||||
val Accessor.getter: suspend (Scope) -> ObjRecord
|
||||
get() = { scope -> this.get(scope) }
|
||||
val Accessor.getter: AccessorGetter
|
||||
get() = object : AccessorGetter {
|
||||
override suspend fun call(scope: Scope): ObjRecord = this@getter.get(scope)
|
||||
}
|
||||
|
||||
fun Accessor.setter(pos: Pos): suspend (Scope, Obj) -> Unit = { scope, newValue ->
|
||||
this.setAt(pos, scope, newValue)
|
||||
fun Accessor.setter(pos: Pos): AccessorSetter = object : AccessorSetter {
|
||||
override suspend fun call(scope: Scope, value: Obj) {
|
||||
this@setter.setAt(pos, scope, value)
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,14 @@ import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
|
||||
fun interface OnNotFound {
|
||||
suspend fun call(): Obj?
|
||||
}
|
||||
|
||||
fun interface EnumerateCallback {
|
||||
suspend fun call(element: Obj): Boolean
|
||||
}
|
||||
|
||||
open class Obj {
|
||||
|
||||
open val isConst: Boolean = false
|
||||
@ -91,7 +99,7 @@ open class Obj {
|
||||
scope: Scope,
|
||||
name: String,
|
||||
args: Arguments = Arguments.EMPTY,
|
||||
onNotFoundResult: (suspend () -> Obj?)? = null
|
||||
onNotFoundResult: OnNotFound? = null
|
||||
): Obj {
|
||||
// 0. Prefer private member of current class context
|
||||
scope.currentClassCtx?.let { caller ->
|
||||
@ -100,7 +108,7 @@ open class Obj {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, caller)
|
||||
} else if (rec.type != ObjRecord.Type.Delegated) {
|
||||
return rec.value.invoke(scope, this, args, caller)
|
||||
return rec.value.invokeCallable(scope, this, args, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,12 +122,12 @@ open class Obj {
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invokeCallable ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type != ObjRecord.Type.Delegated) {
|
||||
return rec.value.invoke(scope, this, args, decl)
|
||||
return rec.value.invokeCallable(scope, this, args, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,7 +138,7 @@ open class Obj {
|
||||
if (extension.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (extension.value as ObjProperty).callGetter(scope, this, extension.declaringClass)
|
||||
} else if (extension.type != ObjRecord.Type.Delegated) {
|
||||
return extension.value.invoke(scope, this, args)
|
||||
return extension.value.invokeCallable(scope, this, args)
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,18 +149,18 @@ open class Obj {
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invokeCallable ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type != ObjRecord.Type.Delegated) {
|
||||
return rec.value.invoke(scope, this, args, decl)
|
||||
return rec.value.invokeCallable(scope, this, args, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onNotFoundResult?.invoke()
|
||||
return onNotFoundResult?.call()
|
||||
?: scope.raiseError(
|
||||
"no such member: $name on ${objClass.className}. Considered order: ${objClass.renderLinearization(true)}. " +
|
||||
"Tip: try this@Base.$name(...) or (obj as Base).$name(...) if ambiguous"
|
||||
@ -174,9 +182,11 @@ open class Obj {
|
||||
open suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if (other === this) return 0
|
||||
if (other === ObjNull || other === ObjUnset || other === ObjVoid) return 2
|
||||
return invokeInstanceMethod(scope, "compareTo", Arguments(other)) {
|
||||
scope.raiseNotImplemented("compareTo for ${objClass.className}")
|
||||
}.cast<ObjInt>(scope).toInt()
|
||||
return invokeInstanceMethod(scope, "compareTo", Arguments(other), onNotFoundResult = object : OnNotFound {
|
||||
override suspend fun call(): Obj? {
|
||||
scope.raiseNotImplemented("compareTo for ${objClass.className}")
|
||||
}
|
||||
}).toInt()
|
||||
}
|
||||
|
||||
open suspend fun equals(scope: Scope, other: Obj): Boolean {
|
||||
@ -202,16 +212,16 @@ open class Obj {
|
||||
*
|
||||
* IF callback returns false, iteration is stopped.
|
||||
*/
|
||||
open suspend fun enumerate(scope: Scope, callback: suspend (Obj) -> Boolean) {
|
||||
open suspend fun enumerate(scope: Scope, callback: EnumerateCallback) {
|
||||
val iterator = invokeInstanceMethod(scope, "iterator")
|
||||
val hasNext = iterator.getInstanceMethod(scope, "hasNext")
|
||||
val next = iterator.getInstanceMethod(scope, "next")
|
||||
var closeIt = false
|
||||
try {
|
||||
while (hasNext.invoke(scope, iterator).toBool()) {
|
||||
val nextValue = next.invoke(scope, iterator)
|
||||
while (hasNext.invokeCallable(scope, iterator).toBool()) {
|
||||
val nextValue = next.invokeCallable(scope, iterator)
|
||||
val shouldContinue = try {
|
||||
callback(nextValue)
|
||||
callback.call(nextValue)
|
||||
} catch (e: Exception) {
|
||||
// iteration aborted due to exception in callback
|
||||
closeIt = true
|
||||
@ -448,7 +458,7 @@ open class Obj {
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
val resolved = resolveRecord(scope, rec, name, caller)
|
||||
if (resolved.type == ObjRecord.Type.Fun && resolved.value is Statement)
|
||||
return resolved.copy(value = resolved.value.invoke(scope, this, Arguments.EMPTY, caller))
|
||||
return resolved.copy(value = resolved.value.invokeCallable(scope, this, Arguments.EMPTY, caller))
|
||||
return resolved
|
||||
}
|
||||
}
|
||||
@ -462,7 +472,7 @@ open class Obj {
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val resolved = resolveRecord(scope, rec, name, decl)
|
||||
if (resolved.type == ObjRecord.Type.Fun && resolved.value is Statement)
|
||||
return resolved.copy(value = resolved.value.invoke(scope, this, Arguments.EMPTY, decl))
|
||||
return resolved.copy(value = resolved.value.invokeCallable(scope, this, Arguments.EMPTY, decl))
|
||||
return resolved
|
||||
}
|
||||
}
|
||||
@ -472,7 +482,7 @@ open class Obj {
|
||||
if (extension != null) {
|
||||
val resolved = resolveRecord(scope, extension, name, extension.declaringClass)
|
||||
if (resolved.type == ObjRecord.Type.Fun && resolved.value is Statement)
|
||||
return resolved.copy(value = resolved.value.invoke(scope, this, Arguments.EMPTY, extension.declaringClass))
|
||||
return resolved.copy(value = resolved.value.invokeCallable(scope, this, Arguments.EMPTY, extension.declaringClass))
|
||||
return resolved
|
||||
}
|
||||
|
||||
@ -486,7 +496,7 @@ open class Obj {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access field ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
val resolved = resolveRecord(scope, rec, name, decl)
|
||||
if (resolved.type == ObjRecord.Type.Fun && resolved.value is Statement)
|
||||
return resolved.copy(value = resolved.value.invoke(scope, this, Arguments.EMPTY, decl))
|
||||
return resolved.copy(value = resolved.value.invokeCallable(scope, this, Arguments.EMPTY, decl))
|
||||
return resolved
|
||||
}
|
||||
}
|
||||
@ -501,21 +511,17 @@ open class Obj {
|
||||
if (obj.type == ObjRecord.Type.Delegated) {
|
||||
val del = obj.delegate ?: scope.raiseError("Internal error: delegated property $name has no delegate")
|
||||
val th = if (this === ObjVoid) ObjNull else this
|
||||
if (del.objClass.getInstanceMemberOrNull("getValue") == null) {
|
||||
val wrapper = object : Statement() {
|
||||
val res = del.invokeInstanceMethod(scope, "getValue", Arguments(th, ObjString(name)), onNotFoundResult = {
|
||||
// If getValue not found, return a wrapper that calls invokeCallable
|
||||
object : Statement() {
|
||||
override val pos: Pos = Pos.builtIn
|
||||
override suspend fun execute(s: Scope): Obj {
|
||||
val th2 = if (s.thisObj === ObjVoid) ObjNull else s.thisObj
|
||||
val allArgs = (listOf(th2, ObjString(name)) + s.args.list).toTypedArray()
|
||||
return del.invokeInstanceMethod(s, "invoke", Arguments(*allArgs))
|
||||
return del.invokeInstanceMethod(s, "invokeCallable", Arguments(*allArgs))
|
||||
}
|
||||
}
|
||||
return obj.copy(
|
||||
value = wrapper,
|
||||
type = ObjRecord.Type.Other
|
||||
)
|
||||
}
|
||||
val res = del.invokeInstanceMethod(scope, "getValue", Arguments(th, ObjString(name)))
|
||||
})
|
||||
return obj.copy(
|
||||
value = res,
|
||||
type = ObjRecord.Type.Other
|
||||
@ -609,18 +615,20 @@ open class Obj {
|
||||
scope.raiseNotImplemented()
|
||||
}
|
||||
|
||||
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj =
|
||||
suspend fun invokeCallable(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj =
|
||||
if (PerfFlags.SCOPE_POOL)
|
||||
scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
||||
if (declaringClass != null) child.currentClassCtx = declaringClass
|
||||
callOn(child)
|
||||
}
|
||||
scope.withChildFrame(args, newThisObj = thisObj, block = object : ScopeBlock<Obj> {
|
||||
override suspend fun call(child: Scope): Obj {
|
||||
if (declaringClass != null) child.currentClassCtx = declaringClass
|
||||
return callOn(child)
|
||||
}
|
||||
})
|
||||
else
|
||||
callOn(scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
||||
if (declaringClass != null) it.currentClassCtx = declaringClass
|
||||
})
|
||||
|
||||
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
||||
suspend fun invokeCallable(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
||||
callOn(
|
||||
scope.createChildScope(
|
||||
scope.pos,
|
||||
@ -629,7 +637,7 @@ open class Obj {
|
||||
)
|
||||
)
|
||||
|
||||
suspend fun invoke(scope: Scope, thisObj: Obj): Obj =
|
||||
suspend fun invokeCallable(scope: Scope, thisObj: Obj): Obj =
|
||||
callOn(
|
||||
scope.createChildScope(
|
||||
scope.pos,
|
||||
@ -638,7 +646,7 @@ open class Obj {
|
||||
)
|
||||
)
|
||||
|
||||
suspend fun invoke(scope: Scope, atPos: Pos, thisObj: Obj, args: Arguments): Obj =
|
||||
suspend fun invokeCallable(scope: Scope, atPos: Pos, thisObj: Obj, args: Arguments): Obj =
|
||||
callOn(scope.createChildScope(atPos, args = args, newThisObj = thisObj))
|
||||
|
||||
|
||||
@ -685,117 +693,138 @@ open class Obj {
|
||||
name = "toString",
|
||||
doc = "Returns a string representation of the object.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisObj.toString(this, true)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisObj.toString(scp, true)
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "inspect",
|
||||
doc = "Returns a detailed string representation for debugging.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisObj.inspect(this).toObj()
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisObj.inspect(scp).toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "contains",
|
||||
doc = "Returns true if the object contains the given element.",
|
||||
params = listOf(ParamDoc("element")),
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjBool(thisObj.contains(this, args.firstAndOnly()))
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjBool(scp.thisObj.contains(scp, scp.args.firstAndOnly()))
|
||||
}
|
||||
)
|
||||
// utilities
|
||||
addFnDoc(
|
||||
name = "let",
|
||||
doc = "Calls the specified function block with `this` value as its argument and returns its result.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
args.firstAndOnly().callOn(createChildScope(Arguments(thisObj)))
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.args.firstAndOnly().callOn(scp.createChildScope(Arguments(scp.thisObj)))
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "apply",
|
||||
doc = "Calls the specified function block with `this` value as its receiver and returns `this` value.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val body = args.firstAndOnly()
|
||||
(thisObj as? ObjInstance)?.let {
|
||||
body.callOn(ApplyScope(this, it.instanceScope))
|
||||
} ?: run {
|
||||
body.callOn(this)
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val body = scp.args.firstAndOnly()
|
||||
(scp.thisObj as? ObjInstance)?.let {
|
||||
body.callOn(ApplyScope(scp, it.instanceScope))
|
||||
} ?: run {
|
||||
body.callOn(scp)
|
||||
}
|
||||
return scp.thisObj
|
||||
}
|
||||
}
|
||||
thisObj
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "also",
|
||||
doc = "Calls the specified function block with `this` value as its argument and returns `this` value.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
args.firstAndOnly().callOn(createChildScope(Arguments(thisObj)))
|
||||
thisObj
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.args.firstAndOnly().callOn(scp.createChildScope(Arguments(scp.thisObj)))
|
||||
return scp.thisObj
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "run",
|
||||
doc = "Calls the specified function block with `this` value as its receiver and returns its result.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
args.firstAndOnly().callOn(this)
|
||||
}
|
||||
addFn("getAt") {
|
||||
requireExactCount(1)
|
||||
thisObj.getAt(this, requiredArg<Obj>(0))
|
||||
}
|
||||
addFn("putAt") {
|
||||
requireExactCount(2)
|
||||
val newValue = args[1]
|
||||
thisObj.putAt(this, requiredArg<Obj>(0), newValue)
|
||||
newValue
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.args.firstAndOnly().callOn(scp)
|
||||
}
|
||||
)
|
||||
addFn("getAt", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireExactCount(1)
|
||||
return scp.thisObj.getAt(scp, scp.requiredArg<Obj>(0))
|
||||
}
|
||||
})
|
||||
addFn("putAt", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireExactCount(2)
|
||||
val newValue = scp.args[1]
|
||||
scp.thisObj.putAt(scp, scp.requiredArg<Obj>(0), newValue)
|
||||
return newValue
|
||||
}
|
||||
})
|
||||
addFnDoc(
|
||||
name = "toJsonString",
|
||||
doc = "Encodes this object to a JSON string.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisObj.toJson(this).toString().toObj()
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.thisObj.toJson(scp).toString().toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "clamp",
|
||||
doc = "Clamps this value within the specified range. If the value is outside the range, it is set to the nearest boundary. Respects inclusive/exclusive range ends.",
|
||||
params = listOf(ParamDoc("range")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val range = requiredArg<ObjRange>(0)
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val range = scp.requiredArg<ObjRange>(0)
|
||||
|
||||
var result = thisObj
|
||||
if (range.start != null && !range.start.isNull) {
|
||||
if (result.compareTo(this, range.start) < 0) {
|
||||
result = range.start
|
||||
}
|
||||
}
|
||||
if (range.end != null && !range.end.isNull) {
|
||||
val cmp = range.end.compareTo(this, result)
|
||||
if (range.isEndInclusive) {
|
||||
if (cmp < 0) result = range.end
|
||||
} else {
|
||||
if (cmp <= 0) {
|
||||
if (range.end is ObjInt) {
|
||||
result = ObjInt.of(range.end.value - 1)
|
||||
} else if (range.end is ObjChar) {
|
||||
result = ObjChar((range.end.value.code - 1).toChar())
|
||||
} else {
|
||||
result = range.end
|
||||
var result = scp.thisObj
|
||||
if (range.start != null && !range.start.isNull) {
|
||||
if (result.compareTo(scp, range.start) < 0) {
|
||||
result = range.start
|
||||
}
|
||||
}
|
||||
if (range.end != null && !range.end.isNull) {
|
||||
val cmp = range.end.compareTo(scp, result)
|
||||
if (range.isEndInclusive) {
|
||||
if (cmp < 0) result = range.end
|
||||
} else {
|
||||
if (cmp <= 0) {
|
||||
if (range.end is ObjInt) {
|
||||
result = ObjInt.of(range.end.value - 1)
|
||||
} else if (range.end is ObjChar) {
|
||||
result = ObjChar((range.end.value.code - 1).toChar())
|
||||
} else {
|
||||
result = range.end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -923,7 +952,7 @@ object ObjUnset : Obj() {
|
||||
scope: Scope,
|
||||
name: String,
|
||||
args: Arguments,
|
||||
onNotFoundResult: (suspend () -> Obj?)?
|
||||
onNotFoundResult: OnNotFound?
|
||||
): Obj = scope.raiseUnset()
|
||||
|
||||
override suspend fun getAt(scope: Scope, index: Obj): Obj = scope.raiseUnset()
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
|
||||
val ObjArray by lazy {
|
||||
@ -31,8 +33,11 @@ val ObjArray by lazy {
|
||||
name = "iterator",
|
||||
doc = "Iterator over elements of this array using its indexer.",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { ObjArrayIterator(thisObj).also { it.init(this) } }
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjArrayIterator(scp.thisObj).also { it.init(scp) }
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "contains",
|
||||
@ -40,26 +45,31 @@ val ObjArray by lazy {
|
||||
params = listOf(ParamDoc("element")),
|
||||
returns = type("lyng.Bool"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val obj = args.firstAndOnly()
|
||||
for (i in 0..<thisObj.invokeInstanceMethod(this, "size").toInt()) {
|
||||
if (thisObj.getAt(this, ObjInt(i.toLong())).compareTo(this, obj) == 0) return@addFnDoc ObjTrue
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val obj = scp.args.firstAndOnly()
|
||||
for (i in 0..<scp.thisObj.invokeInstanceMethod(scp, "size").toInt()) {
|
||||
if (scp.thisObj.getAt(scp, ObjInt(i.toLong())).compareTo(scp, obj) == 0) return ObjTrue
|
||||
}
|
||||
return ObjFalse
|
||||
}
|
||||
}
|
||||
ObjFalse
|
||||
}
|
||||
)
|
||||
|
||||
addPropertyDoc(
|
||||
name = "last",
|
||||
doc = "The last element of this array.",
|
||||
type = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
this.thisObj.invokeInstanceMethod(
|
||||
this,
|
||||
"getAt",
|
||||
(this.thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj()
|
||||
)
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.thisObj.invokeInstanceMethod(
|
||||
scp,
|
||||
"getAt",
|
||||
(scp.thisObj.invokeInstanceMethod(scp, "size").toInt() - 1).toObj()
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@ -68,7 +78,9 @@ val ObjArray by lazy {
|
||||
doc = "Index of the last element (size - 1).",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { (this.thisObj.invokeInstanceMethod(this, "size").toInt() - 1).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = (scp.thisObj.invokeInstanceMethod(scp, "size").toInt() - 1).toObj()
|
||||
}
|
||||
)
|
||||
|
||||
addPropertyDoc(
|
||||
@ -76,7 +88,9 @@ val ObjArray by lazy {
|
||||
doc = "Range of valid indices for this array.",
|
||||
type = type("lyng.Range"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { ObjRange(0.toObj(), this.thisObj.invokeInstanceMethod(this, "size"), false) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjRange(0.toObj(), scp.thisObj.invokeInstanceMethod(scp, "size"), false)
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
@ -84,25 +98,28 @@ val ObjArray by lazy {
|
||||
doc = "Binary search for a target in a sorted array. Returns index or negative insertion point - 1.",
|
||||
params = listOf(ParamDoc("target")),
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val target = args.firstAndOnly()
|
||||
var low = 0
|
||||
var high = thisObj.invokeInstanceMethod(this, "size").toInt() - 1
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val target = scp.args.firstAndOnly()
|
||||
var low = 0
|
||||
var high = scp.thisObj.invokeInstanceMethod(scp, "size").toInt() - 1
|
||||
|
||||
while (low <= high) {
|
||||
val mid = (low + high) / 2
|
||||
val midVal = thisObj.getAt(this, ObjInt(mid.toLong()))
|
||||
while (low <= high) {
|
||||
val mid = (low + high) / 2
|
||||
val midVal = scp.thisObj.getAt(scp, ObjInt(mid.toLong()))
|
||||
|
||||
val cmp = midVal.compareTo(this, target)
|
||||
when {
|
||||
cmp == 0 -> return@addFnDoc (mid).toObj()
|
||||
cmp > 0 -> high = mid - 1
|
||||
else -> low = mid + 1
|
||||
val cmp = midVal.compareTo(scp, target)
|
||||
when {
|
||||
cmp == 0 -> return (mid).toObj()
|
||||
cmp > 0 -> high = mid - 1
|
||||
else -> low = mid + 1
|
||||
}
|
||||
}
|
||||
|
||||
return (-low - 1).toObj()
|
||||
}
|
||||
}
|
||||
|
||||
(-low - 1).toObj()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
|
||||
class ObjArrayIterator(val array: Obj) : Obj() {
|
||||
|
||||
@ -35,16 +36,20 @@ class ObjArrayIterator(val array: Obj) : Obj() {
|
||||
companion object {
|
||||
val type by lazy {
|
||||
ObjClass("ArrayIterator", ObjIterator).apply {
|
||||
addFn("next") {
|
||||
val self = thisAs<ObjArrayIterator>()
|
||||
if (self.nextIndex < self.lastIndex) {
|
||||
self.array.invokeInstanceMethod(this, "getAt", (self.nextIndex++).toObj())
|
||||
} else raiseError(ObjIterationFinishedException(this))
|
||||
}
|
||||
addFn("hasNext") {
|
||||
val self = thisAs<ObjArrayIterator>()
|
||||
if (self.nextIndex < self.lastIndex) ObjTrue else ObjFalse
|
||||
}
|
||||
addFn("next", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjArrayIterator>()
|
||||
return if (self.nextIndex < self.lastIndex) {
|
||||
self.array.invokeInstanceMethod(scp, "getAt", (self.nextIndex++).toObj())
|
||||
} else scp.raiseError(ObjIterationFinishedException(scp))
|
||||
}
|
||||
})
|
||||
addFn("hasNext", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjArrayIterator>()
|
||||
return if (self.nextIndex < self.lastIndex) ObjTrue else ObjFalse
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.bintools.toDump
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import net.sergeych.lynon.BitArray
|
||||
@ -35,29 +36,37 @@ class ObjBitBuffer(val bitArray: BitArray) : Obj() {
|
||||
val type = object: ObjClass("BitBuffer", ObjArray) {
|
||||
|
||||
}.apply {
|
||||
addFn("toBuffer") {
|
||||
requireNoArgs()
|
||||
ObjBuffer(thisAs<ObjBitBuffer>().bitArray.asUByteArray())
|
||||
}
|
||||
addFn("toDump") {
|
||||
requireNoArgs()
|
||||
ObjString(
|
||||
thisAs<ObjBitBuffer>().bitArray.asUByteArray().toDump()
|
||||
)
|
||||
}
|
||||
addFn("toBuffer", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireNoArgs()
|
||||
return ObjBuffer(scp.thisAs<ObjBitBuffer>().bitArray.asUByteArray())
|
||||
}
|
||||
})
|
||||
addFn("toDump", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireNoArgs()
|
||||
return ObjString(
|
||||
scp.thisAs<ObjBitBuffer>().bitArray.asUByteArray().toByteArray().toDump()
|
||||
)
|
||||
}
|
||||
})
|
||||
addPropertyDoc(
|
||||
name = "size",
|
||||
doc = "Size of the bit buffer in bits.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjBitBuffer>().bitArray.size.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjBitBuffer>().bitArray.size.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "sizeInBytes",
|
||||
doc = "Size of the bit buffer in full bytes (rounded up).",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { ObjInt((thisAs<ObjBitBuffer>().bitArray.size + 7) shr 3) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt(((scp.thisAs<ObjBitBuffer>().bitArray.size + 7) shr 3).toLong())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@ import net.sergeych.bintools.decodeHex
|
||||
import net.sergeych.bintools.encodeToHex
|
||||
import net.sergeych.bintools.toDump
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import net.sergeych.lynon.BitArray
|
||||
@ -169,51 +171,85 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
})
|
||||
|
||||
}.apply {
|
||||
addClassFn("decodeBase64") {
|
||||
ObjBuffer(requireOnlyArg<Obj>().toString().decodeBase64Url().asUByteArray())
|
||||
}
|
||||
addClassFn("decodeHex") {
|
||||
ObjBuffer(requireOnlyArg<Obj>().toString().decodeHex().asUByteArray())
|
||||
}
|
||||
addClassFn("decodeBase64", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
ObjBuffer(scp.requireOnlyArg<Obj>().toString().decodeBase64Url().asUByteArray())
|
||||
})
|
||||
addClassFn("decodeHex", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
ObjBuffer(scp.requireOnlyArg<Obj>().toString().decodeHex().asUByteArray())
|
||||
})
|
||||
addPropertyDoc(
|
||||
name = "size",
|
||||
doc = "Number of bytes in this buffer.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { (this.thisObj as ObjBuffer).byteArray.size.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = (scp.thisObj as ObjBuffer).byteArray.size.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "hex",
|
||||
doc = "Hexadecimal string representation of the buffer.",
|
||||
type = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjBuffer>().hex.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjBuffer>().hex.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "base64",
|
||||
doc = "Base64 (URL-safe) string representation of the buffer.",
|
||||
type = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjBuffer>().base64.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjBuffer>().base64.toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "decodeUtf8",
|
||||
doc = "Decode the buffer content as a UTF-8 string.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
ObjString(scp.thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "toMutable",
|
||||
doc = "Return a mutable copy of this buffer.",
|
||||
returns = type("lyng.MutableBuffer"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireNoArgs()
|
||||
return ObjMutableBuffer(scp.thisAs<ObjBuffer>().byteArray.copyOf())
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "toDump",
|
||||
doc = "Return a hexadecimal dump string of the buffer.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.requireNoArgs()
|
||||
return ObjString(scp.thisAs<ObjBuffer>().byteArray.toByteArray().toDump())
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "toBitInput",
|
||||
doc = "Return a bit buffer for reading bits from this buffer.",
|
||||
returns = type("lyng.BitBuffer"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
ObjBitBuffer(BitArray(scp.thisAs<ObjBuffer>().byteArray, 8))
|
||||
}
|
||||
)
|
||||
addFn("decodeUtf8") {
|
||||
ObjString(
|
||||
thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString()
|
||||
)
|
||||
}
|
||||
addFn("toMutable") {
|
||||
requireNoArgs()
|
||||
ObjMutableBuffer(thisAs<ObjBuffer>().byteArray.copyOf())
|
||||
}
|
||||
addFn("toDump") {
|
||||
requireNoArgs()
|
||||
ObjString(
|
||||
thisAs<ObjBuffer>().byteArray.toByteArray().toDump()
|
||||
)
|
||||
}
|
||||
addFn("toBitInput") {
|
||||
ObjBitBuffer(BitArray(thisAs<ObjBuffer>().byteArray, 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
|
||||
@ -52,14 +53,16 @@ class ObjChar(val value: Char): Obj() {
|
||||
doc = "Unicode code point (UTF-16 code unit) of this character.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { ObjInt((this.thisObj as ObjChar).value.code.toLong()) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt((scp.thisObj as ObjChar).value.code.toLong())
|
||||
}
|
||||
)
|
||||
addFn("isDigit") {
|
||||
thisAs<ObjChar>().value.isDigit().toObj()
|
||||
}
|
||||
addFn("isSpace") {
|
||||
thisAs<ObjChar>().value.isWhitespace().toObj()
|
||||
}
|
||||
addFn("isDigit", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjChar>().value.isDigit().toObj()
|
||||
})
|
||||
addFn("isSpace", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjChar>().value.isWhitespace().toObj()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,14 +40,18 @@ val ObjClassType by lazy {
|
||||
doc = "Full name of this class including package if available.",
|
||||
type = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { (this.thisObj as ObjClass).classNameObj }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = (scp.thisObj as ObjClass).classNameObj
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "name",
|
||||
doc = "Simple name of this class (without package).",
|
||||
type = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { (this.thisObj as ObjClass).classNameObj }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = (scp.thisObj as ObjClass).classNameObj
|
||||
}
|
||||
)
|
||||
|
||||
addPropertyDoc(
|
||||
@ -55,16 +59,18 @@ val ObjClassType by lazy {
|
||||
doc = "Declared instance fields of this class and its ancestors (C3 order), without duplicates.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.String"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val cls = this.thisObj as ObjClass
|
||||
val seen = hashSetOf<String>()
|
||||
val names = mutableListOf<Obj>()
|
||||
for (c in cls.mro) {
|
||||
for ((n, rec) in c.members) {
|
||||
if (rec.value !is Statement && seen.add(n)) names += ObjString(n)
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val cls = scp.thisObj as ObjClass
|
||||
val seen = hashSetOf<String>()
|
||||
val names = mutableListOf<Obj>()
|
||||
for (c in cls.mro) {
|
||||
for ((n, rec) in c.members) {
|
||||
if (rec.value !is Statement && seen.add(n)) names += ObjString(n)
|
||||
}
|
||||
}
|
||||
return ObjList(names.toMutableList())
|
||||
}
|
||||
ObjList(names.toMutableList())
|
||||
}
|
||||
)
|
||||
|
||||
@ -73,16 +79,18 @@ val ObjClassType by lazy {
|
||||
doc = "Declared instance methods of this class and its ancestors (C3 order), without duplicates.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.String"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val cls = this.thisObj as ObjClass
|
||||
val seen = hashSetOf<String>()
|
||||
val names = mutableListOf<Obj>()
|
||||
for (c in cls.mro) {
|
||||
for ((n, rec) in c.members) {
|
||||
if (rec.value is Statement && seen.add(n)) names += ObjString(n)
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val cls = scp.thisObj as ObjClass
|
||||
val seen = hashSetOf<String>()
|
||||
val names = mutableListOf<Obj>()
|
||||
for (c in cls.mro) {
|
||||
for ((n, rec) in c.members) {
|
||||
if (rec.value is Statement && seen.add(n)) names += ObjString(n)
|
||||
}
|
||||
}
|
||||
return ObjList(names.toMutableList())
|
||||
}
|
||||
ObjList(names.toMutableList())
|
||||
}
|
||||
)
|
||||
|
||||
@ -91,13 +99,16 @@ val ObjClassType by lazy {
|
||||
doc = "Lookup a member by name in this class (including ancestors) and return it, or null if absent.",
|
||||
params = listOf(ParamDoc("name", type("lyng.String"))),
|
||||
returns = type("lyng.Any", nullable = true),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val cls = thisAs<ObjClass>()
|
||||
val name = requiredArg<ObjString>(0).value
|
||||
val rec = cls.getInstanceMemberOrNull(name)
|
||||
rec?.value ?: ObjNull
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val cls = scp.thisAs<ObjClass>()
|
||||
val name = scp.requiredArg<ObjString>(0).value
|
||||
val rec = cls.getInstanceMemberOrNull(name)
|
||||
return rec?.value ?: ObjNull
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +125,8 @@ open class ObjClass(
|
||||
val classId: Long = ClassIdGen.nextId()
|
||||
var layoutVersion: Int = 0
|
||||
|
||||
fun mangledName(name: String): String = "$className::$name"
|
||||
private val mangledNameCache = mutableMapOf<String, String>()
|
||||
fun mangledName(name: String): String = mangledNameCache.getOrPut(name) { "$className::$name" }
|
||||
|
||||
/**
|
||||
* Map of public member names to their effective storage keys in instanceScope.objects.
|
||||
@ -127,7 +139,7 @@ open class ObjClass(
|
||||
if (cls.className == "Obj") continue
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.visibility == Visibility.Public) {
|
||||
val key = if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
val key = if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
res[name] = key
|
||||
}
|
||||
}
|
||||
@ -266,119 +278,6 @@ open class ObjClass(
|
||||
*/
|
||||
internal val members = mutableMapOf<String, ObjRecord>()
|
||||
|
||||
internal data class FieldSlot(val slot: Int, val record: ObjRecord)
|
||||
internal data class ResolvedMember(val record: ObjRecord, val declaringClass: ObjClass)
|
||||
internal data class MethodSlot(val slot: Int, val record: ObjRecord)
|
||||
private var fieldSlotLayoutVersion: Int = -1
|
||||
private var fieldSlotMap: Map<String, FieldSlot> = emptyMap()
|
||||
private var fieldSlotCount: Int = 0
|
||||
private var instanceMemberLayoutVersion: Int = -1
|
||||
private var instanceMemberCache: Map<String, ResolvedMember> = emptyMap()
|
||||
private var methodSlotLayoutVersion: Int = -1
|
||||
private var methodSlotMap: Map<String, MethodSlot> = emptyMap()
|
||||
private var methodSlotCount: Int = 0
|
||||
|
||||
private fun ensureFieldSlots(): Map<String, FieldSlot> {
|
||||
if (fieldSlotLayoutVersion == layoutVersion) return fieldSlotMap
|
||||
val res = mutableMapOf<String, FieldSlot>()
|
||||
var idx = 0
|
||||
for (cls in mro) {
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.isAbstract) continue
|
||||
if (rec.type != ObjRecord.Type.Field && rec.type != ObjRecord.Type.ConstructorField) continue
|
||||
val key = cls.mangledName(name)
|
||||
if (res.containsKey(key)) continue
|
||||
res[key] = FieldSlot(idx, rec)
|
||||
idx += 1
|
||||
}
|
||||
}
|
||||
fieldSlotMap = res
|
||||
fieldSlotCount = idx
|
||||
fieldSlotLayoutVersion = layoutVersion
|
||||
return fieldSlotMap
|
||||
}
|
||||
|
||||
private fun ensureInstanceMemberCache(): Map<String, ResolvedMember> {
|
||||
if (instanceMemberLayoutVersion == layoutVersion) return instanceMemberCache
|
||||
val res = mutableMapOf<String, ResolvedMember>()
|
||||
for (cls in mro) {
|
||||
if (cls.className == "Obj") break
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.isAbstract) continue
|
||||
if (res.containsKey(name)) continue
|
||||
val decl = rec.declaringClass ?: cls
|
||||
res[name] = ResolvedMember(rec, decl)
|
||||
}
|
||||
cls.classScope?.objects?.forEach { (name, rec) ->
|
||||
if (rec.isAbstract) return@forEach
|
||||
if (res.containsKey(name)) return@forEach
|
||||
val decl = rec.declaringClass ?: cls
|
||||
res[name] = ResolvedMember(rec, decl)
|
||||
}
|
||||
}
|
||||
instanceMemberCache = res
|
||||
instanceMemberLayoutVersion = layoutVersion
|
||||
return instanceMemberCache
|
||||
}
|
||||
|
||||
private fun ensureMethodSlots(): Map<String, MethodSlot> {
|
||||
if (methodSlotLayoutVersion == layoutVersion) return methodSlotMap
|
||||
val res = mutableMapOf<String, MethodSlot>()
|
||||
var idx = 0
|
||||
for (cls in mro) {
|
||||
if (cls.className == "Obj") break
|
||||
for ((name, rec) in cls.members) {
|
||||
if (rec.isAbstract) continue
|
||||
if (rec.value !is Statement &&
|
||||
rec.type != ObjRecord.Type.Delegated &&
|
||||
rec.type != ObjRecord.Type.Fun &&
|
||||
rec.type != ObjRecord.Type.Property) {
|
||||
continue
|
||||
}
|
||||
val key = if (rec.visibility == Visibility.Private || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
if (res.containsKey(key)) continue
|
||||
res[key] = MethodSlot(idx, rec)
|
||||
idx += 1
|
||||
}
|
||||
cls.classScope?.objects?.forEach { (name, rec) ->
|
||||
if (rec.isAbstract) return@forEach
|
||||
if (rec.value !is Statement &&
|
||||
rec.type != ObjRecord.Type.Delegated &&
|
||||
rec.type != ObjRecord.Type.Property) return@forEach
|
||||
val key = if (rec.visibility == Visibility.Private || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
if (res.containsKey(key)) return@forEach
|
||||
res[key] = MethodSlot(idx, rec)
|
||||
idx += 1
|
||||
}
|
||||
}
|
||||
methodSlotMap = res
|
||||
methodSlotCount = idx
|
||||
methodSlotLayoutVersion = layoutVersion
|
||||
return methodSlotMap
|
||||
}
|
||||
|
||||
internal fun fieldSlotCount(): Int {
|
||||
ensureFieldSlots()
|
||||
return fieldSlotCount
|
||||
}
|
||||
|
||||
internal fun fieldSlotForKey(key: String): FieldSlot? {
|
||||
ensureFieldSlots()
|
||||
return fieldSlotMap[key]
|
||||
}
|
||||
|
||||
internal fun fieldSlotMap(): Map<String, FieldSlot> = ensureFieldSlots()
|
||||
internal fun resolveInstanceMember(name: String): ResolvedMember? = ensureInstanceMemberCache()[name]
|
||||
internal fun methodSlotCount(): Int {
|
||||
ensureMethodSlots()
|
||||
return methodSlotCount
|
||||
}
|
||||
internal fun methodSlotForKey(key: String): MethodSlot? {
|
||||
ensureMethodSlots()
|
||||
return methodSlotMap[key]
|
||||
}
|
||||
internal fun methodSlotMap(): Map<String, MethodSlot> = ensureMethodSlots()
|
||||
|
||||
override fun toString(): String = className
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int = if (other === this) 0 else -1
|
||||
@ -396,8 +295,8 @@ open class ObjClass(
|
||||
for (cls in mro) {
|
||||
// 1) members-defined methods and fields
|
||||
for ((k, v) in cls.members) {
|
||||
if (!v.isAbstract && (v.value is Statement || v.type == ObjRecord.Type.Delegated || v.type == ObjRecord.Type.Field || v.type == ObjRecord.Type.ConstructorField)) {
|
||||
val key = if (v.visibility == Visibility.Private || v.type == ObjRecord.Type.Field || v.type == ObjRecord.Type.ConstructorField || v.type == ObjRecord.Type.Delegated) cls.mangledName(k) else k
|
||||
if (!v.isAbstract && (v.value is Statement || v.type == ObjRecord.Type.Delegated || v.type == ObjRecord.Type.Field)) {
|
||||
val key = if (v.visibility == Visibility.Private || v.type == ObjRecord.Type.Field || v.type == ObjRecord.Type.Delegated) cls.mangledName(k) else k
|
||||
if (!res.containsKey(key)) {
|
||||
res[key] = v
|
||||
}
|
||||
@ -439,47 +338,12 @@ open class ObjClass(
|
||||
val stableParent = classScope ?: scope.parent
|
||||
instance.instanceScope = Scope(stableParent, scope.args, scope.pos, instance)
|
||||
instance.instanceScope.currentClassCtx = null
|
||||
val fieldSlots = fieldSlotMap()
|
||||
if (fieldSlots.isNotEmpty()) {
|
||||
instance.initFieldSlots(fieldSlotCount())
|
||||
}
|
||||
val methodSlots = methodSlotMap()
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
instance.initMethodSlots(methodSlotCount())
|
||||
}
|
||||
// Expose instance methods (and other callable members) directly in the instance scope for fast lookup
|
||||
// This mirrors Obj.autoInstanceScope behavior for ad-hoc scopes and makes fb.method() resolution robust
|
||||
|
||||
instance.instanceScope.objects.putAll(templateMethods)
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
for ((key, rec) in templateMethods) {
|
||||
val slot = methodSlots[key]
|
||||
if (slot != null) {
|
||||
instance.setMethodSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (p in templateOthers) {
|
||||
val rec = p.second.copy()
|
||||
instance.instanceScope.objects[p.first] = rec
|
||||
val slot = fieldSlots[p.first]
|
||||
if (slot != null) {
|
||||
instance.setFieldSlotRecord(slot.slot, rec)
|
||||
}
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
val mSlot = methodSlots[p.first]
|
||||
if (mSlot != null) {
|
||||
instance.setMethodSlotRecord(mSlot.slot, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methodSlots.isNotEmpty()) {
|
||||
for ((_, mSlot) in methodSlots) {
|
||||
val idx = mSlot.slot
|
||||
if (idx >= 0 && idx < instance.methodSlots.size && instance.methodSlots[idx] == null) {
|
||||
instance.setMethodSlotRecord(idx, mSlot.record)
|
||||
}
|
||||
}
|
||||
instance.instanceScope.objects[p.first] = p.second.copy()
|
||||
}
|
||||
return instance
|
||||
}
|
||||
@ -564,10 +428,6 @@ open class ObjClass(
|
||||
if (rec != null) {
|
||||
val mangled = c.mangledName(p.name)
|
||||
instance.instanceScope.objects[mangled] = rec
|
||||
val slot = instance.objClass.fieldSlotForKey(mangled)
|
||||
if (slot != null) {
|
||||
instance.setFieldSlotRecord(slot.slot, rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -698,9 +558,9 @@ open class ObjClass(
|
||||
isClosed: Boolean = false,
|
||||
isOverride: Boolean = false,
|
||||
pos: Pos = Pos.builtIn,
|
||||
code: (suspend Scope.() -> Obj)? = null
|
||||
code: ScopeCallable? = null
|
||||
) {
|
||||
val stmt = code?.let { statement { it() } } ?: ObjNull
|
||||
val stmt = code?.let { statement(pos, f = it) } ?: ObjNull
|
||||
createField(
|
||||
name, stmt, isMutable, visibility, writeVisibility, pos, declaringClass,
|
||||
isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride,
|
||||
@ -712,8 +572,8 @@ open class ObjClass(
|
||||
|
||||
fun addProperty(
|
||||
name: String,
|
||||
getter: (suspend Scope.() -> Obj)? = null,
|
||||
setter: (suspend Scope.(Obj) -> Unit)? = null,
|
||||
getter: ScopeCallable? = null,
|
||||
setter: ScopeCallable? = null,
|
||||
visibility: Visibility = Visibility.Public,
|
||||
writeVisibility: Visibility? = null,
|
||||
declaringClass: ObjClass? = this,
|
||||
@ -723,8 +583,8 @@ open class ObjClass(
|
||||
pos: Pos = Pos.builtIn,
|
||||
prop: ObjProperty? = null
|
||||
) {
|
||||
val g = getter?.let { statement { it() } }
|
||||
val s = setter?.let { statement { it(requiredArg(0)); ObjVoid } }
|
||||
val g = getter?.let { statement(pos, f = it) }
|
||||
val s = setter?.let { statement(pos, f = it) }
|
||||
val finalProp = prop ?: if (isAbstract) ObjNull else ObjProperty(name, g, s)
|
||||
createField(
|
||||
name, finalProp, false, visibility, writeVisibility, pos, declaringClass,
|
||||
@ -734,8 +594,8 @@ open class ObjClass(
|
||||
}
|
||||
|
||||
fun addClassConst(name: String, value: Obj) = createClassField(name, value)
|
||||
fun addClassFn(name: String, isOpen: Boolean = false, code: suspend Scope.() -> Obj) {
|
||||
createClassField(name, statement { code() }, isOpen, type = ObjRecord.Type.Fun)
|
||||
fun addClassFn(name: String, isOpen: Boolean = false, code: ScopeCallable) {
|
||||
createClassField(name, statement(f = code), isOpen, type = ObjRecord.Type.Fun)
|
||||
}
|
||||
|
||||
|
||||
@ -845,25 +705,25 @@ open class ObjClass(
|
||||
|
||||
override suspend fun invokeInstanceMethod(
|
||||
scope: Scope, name: String, args: Arguments,
|
||||
onNotFoundResult: (suspend () -> Obj?)?
|
||||
onNotFoundResult: OnNotFound?
|
||||
): Obj {
|
||||
getInstanceMemberOrNull(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: findDeclaringClassOf(name) ?: this
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val del = rec.delegate ?: scope.raiseError("Internal error: delegated member $name has no delegate")
|
||||
val allArgs = (listOf(this, ObjString(name)) + args.list).toTypedArray()
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs), onNotFoundResult = {
|
||||
return del.invokeInstanceMethod(scope, "invokeCallable", Arguments(*allArgs), onNotFoundResult = {
|
||||
// Fallback: property delegation
|
||||
val propVal = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
propVal.invoke(scope, this, args, decl)
|
||||
propVal.invokeCallable(scope, this, args, decl)
|
||||
})
|
||||
}
|
||||
if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(scope, this, args, decl)
|
||||
return rec.value.invokeCallable(scope, this, args, decl)
|
||||
} else {
|
||||
// Resolved field or property value
|
||||
val resolved = readField(scope, name)
|
||||
return resolved.value.invoke(scope, this, args, decl)
|
||||
return resolved.value.invokeCallable(scope, this, args, decl)
|
||||
}
|
||||
}
|
||||
return super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
@ -889,3 +749,5 @@ open class ObjClass(
|
||||
scope.raiseNotImplemented()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.ParamDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
@ -38,11 +39,14 @@ class ObjCompletableDeferred(val completableDeferred: CompletableDeferred<Obj>):
|
||||
doc = "Complete this deferred with the given value. Subsequent calls have no effect.",
|
||||
params = listOf(ParamDoc("value")),
|
||||
returns = type("lyng.Void"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjCompletableDeferred>().completableDeferred.complete(args.firstAndOnly())
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.thisAs<ObjCompletableDeferred>().completableDeferred.complete(scp.args.firstAndOnly())
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ import kotlinx.datetime.*
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.miniast.addClassFnDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
@ -54,7 +55,9 @@ class ObjDateTime(val instant: Instant, val timeZone: TimeZone) : Obj() {
|
||||
}
|
||||
if (rec.type == ObjRecord.Type.Fun || rec.value is Statement) {
|
||||
val s = rec.value as Statement
|
||||
return ObjRecord(net.sergeych.lyng.statement { s.execute(this.createChildScope(newThisObj = this@ObjDateTime)) }, rec.isMutable)
|
||||
return ObjRecord(net.sergeych.lyng.statement(f = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = s.execute(scp.createChildScope(newThisObj = this@ObjDateTime))
|
||||
}), rec.isMutable)
|
||||
}
|
||||
return resolveRecord(scope, rec, name, rec.declaringClass ?: cls)
|
||||
}
|
||||
@ -172,122 +175,129 @@ class ObjDateTime(val instant: Instant, val timeZone: TimeZone) : Obj() {
|
||||
}
|
||||
}.apply {
|
||||
addPropertyDoc("year", "The year component.", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.year.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.year.toObj() })
|
||||
addPropertyDoc("month", "The month component (1..12).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.monthNumber.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.monthNumber.toObj() })
|
||||
addPropertyDoc("dayOfMonth", "The day of month component.", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.dayOfMonth.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.dayOfMonth.toObj() })
|
||||
addPropertyDoc("day", "Alias to dayOfMonth.", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.dayOfMonth.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.dayOfMonth.toObj() })
|
||||
addPropertyDoc("hour", "The hour component (0..23).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.hour.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.hour.toObj() })
|
||||
addPropertyDoc("minute", "The minute component (0..59).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.minute.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.minute.toObj() })
|
||||
addPropertyDoc("second", "The second component (0..59).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.second.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.second.toObj() })
|
||||
addPropertyDoc("dayOfWeek", "The day of week (1=Monday, 7=Sunday).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.dayOfWeek.isoDayNumber.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().localDateTime.dayOfWeek.isoDayNumber.toObj() })
|
||||
addPropertyDoc("timeZone", "The time zone ID (e.g. 'Z', '+02:00', 'Europe/Prague').", type("lyng.String"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().timeZone.id.toObj() })
|
||||
getter = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().timeZone.id.toObj() })
|
||||
|
||||
addFnDoc("toInstant", "Convert this localized date time back to an absolute Instant.", returns = type("lyng.Instant"), moduleName = "lyng.time") {
|
||||
ObjInstant(thisAs<ObjDateTime>().instant)
|
||||
}
|
||||
addFnDoc("toEpochSeconds", "Return the number of full seconds since the Unix epoch (UTC).", returns = type("lyng.Int"), moduleName = "lyng.time") {
|
||||
thisAs<ObjDateTime>().instant.epochSeconds.toObj()
|
||||
}
|
||||
addFnDoc("toRFC3339", "Return the RFC3339 string representation of this date time, including its timezone offset.", returns = type("lyng.String"), moduleName = "lyng.time") {
|
||||
thisAs<ObjDateTime>().toRFC3339().toObj()
|
||||
}
|
||||
addFnDoc("toSortableString", "Alias to toRFC3339.", returns = type("lyng.String"), moduleName = "lyng.time") {
|
||||
thisAs<ObjDateTime>().toRFC3339().toObj()
|
||||
}
|
||||
|
||||
addFnDoc("toEpochMilliseconds", "Return the number of milliseconds since the Unix epoch (UTC).", returns = type("lyng.Int"), moduleName = "lyng.time") {
|
||||
thisAs<ObjDateTime>().instant.toEpochMilliseconds().toObj()
|
||||
}
|
||||
addFnDoc("toInstant", "Convert this localized date time back to an absolute Instant.", returns = type("lyng.Instant"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjInstant(scp.thisAs<ObjDateTime>().instant) })
|
||||
addFnDoc("toEpochSeconds", "Return the number of full seconds since the Unix epoch (UTC).", returns = type("lyng.Int"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().instant.epochSeconds.toObj() })
|
||||
addFnDoc("toRFC3339", "Return the RFC3339 string representation of this date time, including its timezone offset.", returns = type("lyng.String"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().toRFC3339().toObj() })
|
||||
addFnDoc("toSortableString", "Alias to toRFC3339.", returns = type("lyng.String"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().toRFC3339().toObj() })
|
||||
|
||||
addFnDoc("toEpochMilliseconds", "Return the number of milliseconds since the Unix epoch (UTC).", returns = type("lyng.Int"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDateTime>().instant.toEpochMilliseconds().toObj() })
|
||||
addFnDoc("toTimeZone", "Return a new DateTime representing the same instant but in a different time zone. " +
|
||||
"Accepts a timezone ID string (e.g., 'UTC', '+02:00') or an integer offset in seconds.",
|
||||
params = listOf(net.sergeych.lyng.miniast.ParamDoc("tz", type = type("lyng.Any"))),
|
||||
returns = type("lyng.DateTime"), moduleName = "lyng.time") {
|
||||
val tz = when (val a = args.list.getOrNull(0)) {
|
||||
is ObjString -> TimeZone.of(a.value)
|
||||
is ObjInt -> UtcOffset(seconds = a.value.toInt()).asTimeZone()
|
||||
else -> raiseIllegalArgument("invalid timezone: $a")
|
||||
}
|
||||
ObjDateTime(thisAs<ObjDateTime>().instant, tz)
|
||||
}
|
||||
addFnDoc("toUTC", "Shortcut to convert this date time to the UTC time zone.", returns = type("lyng.DateTime"), moduleName = "lyng.time") {
|
||||
ObjDateTime(thisAs<ObjDateTime>().instant, TimeZone.UTC)
|
||||
}
|
||||
returns = type("lyng.DateTime"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val tz = when (val a = scp.args.list.getOrNull(0)) {
|
||||
is ObjString -> TimeZone.of(a.value)
|
||||
is ObjInt -> UtcOffset(seconds = a.value.toInt()).asTimeZone()
|
||||
else -> scp.raiseIllegalArgument("invalid timezone: $a")
|
||||
}
|
||||
return ObjDateTime(scp.thisAs<ObjDateTime>().instant, tz)
|
||||
}
|
||||
})
|
||||
addFnDoc("toUTC", "Shortcut to convert this date time to the UTC time zone.", returns = type("lyng.DateTime"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable { override suspend fun call(scp: Scope): Obj = ObjDateTime(scp.thisAs<ObjDateTime>().instant, TimeZone.UTC) })
|
||||
|
||||
addFnDoc("addMonths", "Return a new DateTime with the specified number of months added (or subtracted if negative). " +
|
||||
"Normalizes the day of month if necessary (e.g., Jan 31 + 1 month = Feb 28/29).",
|
||||
params = listOf(net.sergeych.lyng.miniast.ParamDoc("months", type = type("lyng.Int"))),
|
||||
returns = type("lyng.DateTime"), moduleName = "lyng.time") {
|
||||
val n = args.list.getOrNull(0)?.toInt() ?: 0
|
||||
val res = thisAs<ObjDateTime>().instant.plus(n, DateTimeUnit.MONTH, thisAs<ObjDateTime>().timeZone)
|
||||
ObjDateTime(res, thisAs<ObjDateTime>().timeZone)
|
||||
}
|
||||
returns = type("lyng.DateTime"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val n = scp.args.list.getOrNull(0)?.toInt() ?: 0
|
||||
val res = scp.thisAs<ObjDateTime>().instant.plus(n, DateTimeUnit.MONTH, scp.thisAs<ObjDateTime>().timeZone)
|
||||
return ObjDateTime(res, scp.thisAs<ObjDateTime>().timeZone)
|
||||
}
|
||||
})
|
||||
addFnDoc("addYears", "Return a new DateTime with the specified number of years added (or subtracted if negative).",
|
||||
params = listOf(net.sergeych.lyng.miniast.ParamDoc("years", type = type("lyng.Int"))),
|
||||
returns = type("lyng.DateTime"), moduleName = "lyng.time") {
|
||||
val n = args.list.getOrNull(0)?.toInt() ?: 0
|
||||
val res = thisAs<ObjDateTime>().instant.plus(n, DateTimeUnit.YEAR, thisAs<ObjDateTime>().timeZone)
|
||||
ObjDateTime(res, thisAs<ObjDateTime>().timeZone)
|
||||
}
|
||||
returns = type("lyng.DateTime"), moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val n = scp.args.list.getOrNull(0)?.toInt() ?: 0
|
||||
val res = scp.thisAs<ObjDateTime>().instant.plus(n, DateTimeUnit.YEAR, scp.thisAs<ObjDateTime>().timeZone)
|
||||
return ObjDateTime(res, scp.thisAs<ObjDateTime>().timeZone)
|
||||
}
|
||||
})
|
||||
|
||||
addClassFn("now") {
|
||||
val tz = when (val a = args.list.getOrNull(0)) {
|
||||
null -> TimeZone.currentSystemDefault()
|
||||
is ObjString -> TimeZone.of(a.value)
|
||||
is ObjInt -> UtcOffset(seconds = a.value.toInt()).asTimeZone()
|
||||
else -> raiseIllegalArgument("invalid timezone: $a")
|
||||
addClassFn("now", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val tz = when (val a = scp.args.list.getOrNull(0)) {
|
||||
null -> TimeZone.currentSystemDefault()
|
||||
is ObjString -> TimeZone.of(a.value)
|
||||
is ObjInt -> UtcOffset(seconds = a.value.toInt()).asTimeZone()
|
||||
else -> scp.raiseIllegalArgument("invalid timezone: $a")
|
||||
}
|
||||
return ObjDateTime(kotlin.time.Clock.System.now(), tz)
|
||||
}
|
||||
ObjDateTime(kotlin.time.Clock.System.now(), tz)
|
||||
}
|
||||
})
|
||||
|
||||
addClassFnDoc("parseRFC3339",
|
||||
"Parse an RFC3339 string into a DateTime object. " +
|
||||
"Note: if the string does not specify a timezone, UTC is assumed.",
|
||||
params = listOf(net.sergeych.lyng.miniast.ParamDoc("string", type = type("lyng.String"))),
|
||||
returns = type("lyng.DateTime"),
|
||||
moduleName = "lyng.time") {
|
||||
val s = (args.firstAndOnly() as ObjString).value
|
||||
// kotlinx-datetime's Instant.parse handles RFC3339
|
||||
// But we want to preserve the offset if present for DateTime.
|
||||
// However, Instant.parse("...") always gives an Instant.
|
||||
// If we want the specific offset from the string, we might need a more complex parse.
|
||||
// For now, let's stick to parsing it as Instant and converting to UTC or specified TZ.
|
||||
// Actually, if the string has an offset, Instant.parse handles it but returns UTC instant.
|
||||
|
||||
// Let's try to detect if there is an offset in the string.
|
||||
// If not, use UTC.
|
||||
val instant = Instant.parse(s)
|
||||
|
||||
// RFC3339 can have Z or +/-HH:mm or +/-HHmm or +/-HH
|
||||
val tz = try {
|
||||
if (s.endsWith("Z", ignoreCase = true)) {
|
||||
TimeZone.of("Z")
|
||||
} else {
|
||||
// Look for the last + or - which is likely the start of the offset
|
||||
val lastPlus = s.lastIndexOf('+')
|
||||
val lastMinus = s.lastIndexOf('-')
|
||||
val offsetStart = if (lastPlus > lastMinus) lastPlus else lastMinus
|
||||
if (offsetStart > s.lastIndexOf('T')) {
|
||||
// Likely an offset
|
||||
val offsetStr = s.substring(offsetStart)
|
||||
TimeZone.of(offsetStr)
|
||||
} else {
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val s = (scp.args.firstAndOnly() as ObjString).value
|
||||
// kotlinx-datetime's Instant.parse handles RFC3339
|
||||
// But we want to preserve the offset if present for DateTime.
|
||||
// However, Instant.parse("...") always gives an Instant.
|
||||
// If we want the specific offset from the string, we might need a more complex parse.
|
||||
// For now, let's stick to parsing it as Instant and converting to UTC or specified TZ.
|
||||
// Actually, if the string has an offset, Instant.parse handles it but returns UTC instant.
|
||||
|
||||
// Let's try to detect if there is an offset in the string.
|
||||
// If not, use UTC.
|
||||
val instant = Instant.parse(s)
|
||||
|
||||
// RFC3339 can have Z or +/-HH:mm or +/-HHmm or +/-HH
|
||||
val tz = try {
|
||||
if (s.endsWith("Z", ignoreCase = true)) {
|
||||
TimeZone.of("Z")
|
||||
} else {
|
||||
// Look for the last + or - which is likely the start of the offset
|
||||
val lastPlus = s.lastIndexOf('+')
|
||||
val lastMinus = s.lastIndexOf('-')
|
||||
val offsetStart = if (lastPlus > lastMinus) lastPlus else lastMinus
|
||||
if (offsetStart > s.lastIndexOf('T')) {
|
||||
// Likely an offset
|
||||
val offsetStr = s.substring(offsetStart)
|
||||
TimeZone.of(offsetStr)
|
||||
} else {
|
||||
TimeZone.UTC
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
TimeZone.UTC
|
||||
}
|
||||
return ObjDateTime(instant, tz)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
TimeZone.UTC
|
||||
}
|
||||
|
||||
ObjDateTime(instant, tz)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.coroutines.Deferred
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
@ -37,23 +38,30 @@ open class ObjDeferred(val deferred: Deferred<Obj>): Obj() {
|
||||
name = "await",
|
||||
doc = "Suspend until completion and return the result value (or throw if failed).",
|
||||
returns = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { thisAs<ObjDeferred>().deferred.await() }
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDeferred>().deferred.await()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isCompleted",
|
||||
doc = "Whether this deferred has completed (successfully or with an error).",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjDeferred>().deferred.isCompleted.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDeferred>().deferred.isCompleted.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isActive",
|
||||
doc = "Whether this deferred is currently active (not completed and not cancelled).",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val d = thisAs<ObjDeferred>().deferred
|
||||
(d.isActive || (!d.isCompleted && !d.isCancelled)).toObj()
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val d = scp.thisAs<ObjDeferred>().deferred
|
||||
return (d.isActive || (!d.isCompleted && !d.isCancelled)).toObj()
|
||||
}
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
@ -61,7 +69,9 @@ open class ObjDeferred(val deferred: Deferred<Obj>): Obj() {
|
||||
doc = "Whether this deferred was cancelled.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjDeferred>().deferred.isCancelled.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDeferred>().deferred.isCancelled.toObj()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import kotlin.time.Duration
|
||||
@ -79,42 +80,54 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Return this duration as a real number of days.",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDuration>().duration.toDouble(DurationUnit.DAYS).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDuration>().duration.toDouble(DurationUnit.DAYS).toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "hours",
|
||||
doc = "Return this duration as a real number of hours.",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDuration>().duration.toDouble(DurationUnit.HOURS).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDuration>().duration.toDouble(DurationUnit.HOURS).toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "minutes",
|
||||
doc = "Return this duration as a real number of minutes.",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDuration>().duration.toDouble(DurationUnit.MINUTES).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDuration>().duration.toDouble(DurationUnit.MINUTES).toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "seconds",
|
||||
doc = "Return this duration as a real number of seconds.",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDuration>().duration.toDouble(DurationUnit.SECONDS).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDuration>().duration.toDouble(DurationUnit.SECONDS).toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "milliseconds",
|
||||
doc = "Return this duration as a real number of milliseconds.",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDuration>().duration.toDouble(DurationUnit.MILLISECONDS).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDuration>().duration.toDouble(DurationUnit.MILLISECONDS).toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "microseconds",
|
||||
doc = "Return this duration as a real number of microseconds.",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDuration>().duration.toDouble(DurationUnit.MICROSECONDS).toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjDuration>().duration.toDouble(DurationUnit.MICROSECONDS).toObj()
|
||||
}
|
||||
)
|
||||
// extensions
|
||||
|
||||
@ -123,7 +136,9 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Construct a `Duration` equal to this integer number of seconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.seconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.seconds)
|
||||
}
|
||||
)
|
||||
|
||||
ObjInt.type.addPropertyDoc(
|
||||
@ -131,14 +146,18 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Construct a `Duration` equal to this integer number of seconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.seconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.seconds)
|
||||
}
|
||||
)
|
||||
ObjInt.type.addPropertyDoc(
|
||||
name = "milliseconds",
|
||||
doc = "Construct a `Duration` equal to this integer number of milliseconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.milliseconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.milliseconds)
|
||||
}
|
||||
)
|
||||
|
||||
ObjInt.type.addPropertyDoc(
|
||||
@ -146,14 +165,18 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Construct a `Duration` equal to this integer number of milliseconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.milliseconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.milliseconds)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "seconds",
|
||||
doc = "Construct a `Duration` equal to this real number of seconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.seconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.seconds)
|
||||
}
|
||||
)
|
||||
|
||||
ObjReal.type.addPropertyDoc(
|
||||
@ -161,7 +184,9 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Construct a `Duration` equal to this real number of seconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.seconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.seconds)
|
||||
}
|
||||
)
|
||||
|
||||
ObjReal.type.addPropertyDoc(
|
||||
@ -169,14 +194,18 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Construct a `Duration` equal to this real number of milliseconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.milliseconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.milliseconds)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "millisecond",
|
||||
doc = "Construct a `Duration` equal to this real number of milliseconds.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.milliseconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.milliseconds)
|
||||
}
|
||||
)
|
||||
|
||||
ObjInt.type.addPropertyDoc(
|
||||
@ -184,84 +213,108 @@ class ObjDuration(val duration: Duration) : Obj() {
|
||||
doc = "Construct a `Duration` equal to this integer number of minutes.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.minutes) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.minutes)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "minutes",
|
||||
doc = "Construct a `Duration` equal to this real number of minutes.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.minutes) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.minutes)
|
||||
}
|
||||
)
|
||||
ObjInt.type.addPropertyDoc(
|
||||
name = "minute",
|
||||
doc = "Construct a `Duration` equal to this integer number of minutes.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.minutes) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.minutes)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "minute",
|
||||
doc = "Construct a `Duration` equal to this real number of minutes.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.minutes) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.minutes)
|
||||
}
|
||||
)
|
||||
ObjInt.type.addPropertyDoc(
|
||||
name = "hours",
|
||||
doc = "Construct a `Duration` equal to this integer number of hours.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.hours) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.hours)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "hours",
|
||||
doc = "Construct a `Duration` equal to this real number of hours.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.hours) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.hours)
|
||||
}
|
||||
)
|
||||
ObjInt.type.addPropertyDoc(
|
||||
name = "hour",
|
||||
doc = "Construct a `Duration` equal to this integer number of hours.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.hours) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.hours)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "hour",
|
||||
doc = "Construct a `Duration` equal to this real number of hours.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.hours) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.hours)
|
||||
}
|
||||
)
|
||||
ObjInt.type.addPropertyDoc(
|
||||
name = "days",
|
||||
doc = "Construct a `Duration` equal to this integer number of days.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.days) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.days)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "days",
|
||||
doc = "Construct a `Duration` equal to this real number of days.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.days) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.days)
|
||||
}
|
||||
)
|
||||
ObjInt.type.addPropertyDoc(
|
||||
name = "day",
|
||||
doc = "Construct a `Duration` equal to this integer number of days.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjInt>().value.days) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjInt>().value.days)
|
||||
}
|
||||
)
|
||||
ObjReal.type.addPropertyDoc(
|
||||
name = "day",
|
||||
doc = "Construct a `Duration` equal to this real number of days.",
|
||||
type = type("lyng.Duration"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjDuration(thisAs<ObjReal>().value.days) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjDuration(scp.thisAs<ObjReal>().value.days)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -17,31 +17,32 @@
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Arguments
|
||||
import net.sergeych.lyng.ClosureScope
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.*
|
||||
|
||||
class ObjDynamicContext(val delegate: ObjDynamic) : Obj() {
|
||||
override val objClass: ObjClass get() = type
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("DelegateContext").apply {
|
||||
addFn("get") {
|
||||
val d = thisAs<ObjDynamicContext>().delegate
|
||||
if (d.readCallback != null)
|
||||
raiseIllegalState("get already defined")
|
||||
d.readCallback = requireOnlyArg()
|
||||
ObjVoid
|
||||
}
|
||||
addFn("get", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val d = scp.thisAs<ObjDynamicContext>().delegate
|
||||
if (d.readCallback != null)
|
||||
scp.raiseIllegalState("get already defined")
|
||||
d.readCallback = scp.requireOnlyArg()
|
||||
return ObjVoid
|
||||
}
|
||||
})
|
||||
|
||||
addFn("set") {
|
||||
val d = thisAs<ObjDynamicContext>().delegate
|
||||
if (d.writeCallback != null)
|
||||
raiseIllegalState("set already defined")
|
||||
d.writeCallback = requireOnlyArg()
|
||||
ObjVoid
|
||||
}
|
||||
addFn("set", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val d = scp.thisAs<ObjDynamicContext>().delegate
|
||||
if (d.writeCallback != null)
|
||||
scp.raiseIllegalState("set already defined")
|
||||
d.writeCallback = scp.requireOnlyArg()
|
||||
return ObjVoid
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@ -81,11 +82,11 @@ open class ObjDynamic(var readCallback: Statement? = null, var writeCallback: St
|
||||
scope: Scope,
|
||||
name: String,
|
||||
args: Arguments,
|
||||
onNotFoundResult: (suspend () -> Obj?)?
|
||||
onNotFoundResult: OnNotFound?
|
||||
): Obj {
|
||||
val execBase = builderScope?.let { ClosureScope(scope, it) } ?: scope
|
||||
val over = readCallback?.execute(execBase.createChildScope(Arguments(ObjString(name))))
|
||||
return over?.invoke(scope, scope.thisObj, args)
|
||||
return over?.invokeCallable(scope, scope.thisObj, args)
|
||||
?: super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
}
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ package net.sergeych.lyng.obj/*
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
@ -74,12 +75,18 @@ class ObjEnumClass(val name: String) : ObjClass(name, EnumBase) {
|
||||
|
||||
init {
|
||||
addClassConst("entries", objEntries )
|
||||
addClassFn("valueOf") {
|
||||
val name = requireOnlyArg<ObjString>()
|
||||
byName[name] ?: raiseSymbolNotFound("does not exists: enum ${className}.$name")
|
||||
}
|
||||
addPropertyDoc("name", doc = "Entry name as string", type = type("lyng.String"), getter = { thisAs<ObjEnumEntry>().name })
|
||||
addPropertyDoc("ordinal", doc = "Entry ordinal position", type = type("lyng.Int"), getter = { thisAs<ObjEnumEntry>().ordinal })
|
||||
addClassFn("valueOf", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val name = scp.requireOnlyArg<ObjString>()
|
||||
return byName[name] ?: scp.raiseSymbolNotFound("does not exists: enum ${className}.$name")
|
||||
}
|
||||
})
|
||||
addPropertyDoc("name", doc = "Entry name as string", type = type("lyng.String"), getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjEnumEntry>().name
|
||||
})
|
||||
addPropertyDoc("ordinal", doc = "Entry ordinal position", type = type("lyng.Int"), getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjEnumEntry>().ordinal
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -125,7 +125,9 @@ open class ObjException(
|
||||
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
||||
init {
|
||||
constructorMeta = ArgsDeclaration(
|
||||
listOf(ArgsDeclaration.Item("message", defaultValue = statement { ObjString(name) })),
|
||||
listOf(ArgsDeclaration.Item("message", defaultValue = statement(f = object : ScopeCallable {
|
||||
override suspend fun call(scope: Scope): Obj = ObjString(name)
|
||||
}))),
|
||||
Token.Type.RPAREN
|
||||
)
|
||||
}
|
||||
@ -163,27 +165,33 @@ open class ObjException(
|
||||
}
|
||||
|
||||
val Root = ExceptionClass("Exception").apply {
|
||||
instanceInitializers.add(statement {
|
||||
if (thisObj is ObjInstance) {
|
||||
val msg = get("message")?.value ?: ObjString("Exception")
|
||||
(thisObj as ObjInstance).instanceScope.addItem("Exception::message", false, msg)
|
||||
instanceInitializers.add(statement(f = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
if (scp.thisObj is ObjInstance) {
|
||||
val msg = scp.get("message")?.value ?: ObjString("Exception")
|
||||
(scp.thisObj as ObjInstance).instanceScope.addItem("Exception::message", false, msg)
|
||||
|
||||
val stack = captureStackTrace(this)
|
||||
(thisObj as ObjInstance).instanceScope.addItem("Exception::stackTrace", false, stack)
|
||||
val stack = captureStackTrace(scp)
|
||||
(scp.thisObj as ObjInstance).instanceScope.addItem("Exception::stackTrace", false, stack)
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
ObjVoid
|
||||
}))
|
||||
instanceConstructor = statement(f = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjVoid
|
||||
})
|
||||
instanceConstructor = statement { ObjVoid }
|
||||
addPropertyDoc(
|
||||
name = "message",
|
||||
doc = "Human‑readable error message.",
|
||||
type = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
when (val t = this.thisObj) {
|
||||
is ObjException -> t.message
|
||||
is ObjInstance -> t.instanceScope.get("Exception::message")?.value ?: ObjNull
|
||||
else -> ObjNull
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return when (val t = scp.thisObj) {
|
||||
is ObjException -> t.message
|
||||
is ObjInstance -> t.instanceScope.get("Exception::message")?.value ?: ObjNull
|
||||
else -> ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -192,10 +200,12 @@ open class ObjException(
|
||||
doc = "Extra data associated with the exception.",
|
||||
type = type("lyng.Any", nullable = true),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
when (val t = this.thisObj) {
|
||||
is ObjException -> t.extraData
|
||||
else -> ObjNull
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return when (val t = scp.thisObj) {
|
||||
is ObjException -> t.extraData
|
||||
else -> ObjNull
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -204,11 +214,13 @@ open class ObjException(
|
||||
doc = "Stack trace captured at throw site as a list of `StackTraceEntry`.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.StackTraceEntry"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
when (val t = this.thisObj) {
|
||||
is ObjException -> t.getStackTrace()
|
||||
is ObjInstance -> t.instanceScope.get("Exception::stackTrace")?.value as? ObjList ?: ObjList()
|
||||
else -> ObjList()
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return when (val t = scp.thisObj) {
|
||||
is ObjException -> t.getStackTrace()
|
||||
is ObjInstance -> t.instanceScope.get("Exception::stackTrace")?.value as? ObjList ?: ObjList()
|
||||
else -> ObjList()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -216,23 +228,26 @@ open class ObjException(
|
||||
name = "toString",
|
||||
doc = "Human‑readable string representation of the error.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val msg = when (val t = thisObj) {
|
||||
is ObjException -> t.message.value
|
||||
is ObjInstance -> (t.instanceScope.get("Exception::message")?.value as? ObjString)?.value
|
||||
?: t.objClass.className
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val msg = when (val t = scp.thisObj) {
|
||||
is ObjException -> t.message.value
|
||||
is ObjInstance -> (t.instanceScope.get("Exception::message")?.value as? ObjString)?.value
|
||||
?: t.objClass.className
|
||||
|
||||
else -> t.objClass.className
|
||||
else -> t.objClass.className
|
||||
}
|
||||
val stack = when (val t = scp.thisObj) {
|
||||
is ObjException -> t.getStackTrace()
|
||||
is ObjInstance -> t.instanceScope.get("Exception::stackTrace")?.value as? ObjList ?: ObjList()
|
||||
else -> ObjList()
|
||||
}
|
||||
val at = stack.list.firstOrNull()?.toString(scp) ?: ObjString("(unknown)")
|
||||
return ObjString("${scp.thisObj.objClass.className}: $msg at $at")
|
||||
}
|
||||
}
|
||||
val stack = when (val t = thisObj) {
|
||||
is ObjException -> t.getStackTrace()
|
||||
is ObjInstance -> t.instanceScope.get("Exception::stackTrace")?.value as? ObjList ?: ObjList()
|
||||
else -> ObjList()
|
||||
}
|
||||
val at = stack.list.firstOrNull()?.toString(this) ?: ObjString("(unknown)")
|
||||
ObjString("${thisObj.objClass.className}: $msg at $at")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private val op = ProtectedOp()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -45,28 +45,31 @@ class ObjFlowBuilder(val output: SendChannel<Obj>) : Obj() {
|
||||
doc = "Send a value to the flow consumer. Suspends if back‑pressured; no‑ops after consumer stops.",
|
||||
params = listOf(ParamDoc("value", type("lyng.Any"))),
|
||||
returns = type("lyng.Void"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val data = requireOnlyArg<Obj>()
|
||||
try {
|
||||
val channel = thisAs<ObjFlowBuilder>().output
|
||||
if (!channel.isClosedForSend)
|
||||
channel.send(data)
|
||||
else
|
||||
// Flow consumer is no longer collecting; signal producer to stop
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
} catch (x: Exception) {
|
||||
// Any failure to send (including closed channel) should gracefully stop the producer.
|
||||
if (x is CancellationException) {
|
||||
// Cancellation is a normal control-flow event
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
} else {
|
||||
// Treat other send failures as normal flow termination as well
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val data = scp.requireOnlyArg<Obj>()
|
||||
try {
|
||||
val channel = scp.thisAs<ObjFlowBuilder>().output
|
||||
if (!channel.isClosedForSend)
|
||||
channel.send(data)
|
||||
else
|
||||
// Flow consumer is no longer collecting; signal producer to stop
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
} catch (x: Exception) {
|
||||
// Any failure to send (including closed channel) should gracefully stop the producer.
|
||||
if (x is CancellationException) {
|
||||
// Cancellation is a normal control-flow event
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
} else {
|
||||
// Treat other send failures as normal flow termination as well
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
}
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,15 +106,21 @@ class ObjFlow(val producer: Statement, val scope: Scope) : Obj() {
|
||||
name = "iterator",
|
||||
doc = "Create a pull‑based iterator over this flow. Each step resumes the producer as needed.",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val objFlow = thisAs<ObjFlow>()
|
||||
ObjFlowIterator(statement {
|
||||
objFlow.producer.execute(
|
||||
ClosureScope(this, objFlow.scope)
|
||||
)
|
||||
})
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val objFlow = scp.thisAs<ObjFlow>()
|
||||
return ObjFlowIterator(statement(f = object : ScopeCallable {
|
||||
override suspend fun call(scp2: Scope): Obj {
|
||||
objFlow.producer.execute(
|
||||
ClosureScope(scp2, objFlow.scope)
|
||||
)
|
||||
return ObjVoid
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,27 +173,36 @@ class ObjFlowIterator(val producer: Statement) : Obj() {
|
||||
name = "hasNext",
|
||||
doc = "Whether another element is available from the flow.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { thisAs<ObjFlowIterator>().hasNext(this).toObj() }
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjFlowIterator>().hasNext(scp).toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "next",
|
||||
doc = "Receive the next element from the flow or throw if completed.",
|
||||
returns = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val x = thisAs<ObjFlowIterator>()
|
||||
x.next(this)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val x = scp.thisAs<ObjFlowIterator>()
|
||||
return x.next(scp)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "cancelIteration",
|
||||
doc = "Stop iteration and cancel the underlying flow producer.",
|
||||
returns = type("lyng.Void"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val x = thisAs<ObjFlowIterator>()
|
||||
x.cancel()
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val x = scp.thisAs<ObjFlowIterator>()
|
||||
x.cancel()
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,36 +30,6 @@ import net.sergeych.lynon.LynonType
|
||||
class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
|
||||
internal lateinit var instanceScope: Scope
|
||||
internal var fieldSlots: Array<ObjRecord?> = emptyArray()
|
||||
internal var methodSlots: Array<ObjRecord?> = emptyArray()
|
||||
|
||||
internal fun initFieldSlots(size: Int) {
|
||||
fieldSlots = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
internal fun setFieldSlotRecord(slot: Int, rec: ObjRecord) {
|
||||
if (slot >= 0 && slot < fieldSlots.size) fieldSlots[slot] = rec
|
||||
}
|
||||
|
||||
internal fun initMethodSlots(size: Int) {
|
||||
methodSlots = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
internal fun setMethodSlotRecord(slot: Int, rec: ObjRecord) {
|
||||
if (slot >= 0 && slot < methodSlots.size) methodSlots[slot] = rec
|
||||
}
|
||||
|
||||
internal fun fieldRecordForKey(key: String): ObjRecord? {
|
||||
val slot = objClass.fieldSlotForKey(key) ?: return null
|
||||
val idx = slot.slot
|
||||
return if (idx >= 0 && idx < fieldSlots.size) fieldSlots[idx] else null
|
||||
}
|
||||
|
||||
internal fun methodRecordForKey(key: String): ObjRecord? {
|
||||
val slot = objClass.methodSlotForKey(key) ?: return null
|
||||
val idx = slot.slot
|
||||
return if (idx >= 0 && idx < methodSlots.size) methodSlots[idx] else null
|
||||
}
|
||||
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
val caller = scope.currentClassCtx
|
||||
@ -67,16 +37,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// Fast path for public members when outside any class context
|
||||
if (caller == null) {
|
||||
objClass.publicMemberResolution[name]?.let { key ->
|
||||
fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name) ?: objClass
|
||||
return resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
instanceScope.objects[key]?.let { rec ->
|
||||
// Directly return fields to bypass resolveRecord overhead
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
@ -96,16 +56,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
// Check for private fields (stored in instanceScope)
|
||||
val mangled = c.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return resolveRecord(scope, rec, name, c)
|
||||
@ -117,16 +67,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
for (cls in objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val mangled = cls.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
@ -141,12 +81,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
methodRecordForKey(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.visibility, decl, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fall back to super (handles class members and extensions)
|
||||
return super.readField(scope, name)
|
||||
@ -175,13 +109,8 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
val d = decl ?: obj.declaringClass
|
||||
if (d != null) {
|
||||
val mangled = d.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let {
|
||||
targetRec = it
|
||||
}
|
||||
if (targetRec === obj) {
|
||||
instanceScope.objects[mangled]?.let {
|
||||
targetRec = it
|
||||
}
|
||||
instanceScope.objects[mangled]?.let {
|
||||
targetRec = it
|
||||
}
|
||||
}
|
||||
if (targetRec === obj) {
|
||||
@ -205,29 +134,10 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// Fast path for public members when outside any class context
|
||||
if (caller == null) {
|
||||
objClass.publicMemberResolution[name]?.let { key ->
|
||||
fieldRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public) {
|
||||
// Skip property/delegated overhead if it's a plain mutable field
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && rec.isMutable && !rec.isAbstract) {
|
||||
if (rec.value.assign(scope, newValue) == null)
|
||||
rec.value = newValue
|
||||
return
|
||||
}
|
||||
updateRecord(scope, rec, name, newValue, rec.declaringClass)
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, rec.declaringClass)
|
||||
return
|
||||
}
|
||||
}
|
||||
instanceScope.objects[key]?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public) {
|
||||
// Skip property/delegated overhead if it's a plain mutable field
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && rec.isMutable && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Field && rec.isMutable && !rec.isAbstract) {
|
||||
if (rec.value.assign(scope, newValue) == null)
|
||||
rec.value = newValue
|
||||
return
|
||||
@ -250,19 +160,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
// Check for private fields (stored in instanceScope)
|
||||
val mangled = c.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
updateRecord(scope, rec, name, newValue, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
updateRecord(scope, rec, name, newValue, c)
|
||||
@ -275,19 +172,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
for (cls in objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val mangled = cls.mangledName(name)
|
||||
fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name) &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
return
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
@ -304,14 +188,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return
|
||||
}
|
||||
}
|
||||
methodRecordForKey(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name) &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
updateRecord(scope, rec, name, newValue, decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
super.writeField(scope, name, newValue)
|
||||
}
|
||||
@ -342,30 +218,20 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
|
||||
override suspend fun invokeInstanceMethod(
|
||||
scope: Scope, name: String, args: Arguments,
|
||||
onNotFoundResult: (suspend () -> Obj?)?
|
||||
onNotFoundResult: OnNotFound?
|
||||
): Obj {
|
||||
val caller = scope.currentClassCtx
|
||||
|
||||
// Fast path for public members when outside any class context
|
||||
if (caller == null) {
|
||||
objClass.publicMemberResolution[name]?.let { key ->
|
||||
methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
instanceScope.objects[key]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, decl)
|
||||
return rec.value.invokeCallable(instanceScope, this, args, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -375,21 +241,12 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// 0. Prefer private member of current class context
|
||||
caller?.let { c ->
|
||||
val mangled = c.mangledName(name)
|
||||
methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, c)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
instanceScope.objects[mangled]?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, c)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, c)
|
||||
return rec.value.invokeCallable(instanceScope, this, args, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -398,61 +255,53 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, c)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(instanceScope, this, args, c)
|
||||
return rec.value.invokeCallable(instanceScope, this, args, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fast path for non-delegated instance methods in class context
|
||||
methodRecordForKey(name)?.let { rec ->
|
||||
if (!rec.isAbstract && rec.type == ObjRecord.Type.Fun) {
|
||||
val decl = rec.declaringClass ?: objClass.findDeclaringClassOf(name) ?: objClass
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === this) objClass else null
|
||||
if (canAccessMember(rec.visibility, decl, effectiveCaller, name)) {
|
||||
return rec.value.invoke(instanceScope, this, args, decl)
|
||||
// 1. Walk MRO to find member, handling delegation
|
||||
for (cls in objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||
if (rec != null && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val storageName = cls.mangledName(name)
|
||||
val del = instanceScope[storageName]?.delegate ?: rec.delegate
|
||||
?: scope.raiseError("Internal error: delegated member $name has no delegate (tried $storageName)")
|
||||
|
||||
// For delegated member, try 'invokeCallable' first if it's a function-like call
|
||||
val allArgs = (listOf(this, ObjString(name)) + args.list).toTypedArray()
|
||||
return del.invokeInstanceMethod(scope, "invokeCallable", Arguments(*allArgs), onNotFoundResult = {
|
||||
// Fallback: property delegation (getValue then call result)
|
||||
val propVal = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
propVal.invokeCallable(scope, this, args, rec.declaringClass ?: cls)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Resolve instance member via cached MRO lookup, handling delegation
|
||||
objClass.resolveInstanceMember(name)?.let { resolvedMember ->
|
||||
val rec = resolvedMember.record
|
||||
val decl = resolvedMember.declaringClass
|
||||
if (rec.type == ObjRecord.Type.Delegated) {
|
||||
val storageName = decl.mangledName(name)
|
||||
val del = instanceScope[storageName]?.delegate ?: rec.delegate
|
||||
?: scope.raiseError("Internal error: delegated member $name has no delegate (tried $storageName)")
|
||||
|
||||
// For delegated member, try 'invoke' first if it's a function-like call
|
||||
val allArgs = (listOf(this, ObjString(name)) + args.list).toTypedArray()
|
||||
return del.invokeInstanceMethod(scope, "invoke", Arguments(*allArgs), onNotFoundResult = {
|
||||
// Fallback: property delegation (getValue then call result)
|
||||
val propVal = del.invokeInstanceMethod(scope, "getValue", Arguments(this, ObjString(name)))
|
||||
propVal.invoke(scope, this, args, rec.declaringClass ?: decl)
|
||||
})
|
||||
}
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === this) objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't invoke method $name (declared in ${decl.className})"
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === this) objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't invokeCallable method $name (declared in ${decl.className})"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(
|
||||
instanceScope,
|
||||
this,
|
||||
args,
|
||||
decl
|
||||
)
|
||||
} else if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField || rec.type == ObjRecord.Type.Argument) {
|
||||
val resolved = readField(scope, name)
|
||||
return resolved.value.invoke(scope, this, args, resolved.declaringClass)
|
||||
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invokeCallable(
|
||||
instanceScope,
|
||||
this,
|
||||
args,
|
||||
decl
|
||||
)
|
||||
} else if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField || rec.type == ObjRecord.Type.Argument) {
|
||||
val resolved = readField(scope, name)
|
||||
return resolved.value.invokeCallable(scope, this, args, resolved.declaringClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -582,14 +431,6 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
// Qualified field access: prefer mangled storage for the qualified ancestor
|
||||
val mangled = "${startClass.className}::$name"
|
||||
instance.fieldRecordForKey(mangled)?.let { rec ->
|
||||
// Visibility: declaring class is the qualified ancestor for mangled storage
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access field $name (declared in ${decl.className})"))
|
||||
return instance.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
instance.instanceScope.objects[mangled]?.let { rec ->
|
||||
// Visibility: declaring class is the qualified ancestor for mangled storage
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
@ -626,18 +467,6 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
||||
// Qualified write: target mangled storage for the ancestor
|
||||
val mangled = "${startClass.className}::$name"
|
||||
instance.fieldRecordForKey(mangled)?.let { f ->
|
||||
val decl = f.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't assign to field $name (declared in ${decl.className})"
|
||||
).raise()
|
||||
if (!f.isMutable && f.value !== ObjUnset) ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
if (f.value.assign(scope, newValue) == null) f.value = newValue
|
||||
return
|
||||
}
|
||||
instance.instanceScope.objects[mangled]?.let { f ->
|
||||
val decl = f.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
@ -678,18 +507,18 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
scope: Scope,
|
||||
name: String,
|
||||
args: Arguments,
|
||||
onNotFoundResult: (suspend () -> Obj?)?
|
||||
onNotFoundResult: OnNotFound?
|
||||
): Obj {
|
||||
// Qualified method dispatch must start from the specified ancestor, not from the instance scope.
|
||||
memberFromAncestor(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method $name (declared in ${decl.className})"))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invokeCallable method $name (declared in ${decl.className})"))
|
||||
val saved = instance.instanceScope.currentClassCtx
|
||||
instance.instanceScope.currentClassCtx = decl
|
||||
try {
|
||||
return rec.value.invoke(instance.instanceScope, instance, args)
|
||||
return rec.value.invokeCallable(instance.instanceScope, instance, args)
|
||||
} finally {
|
||||
instance.instanceScope.currentClassCtx = saved
|
||||
}
|
||||
@ -703,20 +532,20 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
scope.raiseError(
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't invoke method $name (declared in ${decl?.className ?: "?"})"
|
||||
"can't invokeCallable method $name (declared in ${decl?.className ?: "?"})"
|
||||
)
|
||||
)
|
||||
val saved = instance.instanceScope.currentClassCtx
|
||||
instance.instanceScope.currentClassCtx = decl
|
||||
try {
|
||||
return rec.value.invoke(instance.instanceScope, instance, args)
|
||||
return rec.value.invokeCallable(instance.instanceScope, instance, args)
|
||||
} finally {
|
||||
instance.instanceScope.currentClassCtx = saved
|
||||
}
|
||||
}
|
||||
}
|
||||
return onNotFoundResult?.invoke() ?: scope.raiseSymbolNotFound(name)
|
||||
return onNotFoundResult?.call() ?: scope.raiseSymbolNotFound(name)
|
||||
}
|
||||
|
||||
override fun toString(): String = instance.toString()
|
||||
}
|
||||
}
|
||||
@ -18,17 +18,16 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.datetime.*
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonSettings
|
||||
import net.sergeych.lynon.LynonType
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.isDistantFuture
|
||||
import kotlin.time.isDistantPast
|
||||
|
||||
@ -113,7 +112,7 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
return ObjInstant(
|
||||
when (a0) {
|
||||
null -> {
|
||||
val t = Clock.System.now()
|
||||
val t = kotlin.time.Clock.System.now()
|
||||
Instant.fromEpochSeconds(t.epochSeconds, t.nanosecondsOfSecond)
|
||||
}
|
||||
is ObjInt -> Instant.fromEpochSeconds(a0.value)
|
||||
@ -157,9 +156,11 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
doc = "Return the number of seconds since the Unix epoch as a real number (including fractions).",
|
||||
type = type("lyng.Real"),
|
||||
moduleName = "lyng.time",
|
||||
getter = {
|
||||
val instant = thisAs<ObjInstant>().instant
|
||||
ObjReal(instant.epochSeconds + instant.nanosecondsOfSecond * 1e-9)
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val instant = scp.thisAs<ObjInstant>().instant
|
||||
return ObjReal(instant.epochSeconds + instant.nanosecondsOfSecond * 1e-9)
|
||||
}
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
@ -167,92 +168,114 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
doc = "Whether this instant represents the distant future.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjInstant>().instant.isDistantFuture.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjInstant>().instant.isDistantFuture.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isDistantPast",
|
||||
doc = "Whether this instant represents the distant past.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjInstant>().instant.isDistantPast.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjInstant>().instant.isDistantPast.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "epochWholeSeconds",
|
||||
doc = "Return the number of full seconds since the Unix epoch.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjInt(thisAs<ObjInstant>().instant.epochSeconds) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt(scp.thisAs<ObjInstant>().instant.epochSeconds)
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "nanosecondsOfSecond",
|
||||
doc = "The number of nanoseconds within the current second.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjInt(thisAs<ObjInstant>().instant.nanosecondsOfSecond.toLong()) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt(scp.thisAs<ObjInstant>().instant.nanosecondsOfSecond.toLong())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "truncateToMinute",
|
||||
doc = "Truncate this instant to the nearest minute.",
|
||||
returns = type("lyng.Instant"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
val t = thisAs<ObjInstant>().instant
|
||||
val tz = TimeZone.UTC
|
||||
val dt = t.toLocalDateTime(tz)
|
||||
val truncated = LocalDateTime(dt.year, dt.month, dt.dayOfMonth, dt.hour, dt.minute, 0, 0)
|
||||
ObjInstant(truncated.toInstant(tz), LynonSettings.InstantTruncateMode.Second)
|
||||
}
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val t = scp.thisAs<ObjInstant>().instant
|
||||
val tz = TimeZone.UTC
|
||||
val dt = t.toLocalDateTime(tz)
|
||||
val truncated = LocalDateTime(dt.year, dt.month, dt.dayOfMonth, dt.hour, dt.minute, 0, 0)
|
||||
return ObjInstant(truncated.toInstant(tz), LynonSettings.InstantTruncateMode.Second)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "truncateToSecond",
|
||||
doc = "Truncate this instant to the nearest second.",
|
||||
returns = type("lyng.Instant"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
val t = thisAs<ObjInstant>().instant
|
||||
ObjInstant(Instant.fromEpochSeconds(t.epochSeconds), LynonSettings.InstantTruncateMode.Second)
|
||||
}
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val t = scp.thisAs<ObjInstant>().instant
|
||||
return ObjInstant(Instant.fromEpochSeconds(t.epochSeconds), LynonSettings.InstantTruncateMode.Second)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "truncateToMillisecond",
|
||||
doc = "Truncate this instant to the nearest millisecond.",
|
||||
returns = type("lyng.Instant"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
val t = thisAs<ObjInstant>().instant
|
||||
ObjInstant(
|
||||
Instant.fromEpochSeconds(t.epochSeconds, t.nanosecondsOfSecond / 1_000_000 * 1_000_000),
|
||||
LynonSettings.InstantTruncateMode.Millisecond
|
||||
)
|
||||
}
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val t = scp.thisAs<ObjInstant>().instant
|
||||
return ObjInstant(
|
||||
Instant.fromEpochSeconds(t.epochSeconds, t.nanosecondsOfSecond / 1_000_000 * 1_000_000),
|
||||
LynonSettings.InstantTruncateMode.Millisecond
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "truncateToMicrosecond",
|
||||
doc = "Truncate this instant to the nearest microsecond.",
|
||||
returns = type("lyng.Instant"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
val t = thisAs<ObjInstant>().instant
|
||||
ObjInstant(
|
||||
Instant.fromEpochSeconds(t.epochSeconds, t.nanosecondsOfSecond / 1_000 * 1_000),
|
||||
LynonSettings.InstantTruncateMode.Microsecond
|
||||
)
|
||||
}
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val t = scp.thisAs<ObjInstant>().instant
|
||||
return ObjInstant(
|
||||
Instant.fromEpochSeconds(t.epochSeconds, t.nanosecondsOfSecond / 1_000 * 1_000),
|
||||
LynonSettings.InstantTruncateMode.Microsecond
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "toRFC3339",
|
||||
doc = "Return the RFC3339 string representation of this instant in UTC (e.g., '1970-01-01T00:00:00Z').",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
thisAs<ObjInstant>().instant.toString().toObj()
|
||||
}
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjInstant>().instant.toString().toObj()
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "toSortableString",
|
||||
doc = "Alias to toRFC3339.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
thisAs<ObjInstant>().instant.toString().toObj()
|
||||
}
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjInstant>().instant.toString().toObj()
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "toDateTime",
|
||||
@ -261,24 +284,27 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
"If no argument is provided, the system's current default time zone is used.",
|
||||
params = listOf(net.sergeych.lyng.miniast.ParamDoc("tz", type = type("lyng.Any", true))),
|
||||
returns = type("lyng.DateTime"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
val tz = when (val a = args.list.getOrNull(0)) {
|
||||
null -> TimeZone.currentSystemDefault()
|
||||
is ObjString -> TimeZone.of(a.value)
|
||||
is ObjInt -> UtcOffset(seconds = a.value.toInt()).asTimeZone()
|
||||
else -> raiseIllegalArgument("invalid timezone: $a")
|
||||
moduleName = "lyng.time",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val tz = when (val a = scp.args.list.getOrNull(0)) {
|
||||
null -> TimeZone.currentSystemDefault()
|
||||
is ObjString -> TimeZone.of(a.value)
|
||||
is ObjInt -> UtcOffset(seconds = a.value.toInt()).asTimeZone()
|
||||
else -> scp.raiseIllegalArgument("invalid timezone: $a")
|
||||
}
|
||||
return ObjDateTime(scp.thisAs<ObjInstant>().instant, tz)
|
||||
}
|
||||
}
|
||||
ObjDateTime(thisAs<ObjInstant>().instant, tz)
|
||||
}
|
||||
)
|
||||
|
||||
// class members
|
||||
|
||||
addClassConst("distantFuture", distantFuture)
|
||||
addClassConst("distantPast", distantPast)
|
||||
addClassFn("now") {
|
||||
ObjInstant(Clock.System.now())
|
||||
}
|
||||
addClassFn("now", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInstant(kotlin.time.Clock.System.now())
|
||||
})
|
||||
// addFn("epochMilliseconds") {
|
||||
// ObjInt(instant.toEpochMilliseconds())
|
||||
// }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -20,6 +20,7 @@ package net.sergeych.lyng.obj
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
@ -55,11 +56,7 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if (other !is Numeric) return -2
|
||||
return if (other is ObjInt) {
|
||||
value.compareTo(other.value)
|
||||
} else {
|
||||
doubleValue.compareTo(other.doubleValue)
|
||||
}
|
||||
return value.compareTo(other.doubleValue)
|
||||
}
|
||||
|
||||
override fun toString(): String = value.toString()
|
||||
@ -163,19 +160,13 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val CACHE_LOW: Long = -1024L
|
||||
internal const val CACHE_HIGH: Long = 1023L
|
||||
private val cache = Array((CACHE_HIGH - CACHE_LOW + 1).toInt()) {
|
||||
ObjInt((it + CACHE_LOW).toLong(), true)
|
||||
}
|
||||
private val cache = Array(256) { ObjInt((it - 128).toLong(), true) }
|
||||
|
||||
fun of(value: Long): ObjInt {
|
||||
return if (value in CACHE_LOW..CACHE_HIGH) cache[(value - CACHE_LOW).toInt()]
|
||||
return if (value in -128L..127L) cache[(value + 128).toInt()]
|
||||
else ObjInt(value)
|
||||
}
|
||||
|
||||
internal fun cacheArray(): Array<ObjInt> = cache
|
||||
|
||||
val Zero = of(0)
|
||||
val One = of(1)
|
||||
val type = object : ObjClass("Int") {
|
||||
@ -193,13 +184,14 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
name = "toInt",
|
||||
doc = "Returns this integer (identity operation).",
|
||||
returns = net.sergeych.lyng.miniast.type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisObj
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisObj
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.toObj() = ObjInt.of(this.toLong())
|
||||
fun Long.toObj() = ObjInt.of(this)
|
||||
fun Long.toObj() = ObjInt.of(this)
|
||||
@ -18,6 +18,8 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Arguments
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.miniast.ParamDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
@ -35,13 +37,15 @@ val ObjIterable by lazy {
|
||||
doc = "Collect elements of this iterable into a new list.",
|
||||
type = type("lyng.List"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val result = mutableListOf<Obj>()
|
||||
val it = this.thisObj.invokeInstanceMethod(this, "iterator")
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
result.add(it.invokeInstanceMethod(this, "next"))
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val result = mutableListOf<Obj>()
|
||||
val it = scp.thisObj.invokeInstanceMethod(scp, "iterator")
|
||||
while (it.invokeInstanceMethod(scp, "hasNext").toBool()) {
|
||||
result.add(it.invokeInstanceMethod(scp, "next"))
|
||||
}
|
||||
return ObjList(result)
|
||||
}
|
||||
ObjList(result)
|
||||
}
|
||||
)
|
||||
|
||||
@ -52,16 +56,19 @@ val ObjIterable by lazy {
|
||||
params = listOf(ParamDoc("element")),
|
||||
returns = type("lyng.Bool"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val obj = args.firstAndOnly()
|
||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
if (obj.equals(this, it.invokeInstanceMethod(this, "next")))
|
||||
return@addFnDoc ObjTrue
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val obj = scp.args.firstAndOnly()
|
||||
val it = scp.thisObj.invokeInstanceMethod(scp, "iterator")
|
||||
while (it.invokeInstanceMethod(scp, "hasNext").toBool()) {
|
||||
if (obj.equals(scp, it.invokeInstanceMethod(scp, "next")))
|
||||
return ObjTrue
|
||||
}
|
||||
return ObjFalse
|
||||
}
|
||||
}
|
||||
ObjFalse
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "indexOf",
|
||||
@ -69,34 +76,39 @@ val ObjIterable by lazy {
|
||||
params = listOf(ParamDoc("element")),
|
||||
returns = type("lyng.Int"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val obj = args.firstAndOnly()
|
||||
var index = 0
|
||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
if (obj.equals(this, it.invokeInstanceMethod(this, "next")))
|
||||
return@addFnDoc ObjInt(index.toLong())
|
||||
index++
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val obj = scp.args.firstAndOnly()
|
||||
var index = 0
|
||||
val it = scp.thisObj.invokeInstanceMethod(scp, "iterator")
|
||||
while (it.invokeInstanceMethod(scp, "hasNext").toBool()) {
|
||||
if (obj.equals(scp, it.invokeInstanceMethod(scp, "next")))
|
||||
return ObjInt(index.toLong())
|
||||
index++
|
||||
}
|
||||
return ObjInt(-1L)
|
||||
}
|
||||
}
|
||||
ObjInt(-1L)
|
||||
}
|
||||
)
|
||||
|
||||
addPropertyDoc(
|
||||
name = "toSet",
|
||||
doc = "Collect elements of this iterable into a new set.",
|
||||
type = type("lyng.Set"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
if( this.thisObj.isInstanceOf(ObjSet.type) )
|
||||
this.thisObj
|
||||
else {
|
||||
val result = mutableSetOf<Obj>()
|
||||
val it = this.thisObj.invokeInstanceMethod(this, "iterator")
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
result.add(it.invokeInstanceMethod(this, "next"))
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return if( scp.thisObj.isInstanceOf(ObjSet.type) )
|
||||
scp.thisObj
|
||||
else {
|
||||
val result = mutableSetOf<Obj>()
|
||||
val it = scp.thisObj.invokeInstanceMethod(scp, "iterator")
|
||||
while (it.invokeInstanceMethod(scp, "hasNext").toBool()) {
|
||||
result.add(it.invokeInstanceMethod(scp, "next"))
|
||||
}
|
||||
ObjSet(result)
|
||||
}
|
||||
ObjSet(result)
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -106,16 +118,20 @@ val ObjIterable by lazy {
|
||||
doc = "Collect pairs into a map using [0] as key and [1] as value for each element.",
|
||||
type = type("lyng.Map"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val result = mutableMapOf<Obj, Obj>()
|
||||
this.thisObj.enumerate(this) { pair ->
|
||||
when (pair) {
|
||||
is ObjMapEntry -> result[pair.key] = pair.value
|
||||
else -> result[pair.getAt(this, 0)] = pair.getAt(this, 1)
|
||||
}
|
||||
true
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val result = mutableMapOf<Obj, Obj>()
|
||||
scp.thisObj.enumerate(scp, object : EnumerateCallback {
|
||||
override suspend fun call(pair: Obj): Boolean {
|
||||
when (pair) {
|
||||
is ObjMapEntry -> result[pair.key] = pair.value
|
||||
else -> result[pair.getAt(scp, ObjInt(0))] = pair.getAt(scp, ObjInt(1))
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return ObjMap(result)
|
||||
}
|
||||
ObjMap(result)
|
||||
}
|
||||
)
|
||||
|
||||
@ -124,31 +140,37 @@ val ObjIterable by lazy {
|
||||
doc = "Build a map from elements using the lambda result as key.",
|
||||
params = listOf(ParamDoc("keySelector")),
|
||||
returns = type("lyng.Map"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val association = requireOnlyArg<Statement>()
|
||||
val result = ObjMap()
|
||||
thisObj.toFlow(this).collect {
|
||||
result.map[association.call(this, it)] = it
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val association = scp.requireOnlyArg<Statement>()
|
||||
val result = ObjMap()
|
||||
scp.thisObj.toFlow(scp).collect {
|
||||
result.map[association.invokeCallable(scp, scp.thisObj, it)] = it
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "forEach",
|
||||
doc = "Apply the lambda to each element in iteration order.",
|
||||
params = listOf(ParamDoc("action")),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
||||
val fn = requiredArg<Statement>(0)
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
val x = it.invokeInstanceMethod(this, "next")
|
||||
fn.execute(this.createChildScope(Arguments(listOf(x))))
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val it = scp.thisObj.invokeInstanceMethod(scp, "iterator")
|
||||
val fn = scp.requiredArg<Statement>(0)
|
||||
while (it.invokeInstanceMethod(scp, "hasNext").toBool()) {
|
||||
val x = it.invokeInstanceMethod(scp, "next")
|
||||
fn.execute(scp.createChildScope(Arguments(listOf(x))))
|
||||
}
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "map",
|
||||
@ -156,15 +178,18 @@ val ObjIterable by lazy {
|
||||
params = listOf(ParamDoc("transform")),
|
||||
returns = type("lyng.List"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val fn = requiredArg<Statement>(0)
|
||||
val result = mutableListOf<Obj>()
|
||||
thisObj.toFlow(this).collect {
|
||||
result.add(fn.call(this, it))
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val fn = scp.requiredArg<Statement>(0)
|
||||
val result = mutableListOf<Obj>()
|
||||
scp.thisObj.toFlow(scp).collect {
|
||||
result.add(fn.invokeCallable(scp, scp.thisObj, it))
|
||||
}
|
||||
return ObjList(result)
|
||||
}
|
||||
}
|
||||
ObjList(result)
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "mapNotNull",
|
||||
@ -172,46 +197,56 @@ val ObjIterable by lazy {
|
||||
params = listOf(ParamDoc("transform")),
|
||||
returns = type("lyng.List"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val fn = requiredArg<Statement>(0)
|
||||
val result = mutableListOf<Obj>()
|
||||
thisObj.toFlow(this).collect {
|
||||
val transformed = fn.call(this, it)
|
||||
if( transformed != ObjNull) result.add(transformed)
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val fn = scp.requiredArg<Statement>(0)
|
||||
val result = mutableListOf<Obj>()
|
||||
scp.thisObj.toFlow(scp).collect {
|
||||
val transformed = fn.invokeCallable(scp, scp.thisObj, it)
|
||||
if( transformed != ObjNull) result.add(transformed)
|
||||
}
|
||||
return ObjList(result)
|
||||
}
|
||||
}
|
||||
ObjList(result)
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "take",
|
||||
doc = "Take the first N elements and return them as a list.",
|
||||
params = listOf(ParamDoc("n", type("lyng.Int"))),
|
||||
returns = type("lyng.List"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
var n = requireOnlyArg<ObjInt>().value.toInt()
|
||||
val result = mutableListOf<Obj>()
|
||||
if (n > 0) {
|
||||
thisObj.enumerate(this) {
|
||||
result.add(it)
|
||||
--n > 0
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
var n = scp.requireOnlyArg<ObjInt>().value.toInt()
|
||||
val result = mutableListOf<Obj>()
|
||||
if (n > 0) {
|
||||
scp.thisObj.enumerate(scp, object : EnumerateCallback {
|
||||
override suspend fun call(element: Obj): Boolean {
|
||||
result.add(element)
|
||||
return --n > 0
|
||||
}
|
||||
})
|
||||
}
|
||||
return ObjList(result)
|
||||
}
|
||||
}
|
||||
ObjList(result)
|
||||
}
|
||||
)
|
||||
|
||||
addPropertyDoc(
|
||||
name = "isEmpty",
|
||||
doc = "Whether the iterable has no elements.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
ObjBool(
|
||||
this.thisObj.invokeInstanceMethod(this, "iterator")
|
||||
.invokeInstanceMethod(this, "hasNext").toBool()
|
||||
.not()
|
||||
)
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjBool(
|
||||
scp.thisObj.invokeInstanceMethod(scp, "iterator")
|
||||
.invokeInstanceMethod(scp, "hasNext").toBool()
|
||||
.not()
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@ -220,25 +255,31 @@ val ObjIterable by lazy {
|
||||
doc = "Return a new list sorted using the provided comparator `(a, b) -> Int`.",
|
||||
params = listOf(ParamDoc("comparator")),
|
||||
returns = type("lyng.List"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val list = thisObj.callMethod<ObjList>(this, "toList")
|
||||
val comparator = requireOnlyArg<Statement>()
|
||||
list.quicksort { a, b ->
|
||||
comparator.call(this, a, b).toInt()
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val list = scp.thisObj.callMethod<ObjList>(scp, "toList")
|
||||
val comparator = scp.requireOnlyArg<Statement>()
|
||||
list.quicksort { a, b ->
|
||||
comparator.invokeCallable(scp, scp.thisObj, a, b).toInt()
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
list
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "reversed",
|
||||
doc = "Return a new list with elements in reverse order.",
|
||||
returns = type("lyng.List"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val list = thisObj.callMethod<ObjList>(this, "toList")
|
||||
list.list.reverse()
|
||||
list
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val list = scp.thisObj.callMethod<ObjList>(scp, "toList")
|
||||
list.list.reverse()
|
||||
return list
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -17,6 +17,8 @@
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.TypeGenericDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
@ -38,44 +40,50 @@ val ObjIterator by lazy {
|
||||
doc = "Optional hint to stop iteration early and free resources.",
|
||||
returns = type("lyng.Void"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjVoid
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "hasNext",
|
||||
doc = "Whether another element is available.",
|
||||
returns = type("lyng.Bool"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
raiseNotImplemented("hasNext() is not implemented")
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.raiseNotImplemented("hasNext() is not implemented")
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "next",
|
||||
doc = "Return the next element.",
|
||||
returns = type("lyng.Any"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
raiseNotImplemented("next() is not implemented")
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.raiseNotImplemented("next() is not implemented")
|
||||
}
|
||||
)
|
||||
// Helper to consume iterator into a list
|
||||
addFnDoc(
|
||||
name = "toList",
|
||||
doc = "Consume this iterator and collect elements into a list.",
|
||||
returns = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val out = mutableListOf<Obj>()
|
||||
while (true) {
|
||||
val has = thisObj.invokeInstanceMethod(this, "hasNext").toBool()
|
||||
if (!has) break
|
||||
val v = thisObj.invokeInstanceMethod(this, "next")
|
||||
out += v
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val out = mutableListOf<Obj>()
|
||||
while (true) {
|
||||
val has = scp.thisObj.invokeInstanceMethod(scp, "hasNext").toBool()
|
||||
if (!has) break
|
||||
val v = scp.thisObj.invokeInstanceMethod(scp, "next")
|
||||
out += v
|
||||
}
|
||||
return ObjList(out.toMutableList())
|
||||
}
|
||||
}
|
||||
ObjList(out.toMutableList())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -22,6 +22,7 @@ package net.sergeych.lyng.obj
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
|
||||
/**
|
||||
* Iterator wrapper to allow Kotlin collections to be returned from Lyng objects;
|
||||
@ -33,8 +34,12 @@ class ObjKotlinIterator(val iterator: Iterator<Any?>) : Obj() {
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("KotlinIterator", ObjIterator).apply {
|
||||
addFn("next") { thisAs<ObjKotlinIterator>().iterator.next().toObj() }
|
||||
addFn("hasNext") { thisAs<ObjKotlinIterator>().iterator.hasNext().toObj() }
|
||||
addFn("next", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjKotlinIterator>().iterator.next().toObj()
|
||||
})
|
||||
addFn("hasNext", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjKotlinIterator>().iterator.hasNext().toObj()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@ -50,12 +55,14 @@ class ObjKotlinObjIterator(val iterator: Iterator<Obj>) : Obj() {
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("KotlinIterator", ObjIterator).apply {
|
||||
addFn("next") {
|
||||
thisAs<ObjKotlinObjIterator>().iterator.next()
|
||||
}
|
||||
addFn("hasNext") {
|
||||
thisAs<ObjKotlinObjIterator>().iterator.hasNext().toObj()
|
||||
}
|
||||
addFn("next", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.thisAs<ObjKotlinObjIterator>().iterator.next()
|
||||
})
|
||||
addFn("hasNext", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.thisAs<ObjKotlinObjIterator>().iterator.hasNext().toObj()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@ -71,8 +78,8 @@ fun Obj.toFlow(scope: Scope): Flow<Obj> = flow {
|
||||
val iterator = invokeInstanceMethod(scope, "iterator")
|
||||
val hasNext = iterator.getInstanceMethod(scope, "hasNext")
|
||||
val next = iterator.getInstanceMethod(scope, "next")
|
||||
while (hasNext.invoke(scope, iterator).toBool()) {
|
||||
emit(next.invoke(scope, iterator))
|
||||
while (hasNext.invokeCallable(scope, iterator).toBool()) {
|
||||
emit(next.invokeCallable(scope, iterator))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ package net.sergeych.lyng.obj
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.miniast.ParamDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
@ -111,13 +112,13 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
val next2 = it2.getInstanceMethod(scope, "next")
|
||||
|
||||
while (it1.hasNext()) {
|
||||
if (!hasNext2.invoke(scope, it2).toBool()) return 1 // I'm longer
|
||||
if (!hasNext2.invokeCallable(scope, it2).toBool()) return 1 // I'm longer
|
||||
val v1 = it1.next()
|
||||
val v2 = next2.invoke(scope, it2)
|
||||
val v2 = next2.invokeCallable(scope, it2)
|
||||
val d = v1.compareTo(scope, v2)
|
||||
if (d != 0) return d
|
||||
}
|
||||
return if (hasNext2.invoke(scope, it2).toBool()) -1 else 0
|
||||
return if (hasNext2.invokeCallable(scope, it2).toBool()) -1 else 0
|
||||
}
|
||||
return -2
|
||||
}
|
||||
@ -169,9 +170,9 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
return list.contains(other)
|
||||
}
|
||||
|
||||
override suspend fun enumerate(scope: Scope, callback: suspend (Obj) -> Boolean) {
|
||||
override suspend fun enumerate(scope: Scope, callback: EnumerateCallback) {
|
||||
for (item in list) {
|
||||
if (!callback(item)) break
|
||||
if (!callback.call(item)) break
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +180,9 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
get() = type
|
||||
|
||||
override suspend fun toKotlin(scope: Scope): Any {
|
||||
return list.map { it.toKotlin(scope) }
|
||||
val res = ArrayList<Any?>(list.size)
|
||||
for (i in list) res.add(i.toKotlin(scope))
|
||||
return res
|
||||
}
|
||||
|
||||
suspend fun quicksort(compare: suspend (Obj, Obj) -> Int) = quicksort(compare, 0, list.size - 1)
|
||||
@ -230,7 +233,9 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
override suspend fun lynonType(): LynonType = LynonType.List
|
||||
|
||||
override suspend fun toJson(scope: Scope): JsonElement {
|
||||
return JsonArray(list.map { it.toJson(scope) })
|
||||
val res = ArrayList<JsonElement>(list.size)
|
||||
for (i in list) res.add(i.toJson(scope))
|
||||
return JsonArray(res)
|
||||
}
|
||||
|
||||
override suspend fun defaultToString(scope: Scope): ObjString {
|
||||
@ -256,256 +261,290 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
doc = "Number of elements in this list.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val s = (this.thisObj as ObjList).list.size
|
||||
s.toObj()
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return (scp.thisObj as ObjList).list.size.toObj()
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "add",
|
||||
doc = "Append one or more elements to the end of this list.",
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val l = thisAs<ObjList>().list
|
||||
for (a in args) l.add(a)
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val l = scp.thisAs<ObjList>().list
|
||||
for (a in scp.args) l.add(a)
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "insertAt",
|
||||
doc = "Insert elements starting at the given index.",
|
||||
params = listOf(ParamDoc("index", type("lyng.Int"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
if (args.size < 2) raiseError("addAt takes 2+ arguments")
|
||||
val l = thisAs<ObjList>()
|
||||
var index = requiredArg<ObjInt>(0).value.toInt()
|
||||
for (i in 1..<args.size) l.list.add(index++, args[i])
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
if (scp.args.size < 2) scp.raiseError("addAt takes 2+ arguments")
|
||||
val l = scp.thisAs<ObjList>()
|
||||
var index = scp.requiredArg<ObjInt>(0).value.toInt()
|
||||
for (i in 1..<scp.args.size) l.list.add(index++, scp.args[i])
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "removeAt",
|
||||
doc = "Remove element at index, or a range [start,end) if two indices are provided. Returns the list.",
|
||||
params = listOf(ParamDoc("start", type("lyng.Int")), ParamDoc("end", type("lyng.Int"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val self = thisAs<ObjList>()
|
||||
val start = requiredArg<ObjInt>(0).value.toInt()
|
||||
if (args.size == 2) {
|
||||
val end = requireOnlyArg<ObjInt>().value.toInt()
|
||||
self.list.subList(start, end).clear()
|
||||
} else
|
||||
self.list.removeAt(start)
|
||||
self
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjList>()
|
||||
val start = scp.requiredArg<ObjInt>(0).value.toInt()
|
||||
if (scp.args.size == 2) {
|
||||
val end = scp.requireOnlyArg<ObjInt>().value.toInt()
|
||||
self.list.subList(start, end).clear()
|
||||
} else
|
||||
self.list.removeAt(start)
|
||||
return self
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "removeLast",
|
||||
doc = "Remove the last element or the last N elements if a count is provided. Returns the list.",
|
||||
params = listOf(ParamDoc("count", type("lyng.Int"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val self = thisAs<ObjList>()
|
||||
if (args.isNotEmpty()) {
|
||||
val count = requireOnlyArg<ObjInt>().value.toInt()
|
||||
val size = self.list.size
|
||||
if (count >= size) self.list.clear()
|
||||
else self.list.subList(size - count, size).clear()
|
||||
} else self.list.removeLast()
|
||||
self
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjList>()
|
||||
if (scp.args.isNotEmpty()) {
|
||||
val count = scp.requireOnlyArg<ObjInt>().value.toInt()
|
||||
val size = self.list.size
|
||||
if (count >= size) self.list.clear()
|
||||
else self.list.subList(size - count, size).clear()
|
||||
} else self.list.removeLast()
|
||||
return self
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "removeRange",
|
||||
doc = "Remove a range of elements. Accepts a Range or (start, endInclusive). Returns the list.",
|
||||
params = listOf(ParamDoc("range")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val self = thisAs<ObjList>()
|
||||
val list = self.list
|
||||
val range = requiredArg<Obj>(0)
|
||||
if (range is ObjRange) {
|
||||
val index = range
|
||||
when {
|
||||
index.start is ObjInt && index.end is ObjInt -> {
|
||||
if (index.isEndInclusive)
|
||||
list.subList(index.start.toInt(), index.end.toInt() + 1)
|
||||
else
|
||||
list.subList(index.start.toInt(), index.end.toInt())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjList>()
|
||||
val list = self.list
|
||||
val range = scp.requiredArg<Obj>(0)
|
||||
if (range is ObjRange) {
|
||||
val index = range
|
||||
when {
|
||||
index.start is ObjInt && index.end is ObjInt -> {
|
||||
if (index.isEndInclusive)
|
||||
list.subList(index.start.toInt(), index.end.toInt() + 1)
|
||||
else
|
||||
list.subList(index.start.toInt(), index.end.toInt())
|
||||
}
|
||||
|
||||
index.isOpenStart && !index.isOpenEnd -> {
|
||||
if (index.isEndInclusive)
|
||||
list.subList(0, index.end!!.toInt() + 1)
|
||||
else
|
||||
list.subList(0, index.end!!.toInt())
|
||||
}
|
||||
index.isOpenStart && !index.isOpenEnd -> {
|
||||
if (index.isEndInclusive)
|
||||
list.subList(0, index.end!!.toInt() + 1)
|
||||
else
|
||||
list.subList(0, index.end!!.toInt())
|
||||
}
|
||||
|
||||
index.isOpenEnd && !index.isOpenStart -> {
|
||||
list.subList(index.start!!.toInt(), list.size)
|
||||
}
|
||||
index.isOpenEnd && !index.isOpenStart -> {
|
||||
list.subList(index.start!!.toInt(), list.size)
|
||||
}
|
||||
|
||||
index.isOpenStart && index.isOpenEnd -> {
|
||||
list
|
||||
}
|
||||
index.isOpenStart && index.isOpenEnd -> {
|
||||
list
|
||||
}
|
||||
|
||||
else -> {
|
||||
throw RuntimeException("Can't apply range for index: $index")
|
||||
else -> {
|
||||
throw RuntimeException("Can't apply range for index: $index")
|
||||
}
|
||||
}.clear()
|
||||
} else {
|
||||
val start = range.toInt()
|
||||
val end = scp.requiredArg<ObjInt>(1).value.toInt() + 1
|
||||
self.list.subList(start, end).clear()
|
||||
}
|
||||
}.clear()
|
||||
} else {
|
||||
val start = range.toInt()
|
||||
val end = requiredArg<ObjInt>(1).value.toInt() + 1
|
||||
self.list.subList(start, end).clear()
|
||||
return self
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
)
|
||||
|
||||
addFnDoc(
|
||||
name = "sortWith",
|
||||
doc = "Sort this list in-place using a comparator function (a, b) -> Int.",
|
||||
params = listOf(ParamDoc("comparator")),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val comparator = requireOnlyArg<Statement>()
|
||||
thisAs<ObjList>().quicksort { a, b -> comparator.call(this, a, b).toInt() }
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val comparator = scp.requireOnlyArg<Statement>()
|
||||
scp.thisAs<ObjList>().quicksort { a, b -> comparator.invokeCallable(scp, scp.thisObj, a, b).toInt() }
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "shuffle",
|
||||
doc = "Shuffle elements of this list in-place.",
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjList>().list.shuffle()
|
||||
ObjVoid
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.thisAs<ObjList>().list.shuffle()
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "sum",
|
||||
doc = "Sum elements using dynamic '+' or optimized integer path. Returns null for empty lists.",
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val self = thisAs<ObjList>()
|
||||
val l = self.list
|
||||
if (l.isEmpty()) return@addFnDoc ObjNull
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
// Fast path: all ints → accumulate as long
|
||||
var i = 0
|
||||
var acc: Long = 0
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt) {
|
||||
acc += v.value
|
||||
i++
|
||||
} else {
|
||||
// Fallback to generic dynamic '+' accumulation starting from current acc
|
||||
var res: Obj = ObjInt(acc)
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjList>()
|
||||
val l = self.list
|
||||
if (l.isEmpty()) return ObjNull
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
// Fast path: all ints → accumulate as long
|
||||
var i = 0
|
||||
var acc: Long = 0
|
||||
while (i < l.size) {
|
||||
res = res.plus(this, l[i])
|
||||
i++
|
||||
val v = l[i]
|
||||
if (v is ObjInt) {
|
||||
acc += v.value
|
||||
i++
|
||||
} else {
|
||||
// Fallback to generic dynamic '+' accumulation starting from current acc
|
||||
var res: Obj = ObjInt(acc)
|
||||
while (i < l.size) {
|
||||
res = res.plus(scp, l[i])
|
||||
i++
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
return@addFnDoc res
|
||||
return ObjInt(acc)
|
||||
}
|
||||
// Generic path: dynamic '+' starting from first element
|
||||
var res: Obj = l[0]
|
||||
var k = 1
|
||||
while (k < l.size) {
|
||||
res = res.plus(scp, l[k])
|
||||
k++
|
||||
}
|
||||
return res
|
||||
}
|
||||
return@addFnDoc ObjInt(acc)
|
||||
}
|
||||
// Generic path: dynamic '+' starting from first element
|
||||
var res: Obj = l[0]
|
||||
var k = 1
|
||||
while (k < l.size) {
|
||||
res = res.plus(this, l[k])
|
||||
k++
|
||||
}
|
||||
res
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "min",
|
||||
doc = "Minimum element by natural order. Returns null for empty lists.",
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val l = thisAs<ObjList>().list
|
||||
if (l.isEmpty()) return@addFnDoc ObjNull
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
var i = 0
|
||||
var hasOnlyInts = true
|
||||
var minVal: Long = Long.MAX_VALUE
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt) {
|
||||
if (v.value < minVal) minVal = v.value
|
||||
} else {
|
||||
hasOnlyInts = false
|
||||
break
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val l = scp.thisAs<ObjList>().list
|
||||
if (l.isEmpty()) return ObjNull
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
var i = 0
|
||||
var hasOnlyInts = true
|
||||
var minVal: Long = Long.MAX_VALUE
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt) {
|
||||
if (v.value < minVal) minVal = v.value
|
||||
} else {
|
||||
hasOnlyInts = false
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (hasOnlyInts) return ObjInt(minVal)
|
||||
}
|
||||
i++
|
||||
var res: Obj = l[0]
|
||||
var i = 1
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v.compareTo(scp, res) < 0) res = v
|
||||
i++
|
||||
}
|
||||
return res
|
||||
}
|
||||
if (hasOnlyInts) return@addFnDoc ObjInt(minVal)
|
||||
}
|
||||
var res: Obj = l[0]
|
||||
var i = 1
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v.compareTo(this, res) < 0) res = v
|
||||
i++
|
||||
}
|
||||
res
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "max",
|
||||
doc = "Maximum element by natural order. Returns null for empty lists.",
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val l = thisAs<ObjList>().list
|
||||
if (l.isEmpty()) return@addFnDoc ObjNull
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
var i = 0
|
||||
var hasOnlyInts = true
|
||||
var maxVal: Long = Long.MIN_VALUE
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt) {
|
||||
if (v.value > maxVal) maxVal = v.value
|
||||
} else {
|
||||
hasOnlyInts = false
|
||||
break
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val l = scp.thisAs<ObjList>().list
|
||||
if (l.isEmpty()) return ObjNull
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
var i = 0
|
||||
var hasOnlyInts = true
|
||||
var maxVal: Long = Long.MIN_VALUE
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt) {
|
||||
if (v.value > maxVal) maxVal = v.value
|
||||
} else {
|
||||
hasOnlyInts = false
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (hasOnlyInts) return ObjInt(maxVal)
|
||||
}
|
||||
i++
|
||||
var res: Obj = l[0]
|
||||
var i = 1
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v.compareTo(scp, res) > 0) res = v
|
||||
i++
|
||||
}
|
||||
return res
|
||||
}
|
||||
if (hasOnlyInts) return@addFnDoc ObjInt(maxVal)
|
||||
}
|
||||
var res: Obj = l[0]
|
||||
var i = 1
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v.compareTo(this, res) > 0) res = v
|
||||
i++
|
||||
}
|
||||
res
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "indexOf",
|
||||
doc = "Index of the first occurrence of the given element, or -1 if not found.",
|
||||
params = listOf(ParamDoc("element")),
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val l = thisAs<ObjList>().list
|
||||
val needle = args.firstAndOnly()
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS && needle is ObjInt) {
|
||||
var i = 0
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt && v.value == needle.value) return@addFnDoc ObjInt(i.toLong())
|
||||
i++
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val l = scp.thisAs<ObjList>().list
|
||||
val needle = scp.args.firstAndOnly()
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS && needle is ObjInt) {
|
||||
var i = 0
|
||||
while (i < l.size) {
|
||||
val v = l[i]
|
||||
if (v is ObjInt && v.value == needle.value) return ObjInt(i.toLong())
|
||||
i++
|
||||
}
|
||||
return ObjInt((-1).toLong())
|
||||
}
|
||||
var i = 0
|
||||
while (i < l.size) {
|
||||
if (l[i].compareTo(scp, needle) == 0) return ObjInt(i.toLong())
|
||||
i++
|
||||
}
|
||||
return ObjInt((-1).toLong())
|
||||
}
|
||||
return@addFnDoc ObjInt((-1).toLong())
|
||||
}
|
||||
var i = 0
|
||||
while (i < l.size) {
|
||||
if (l[i].compareTo(this, needle) == 0) return@addFnDoc ObjInt(i.toLong())
|
||||
i++
|
||||
}
|
||||
ObjInt((-1).toLong())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ package net.sergeych.lyng.obj
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
@ -78,21 +79,27 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() {
|
||||
doc = "Key component of this map entry.",
|
||||
type = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjMapEntry>().key }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjMapEntry>().key
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "value",
|
||||
doc = "Value component of this map entry.",
|
||||
type = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjMapEntry>().value }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjMapEntry>().value
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "size",
|
||||
doc = "Number of components in this entry (always 2).",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { 2.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = 2.toObj()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -181,9 +188,11 @@ class ObjMap(val map: MutableMap<Obj, Obj> = mutableMapOf()) : Obj() {
|
||||
}
|
||||
|
||||
override suspend fun toJson(scope: Scope): JsonElement {
|
||||
return JsonObject(
|
||||
map.map { it.key.toString(scope).value to it.value.toJson(scope) }.toMap()
|
||||
)
|
||||
val res = mutableMapOf<String, JsonElement>()
|
||||
for ((k, v) in map) {
|
||||
res[k.toString(scope).value] = v.toJson(scope)
|
||||
}
|
||||
return JsonObject(res)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -224,94 +233,119 @@ class ObjMap(val map: MutableMap<Obj, Obj> = mutableMapOf()) : Obj() {
|
||||
}
|
||||
}.apply {
|
||||
implementingNames.add("Delegate")
|
||||
addFn("getValue") {
|
||||
val self = thisAs<ObjMap>()
|
||||
val key = requiredArg<Obj>(1)
|
||||
self.map[key] ?: ObjNull
|
||||
}
|
||||
addFn("setValue") {
|
||||
val self = thisAs<ObjMap>()
|
||||
val key = requiredArg<Obj>(1)
|
||||
val value = requiredArg<Obj>(2)
|
||||
self.map[key] = value
|
||||
self
|
||||
}
|
||||
addFn("bind") {
|
||||
val mode = requiredArg<ObjEnumEntry>(1)
|
||||
if( mode.ordinal.value > 1)
|
||||
raiseIllegalArgument("Map can be delegated only to val or var, got ${mode.name.value}")
|
||||
thisObj
|
||||
}
|
||||
addFn("getValue", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjMap>()
|
||||
val key = scp.requiredArg<Obj>(1)
|
||||
return self.map[key] ?: ObjNull
|
||||
}
|
||||
})
|
||||
addFn("setValue", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjMap>()
|
||||
val key = scp.requiredArg<Obj>(1)
|
||||
val value = scp.requiredArg<Obj>(2)
|
||||
self.map[key] = value
|
||||
return self
|
||||
}
|
||||
})
|
||||
addFn("bind", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val mode = scp.requiredArg<ObjEnumEntry>(1)
|
||||
if (mode.ordinal.value > 1)
|
||||
scp.raiseIllegalArgument("Map can be delegated only to val or var, got ${mode.name.value}")
|
||||
return scp.thisObj
|
||||
}
|
||||
})
|
||||
addFnDoc(
|
||||
name = "getOrNull",
|
||||
doc = "Get value by key or return null if the key is absent.",
|
||||
params = listOf(ParamDoc("key")),
|
||||
returns = type("lyng.Any", nullable = true),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val key = args.firstAndOnly(pos)
|
||||
thisAs<ObjMap>().map.getOrElse(key) { ObjNull }
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val key = scp.args.firstAndOnly(scp.pos)
|
||||
return scp.thisAs<ObjMap>().map.getOrElse(key) { ObjNull }
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "getOrPut",
|
||||
doc = "Get value by key or compute, store, and return the default from a lambda.",
|
||||
params = listOf(ParamDoc("key"), ParamDoc("default")),
|
||||
returns = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val key = requiredArg<Obj>(0)
|
||||
thisAs<ObjMap>().map.getOrPut(key) {
|
||||
val lambda = requiredArg<Statement>(1)
|
||||
lambda.execute(this)
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val key = scp.requiredArg<Obj>(0)
|
||||
return scp.thisAs<ObjMap>().map.getOrPut(key) {
|
||||
val lambda = scp.requiredArg<Statement>(1)
|
||||
lambda.execute(scp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "size",
|
||||
doc = "Number of entries in the map.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { (this.thisObj as ObjMap).map.size.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = (scp.thisObj as ObjMap).map.size.toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "remove",
|
||||
doc = "Remove the entry by key and return the previous value or null if absent.",
|
||||
params = listOf(ParamDoc("key")),
|
||||
returns = type("lyng.Any", nullable = true),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjMap>().map.remove(requiredArg<Obj>(0))?.toObj() ?: ObjNull
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return scp.thisAs<ObjMap>().map.remove(scp.requiredArg<Obj>(0))?.toObj() ?: ObjNull
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "clear",
|
||||
doc = "Remove all entries from this map. Returns the map.",
|
||||
returns = type("lyng.Map"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjMap>().map.clear()
|
||||
thisObj
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
scp.thisAs<ObjMap>().map.clear()
|
||||
return scp.thisObj
|
||||
}
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "keys",
|
||||
doc = "List of keys in this map.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjMap>().map.keys.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjMap>().map.keys.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "values",
|
||||
doc = "List of values in this map.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { ObjList(thisAs<ObjMap>().map.values.toMutableList()) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjList(scp.thisAs<ObjMap>().map.values.toMutableList())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "iterator",
|
||||
doc = "Iterator over map entries as MapEntry objects.",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.MapEntry"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjKotlinIterator(thisAs<ObjMap>().map.entries.iterator())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjKotlinIterator(scp.thisAs<ObjMap>().map.entries.iterator())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -40,12 +40,12 @@ class ObjMutex(val mutex: Mutex): Obj() {
|
||||
params = listOf(ParamDoc("action")),
|
||||
returns = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val f = requiredArg<Statement>(0)
|
||||
) { scp ->
|
||||
val f = scp.requiredArg<Statement>(0)
|
||||
// Execute user lambda directly in the current scope to preserve the active scope
|
||||
// ancestry across suspension points. The lambda still constructs a ClosureScope
|
||||
// on top of this frame, and parseLambdaExpression sets skipScopeCreation for its body.
|
||||
thisAs<ObjMutex>().mutex.withLock { f.execute(this) }
|
||||
scp.thisAs<ObjMutex>().mutex.withLock { f.execute(scp) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.TypeGenericDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
@ -96,30 +97,6 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
if (other is ObjRange)
|
||||
return containsRange(scope, other)
|
||||
|
||||
if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
if (start is ObjInt && end is ObjInt && other is ObjInt) {
|
||||
val s = start.value
|
||||
val e = end.value
|
||||
val v = other.value
|
||||
if (v < s) return false
|
||||
return if (isEndInclusive) v <= e else v < e
|
||||
}
|
||||
if (start is ObjChar && end is ObjChar && other is ObjChar) {
|
||||
val s = start.value
|
||||
val e = end.value
|
||||
val v = other.value
|
||||
if (v < s) return false
|
||||
return if (isEndInclusive) v <= e else v < e
|
||||
}
|
||||
if (start is ObjString && end is ObjString && other is ObjString) {
|
||||
val s = start.value
|
||||
val e = end.value
|
||||
val v = other.value
|
||||
if (v < s) return false
|
||||
return if (isEndInclusive) v <= e else v < e
|
||||
}
|
||||
}
|
||||
|
||||
if (start == null && end == null) return true
|
||||
if (start != null) {
|
||||
if (start.compareTo(scope, other) > 0) return false
|
||||
@ -139,17 +116,17 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
start is ObjChar && end is ObjChar
|
||||
}
|
||||
|
||||
override suspend fun enumerate(scope: Scope, callback: suspend (Obj) -> Boolean) {
|
||||
override suspend fun enumerate(scope: Scope, callback: EnumerateCallback) {
|
||||
if (start is ObjInt && end is ObjInt) {
|
||||
val s = start.value
|
||||
val e = end.value
|
||||
if (isEndInclusive) {
|
||||
for (i in s..e) {
|
||||
if (!callback(ObjInt.of(i))) break
|
||||
if (!callback.call(ObjInt.of(i))) break
|
||||
}
|
||||
} else {
|
||||
for (i in s..<e) {
|
||||
if (!callback(ObjInt.of(i))) break
|
||||
if (!callback.call(ObjInt.of(i))) break
|
||||
}
|
||||
}
|
||||
} else if (start is ObjChar && end is ObjChar) {
|
||||
@ -157,11 +134,11 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
val e = end.value
|
||||
if (isEndInclusive) {
|
||||
for (c in s..e) {
|
||||
if (!callback(ObjChar(c))) break
|
||||
if (!callback.call(ObjChar(c))) break
|
||||
}
|
||||
} else {
|
||||
for (c in s..<e) {
|
||||
if (!callback(ObjChar(c))) break
|
||||
if (!callback.call(ObjChar(c))) break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -204,64 +181,80 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
doc = "Start bound of the range or null if open.",
|
||||
type = type("lyng.Any", nullable = true),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRange>().start ?: ObjNull }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRange>().start ?: ObjNull
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "end",
|
||||
doc = "End bound of the range or null if open.",
|
||||
type = type("lyng.Any", nullable = true),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRange>().end ?: ObjNull }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRange>().end ?: ObjNull
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isOpen",
|
||||
doc = "Whether the range is open on either side (no start or no end).",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRange>().let { it.start == null || it.end == null }.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRange>().let { it.start == null || it.end == null }.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isIntRange",
|
||||
doc = "True if both bounds are Int values.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRange>().isIntRange.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRange>().isIntRange.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isCharRange",
|
||||
doc = "True if both bounds are Char values.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRange>().isCharRange.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRange>().isCharRange.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "isEndInclusive",
|
||||
doc = "Whether the end bound is inclusive.",
|
||||
type = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRange>().isEndInclusive.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRange>().isEndInclusive.toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "iterator",
|
||||
doc = "Iterator over elements in this range (optimized for Int ranges).",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val self = thisAs<ObjRange>()
|
||||
if (net.sergeych.lyng.PerfFlags.RANGE_FAST_ITER) {
|
||||
val s = self.start
|
||||
val e = self.end
|
||||
if (s is ObjInt && e is ObjInt) {
|
||||
val start = s.value.toInt()
|
||||
val endExclusive = (if (self.isEndInclusive) e.value.toInt() + 1 else e.value.toInt())
|
||||
// Only for ascending simple ranges; fall back otherwise
|
||||
if (start <= endExclusive) {
|
||||
return@addFnDoc ObjFastIntRangeIterator(start, endExclusive)
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjRange>()
|
||||
if (net.sergeych.lyng.PerfFlags.RANGE_FAST_ITER) {
|
||||
val s = self.start
|
||||
val e = self.end
|
||||
if (s is ObjInt && e is ObjInt) {
|
||||
val start = s.value.toInt()
|
||||
val endExclusive = (if (self.isEndInclusive) e.value.toInt() + 1 else e.value.toInt())
|
||||
// Only for ascending simple ranges; fall back otherwise
|
||||
if (start <= endExclusive) {
|
||||
return ObjFastIntRangeIterator(start, endExclusive)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ObjRangeIterator(self).apply { init(scp) }
|
||||
}
|
||||
}
|
||||
ObjRangeIterator(self).apply { init() }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -19,6 +19,7 @@ package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.PerfFlags
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
|
||||
class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
|
||||
@ -28,7 +29,7 @@ class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
|
||||
override val objClass: ObjClass get() = type
|
||||
|
||||
fun Scope.init() {
|
||||
fun init(scope: Scope) {
|
||||
val s = self.start
|
||||
val e = self.end
|
||||
if (s is ObjInt && e is ObjInt) {
|
||||
@ -43,7 +44,7 @@ class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
else
|
||||
(e.value.code - s.value.code)
|
||||
} else {
|
||||
raiseError("not implemented iterator for range of $this")
|
||||
scope.raiseError("not implemented iterator for range of $this")
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +59,7 @@ class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
start.value.code.toLong() + nextIndex++
|
||||
else
|
||||
scope.raiseError("iterator error: unsupported range start")
|
||||
if (isCharRange) ObjChar(x.toInt().toChar()) else ObjInt.of(x)
|
||||
if( isCharRange ) ObjChar(x.toInt().toChar()) else ObjInt(x)
|
||||
}
|
||||
else {
|
||||
scope.raiseError(ObjIterationFinishedException(scope))
|
||||
@ -66,12 +67,14 @@ class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("RangeIterator", ObjIterator).apply {
|
||||
addFn("hasNext") {
|
||||
thisAs<ObjRangeIterator>().hasNext().toObj()
|
||||
}
|
||||
addFn("next") {
|
||||
thisAs<ObjRangeIterator>().next(this)
|
||||
}
|
||||
addFn("hasNext", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.thisAs<ObjRangeIterator>().hasNext().toObj()
|
||||
})
|
||||
addFn("next", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.thisAs<ObjRangeIterator>().next(scp)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,24 +86,23 @@ class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
class ObjFastIntRangeIterator(private val start: Int, private val endExclusive: Int) : Obj() {
|
||||
|
||||
private var cur: Int = start
|
||||
private val cacheLow = ObjInt.CACHE_LOW.toInt()
|
||||
private val useCache = start >= cacheLow && endExclusive <= ObjInt.CACHE_HIGH.toInt() + 1
|
||||
private val cache = if (useCache) ObjInt.cacheArray() else null
|
||||
|
||||
override val objClass: ObjClass get() = type
|
||||
|
||||
fun hasNext(): Boolean = cur < endExclusive
|
||||
|
||||
fun next(scope: Scope): Obj =
|
||||
if (cur < endExclusive) {
|
||||
if (useCache && cache != null) cache[cur++ - cacheLow] else ObjInt(cur++.toLong())
|
||||
}
|
||||
if (cur < endExclusive) ObjInt(cur++.toLong())
|
||||
else scope.raiseError(ObjIterationFinishedException(scope))
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("FastIntRangeIterator", ObjIterator).apply {
|
||||
addFn("hasNext") { thisAs<ObjFastIntRangeIterator>().hasNext().toObj() }
|
||||
addFn("next") { thisAs<ObjFastIntRangeIterator>().next(this) }
|
||||
addFn("hasNext", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjFastIntRangeIterator>().hasNext().toObj()
|
||||
})
|
||||
addFn("next", code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjFastIntRangeIterator>().next(scp)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -21,6 +21,7 @@ import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Pos
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.addConstDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
@ -126,9 +127,9 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
// roundToInt: number rounded to the nearest integer
|
||||
addConstDoc(
|
||||
name = "roundToInt",
|
||||
value = statement(Pos.builtIn) {
|
||||
(it.thisObj as ObjReal).value.roundToLong().toObj()
|
||||
},
|
||||
value = statement(Pos.builtIn, f = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = (scp.thisObj as ObjReal).value.roundToLong().toObj()
|
||||
}),
|
||||
doc = "This real number rounded to the nearest integer.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
@ -137,10 +138,11 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
name = "toInt",
|
||||
doc = "Truncate this real number toward zero to an integer.",
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjInt.of(thisAs<ObjReal>().value.toLong())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt.of(scp.thisAs<ObjReal>().value.toLong())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@ package net.sergeych.lyng.obj
|
||||
import net.sergeych.lyng.PerfFlags
|
||||
import net.sergeych.lyng.RegexCache
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
|
||||
class ObjRegex(val regex: Regex) : Obj() {
|
||||
@ -49,29 +50,36 @@ class ObjRegex(val regex: Regex) : Obj() {
|
||||
doc = "Whether the entire string matches this regular expression.",
|
||||
params = listOf(ParamDoc("text", type("lyng.String"))),
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjBool(args.firstAndOnly().toString().matches(thisAs<ObjRegex>().regex))
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
ObjBool(scp.args.firstAndOnly().toString().matches(scp.thisAs<ObjRegex>().regex))
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "find",
|
||||
doc = "Find the first match in the given string.",
|
||||
params = listOf(ParamDoc("text", type("lyng.String"))),
|
||||
returns = type("lyng.RegexMatch", nullable = true),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjRegex>().find(requireOnlyArg<ObjString>())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
scp.thisAs<ObjRegex>().find(scp.requireOnlyArg<ObjString>())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "findAll",
|
||||
doc = "Find all matches in the given string.",
|
||||
params = listOf(ParamDoc("text", type("lyng.String"))),
|
||||
returns = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.RegexMatch"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val s = requireOnlyArg<ObjString>().value
|
||||
ObjList(thisAs<ObjRegex>().regex.findAll(s).map { ObjRegexMatch(it) }.toMutableList())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val s = scp.requireOnlyArg<ObjString>().value
|
||||
return ObjList(scp.thisAs<ObjRegex>().regex.findAll(s).map { ObjRegexMatch(it) }.toMutableList())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,21 +133,27 @@ class ObjRegexMatch(val match: MatchResult) : Obj() {
|
||||
doc = "List of captured groups with index 0 as the whole match.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.String"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRegexMatch>().objGroups }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRegexMatch>().objGroups
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "value",
|
||||
doc = "The matched substring.",
|
||||
type = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRegexMatch>().objValue }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRegexMatch>().objValue
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "range",
|
||||
doc = "Range of the match in the input (end-exclusive).",
|
||||
type = type("lyng.Range"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRegexMatch>().objRange }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRegexMatch>().objRange
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
|
||||
class RingBuffer<T>(val maxSize: Int) : Iterable<T> {
|
||||
@ -96,39 +97,55 @@ class ObjRingBuffer(val capacity: Int) : Obj() {
|
||||
doc = "Maximum number of elements the buffer can hold.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRingBuffer>().capacity.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRingBuffer>().capacity.toObj()
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "size",
|
||||
doc = "Current number of elements in the buffer.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { thisAs<ObjRingBuffer>().buffer.size.toObj() }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjRingBuffer>().buffer.size.toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "iterator",
|
||||
doc = "Iterator over elements in insertion order (oldest to newest).",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val buffer = thisAs<ObjRingBuffer>().buffer
|
||||
ObjKotlinObjIterator(buffer.iterator())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val buffer = scp.thisAs<ObjRingBuffer>().buffer
|
||||
return ObjKotlinObjIterator(buffer.iterator())
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "add",
|
||||
doc = "Append an element; if full, the oldest element is dropped.",
|
||||
params = listOf(ParamDoc("value", type("lyng.Any"))),
|
||||
returns = type("lyng.Void"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { thisAs<ObjRingBuffer>().apply { buffer.add(requireOnlyArg<Obj>()) } }
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val self = scp.thisAs<ObjRingBuffer>()
|
||||
self.buffer.add(scp.requireOnlyArg<Obj>())
|
||||
return ObjVoid
|
||||
}
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "first",
|
||||
doc = "Return the oldest element in the buffer.",
|
||||
type = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
val buffer = (this.thisObj as ObjRingBuffer).buffer
|
||||
if (buffer.size == 0) ObjNull else buffer.first()
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val buffer = (scp.thisObj as ObjRingBuffer).buffer
|
||||
return if (buffer.size == 0) ObjNull else buffer.iterator().next()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.ParamDoc
|
||||
import net.sergeych.lyng.miniast.TypeGenericDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
@ -46,9 +47,9 @@ class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
|
||||
return set.contains(other)
|
||||
}
|
||||
|
||||
override suspend fun enumerate(scope: Scope, callback: suspend (Obj) -> Boolean) {
|
||||
override suspend fun enumerate(scope: Scope, callback: EnumerateCallback) {
|
||||
for (item in set) {
|
||||
if (!callback(item)) break
|
||||
if (!callback.call(item)) break
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,56 +165,64 @@ class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
|
||||
name = "size",
|
||||
doc = "Number of elements in this set.",
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjSet>().set.size.toObj()
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjSet>().set.size.toObj()
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "intersect",
|
||||
doc = "Intersection with another set. Returns a new set.",
|
||||
params = listOf(ParamDoc("other", type("lyng.Set"))),
|
||||
returns = type("lyng.Set"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjSet>().mul(this, args.firstAndOnly())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjSet>().mul(scp, scp.args.firstAndOnly())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "iterator",
|
||||
doc = "Iterator over elements of this set.",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Any"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjSet>().set.iterator().toObj()
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjKotlinIterator(scp.thisAs<ObjSet>().set.iterator())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "union",
|
||||
doc = "Union with another set or iterable. Returns a new set.",
|
||||
params = listOf(ParamDoc("other")),
|
||||
returns = type("lyng.Set"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjSet>().plus(this, args.firstAndOnly())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjSet>().plus(scp, scp.args.firstAndOnly())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "subtract",
|
||||
doc = "Subtract another set or iterable from this set. Returns a new set.",
|
||||
params = listOf(ParamDoc("other")),
|
||||
returns = type("lyng.Set"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjSet>().minus(this, args.firstAndOnly())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = scp.thisAs<ObjSet>().minus(scp, scp.args.firstAndOnly())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "remove",
|
||||
doc = "Remove one or more elements. Returns true if the set changed.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val set = thisAs<ObjSet>().set
|
||||
val n = set.size
|
||||
for( x in args.list ) set -= x
|
||||
if( n == set.size ) ObjFalse else ObjTrue
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val set = scp.thisAs<ObjSet>().set
|
||||
val n = set.size
|
||||
for( x in scp.args.list ) set -= x
|
||||
return if( n == set.size ) ObjFalse else ObjTrue
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@ import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.PerfFlags
|
||||
import net.sergeych.lyng.RegexCache
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.ScopeCallable
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
@ -139,205 +140,274 @@ data class ObjString(val value: String) : Obj() {
|
||||
name = "iterator",
|
||||
doc = "Iterator over characters of this string.",
|
||||
returns = TypeGenericDoc(type("lyng.Iterator"), listOf(type("lyng.Char"))),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { ObjKotlinIterator(thisAs<ObjString>().value.iterator()) }
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjKotlinIterator(scp.thisAs<ObjString>().value.iterator())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "toInt",
|
||||
doc = "Parse this string as an integer or throw if it is not a valid integer.",
|
||||
returns = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjInt.of(
|
||||
thisAs<ObjString>().value.toLongOrNull()
|
||||
?: raiseIllegalArgument("can't convert to int: $thisObj")
|
||||
)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjInt.of(
|
||||
scp.thisAs<ObjString>().value.toLongOrNull()
|
||||
?: scp.raiseIllegalArgument("can't convert to int: ${scp.thisObj}")
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "startsWith",
|
||||
doc = "Whether this string starts with the given prefix.",
|
||||
params = listOf(ParamDoc("prefix", type("lyng.String"))),
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjBool(thisAs<ObjString>().value.startsWith(requiredArg<ObjString>(0).value))
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjBool(scp.thisAs<ObjString>().value.startsWith(scp.requiredArg<ObjString>(0).value))
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "endsWith",
|
||||
doc = "Whether this string ends with the given suffix.",
|
||||
params = listOf(ParamDoc("suffix", type("lyng.String"))),
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjBool(thisAs<ObjString>().value.endsWith(requiredArg<ObjString>(0).value))
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjBool(scp.thisAs<ObjString>().value.endsWith(scp.requiredArg<ObjString>(0).value))
|
||||
}
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "length",
|
||||
doc = "Number of UTF-16 code units in this string.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { ObjInt.of((this.thisObj as ObjString).value.length.toLong()) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt.of((scp.thisObj as ObjString).value.length.toLong())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "takeLast",
|
||||
doc = "Return a string with the last N characters.",
|
||||
params = listOf(ParamDoc("n", type("lyng.Int"))),
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.takeLast(
|
||||
requiredArg<ObjInt>(0).toInt()
|
||||
).let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjString(
|
||||
scp.thisAs<ObjString>().value.takeLast(
|
||||
scp.requiredArg<ObjInt>(0).toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "take",
|
||||
doc = "Return a string with the first N characters.",
|
||||
params = listOf(ParamDoc("n", type("lyng.Int"))),
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.take(
|
||||
requiredArg<ObjInt>(0).toInt()
|
||||
).let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjString(
|
||||
scp.thisAs<ObjString>().value.take(
|
||||
scp.requiredArg<ObjInt>(0).toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "drop",
|
||||
doc = "Drop the first N characters and return the remainder.",
|
||||
params = listOf(ParamDoc("n", type("lyng.Int"))),
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.drop(
|
||||
requiredArg<ObjInt>(0).toInt()
|
||||
).let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjString(
|
||||
scp.thisAs<ObjString>().value.drop(
|
||||
scp.requiredArg<ObjInt>(0).toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "dropLast",
|
||||
doc = "Drop the last N characters and return the remainder.",
|
||||
params = listOf(ParamDoc("n", type("lyng.Int"))),
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.dropLast(
|
||||
requiredArg<ObjInt>(0).toInt()
|
||||
).let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjString(
|
||||
scp.thisAs<ObjString>().value.dropLast(
|
||||
scp.requiredArg<ObjInt>(0).toInt()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "lower",
|
||||
doc = "Lowercase version of this string (default locale).",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.lowercase().let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjString(scp.thisAs<ObjString>().value.lowercase())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "lowercase",
|
||||
doc = "Lowercase version of this string (default locale).",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.lowercase().let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjString(scp.thisAs<ObjString>().value.lowercase())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "upper",
|
||||
doc = "Uppercase version of this string (default locale).",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.uppercase().let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjString(scp.thisAs<ObjString>().value.uppercase())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "uppercase",
|
||||
doc = "Uppercase version of this string (default locale).",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.uppercase().let(::ObjString)
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjString(scp.thisAs<ObjString>().value.uppercase())
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "characters",
|
||||
doc = "List of characters of this string.",
|
||||
type = TypeGenericDoc(type("lyng.List"), listOf(type("lyng.Char"))),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = {
|
||||
ObjList(
|
||||
(this.thisObj as ObjString).value.map { ObjChar(it) }.toMutableList()
|
||||
)
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjList(
|
||||
(scp.thisObj as ObjString).value.map { ObjChar(it) }.toMutableList()
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "last",
|
||||
doc = "The last character of this string or throw if the string is empty.",
|
||||
returns = type("lyng.Char"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjChar(thisAs<ObjString>().value.lastOrNull() ?: raiseNoSuchElement("empty string"))
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
return ObjChar(scp.thisAs<ObjString>().value.lastOrNull() ?: scp.raiseNoSuchElement("empty string"))
|
||||
}
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "encodeUtf8",
|
||||
doc = "Encode this string as UTF-8 bytes.",
|
||||
returns = type("lyng.Buffer"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) { ObjBuffer(thisAs<ObjString>().value.encodeToByteArray().asUByteArray()) }
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj =
|
||||
ObjBuffer(scp.thisAs<ObjString>().value.encodeToByteArray().asUByteArray())
|
||||
}
|
||||
)
|
||||
addPropertyDoc(
|
||||
name = "size",
|
||||
doc = "Alias for length: the number of characters (code units) in this string.",
|
||||
type = type("lyng.Int"),
|
||||
moduleName = "lyng.stdlib",
|
||||
getter = { ObjInt.of((this.thisObj as ObjString).value.length.toLong()) }
|
||||
getter = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjInt.of((scp.thisObj as ObjString).value.length.toLong())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "toReal",
|
||||
doc = "Parse this string as a real number (floating point).",
|
||||
returns = type("lyng.Real"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
ObjReal.of(thisAs<ObjString>().value.toDouble())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjReal.of(scp.thisAs<ObjString>().value.toDouble())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "trim",
|
||||
doc = "Return a copy of this string with leading and trailing whitespace removed.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjString>().value.trim().let(::ObjString)
|
||||
}
|
||||
addFnDoc("isBlank", "Whether this string is empty or contains only whitespace characters.",
|
||||
returns = type("lyng.Bool"), moduleName = "lyng.stdlib") {
|
||||
ObjBool(thisAs<ObjString>().value.isBlank())
|
||||
}
|
||||
addFnDoc("isEmpty", "Whether this string is empty.",
|
||||
returns = type("lyng.Bool"), moduleName = "lyng.stdlib") {
|
||||
ObjBool(thisAs<ObjString>().value.isEmpty())
|
||||
}
|
||||
addFnDoc("isNotEmpty", "Whether this string is not empty.",
|
||||
returns = type("lyng.Bool"), moduleName = "lyng.stdlib") {
|
||||
ObjBool(thisAs<ObjString>().value.isNotEmpty())
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjString(scp.thisAs<ObjString>().value.trim())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "isBlank",
|
||||
doc = "Whether this string is empty or contains only whitespace characters.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjBool(scp.thisAs<ObjString>().value.isBlank())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "isEmpty",
|
||||
doc = "Whether this string is empty.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjBool(scp.thisAs<ObjString>().value.isEmpty())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "isNotEmpty",
|
||||
doc = "Whether this string is not empty.",
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj = ObjBool(scp.thisAs<ObjString>().value.isNotEmpty())
|
||||
}
|
||||
)
|
||||
addFnDoc(
|
||||
name = "matches",
|
||||
doc = "Whether this string matches the given regular expression or pattern string.",
|
||||
params = listOf(ParamDoc("pattern")),
|
||||
returns = type("lyng.Bool"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
val s = requireOnlyArg<Obj>()
|
||||
val self = thisAs<ObjString>().value
|
||||
ObjBool(
|
||||
when (s) {
|
||||
is ObjRegex -> self.matches(s.regex)
|
||||
is ObjString -> {
|
||||
if (s.value == ".*") true
|
||||
else {
|
||||
val re = if (PerfFlags.REGEX_CACHE) RegexCache.get(s.value) else s.value.toRegex()
|
||||
self.matches(re)
|
||||
}
|
||||
}
|
||||
moduleName = "lyng.stdlib",
|
||||
code = object : ScopeCallable {
|
||||
override suspend fun call(scp: Scope): Obj {
|
||||
val s = scp.requireOnlyArg<Obj>()
|
||||
val self = scp.thisAs<ObjString>().value
|
||||
return ObjBool(
|
||||
when (s) {
|
||||
is ObjRegex -> self.matches(s.regex)
|
||||
is ObjString -> {
|
||||
if (s.value == ".*") true
|
||||
else {
|
||||
val re = if (PerfFlags.REGEX_CACHE) RegexCache.get(s.value) else s.value.toRegex()
|
||||
self.matches(re)
|
||||
}
|
||||
}
|
||||
|
||||
else ->
|
||||
raiseIllegalArgument("can't match ${s.objClass.className}: required Regex or String")
|
||||
else ->
|
||||
scp.raiseIllegalArgument("can't match ${s.objClass.className}: required Regex or String")
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -21,6 +21,10 @@ import net.sergeych.lyng.*
|
||||
import net.sergeych.synctools.ProtectedOp
|
||||
import net.sergeych.synctools.withLock
|
||||
|
||||
interface ModuleBuilder {
|
||||
suspend fun build(scope: ModuleScope)
|
||||
}
|
||||
|
||||
/**
|
||||
* Import manager allow to register packages with builder lambdas and act as an
|
||||
* [ImportProvider]. Note that packages _must be registered_ first with [addPackage],
|
||||
@ -40,16 +44,16 @@ class ImportManager(
|
||||
|
||||
private inner class Entry(
|
||||
val packageName: String,
|
||||
val builder: suspend (ModuleScope) -> Unit,
|
||||
val builder: ModuleBuilder,
|
||||
var cachedScope: ModuleScope? = null
|
||||
) {
|
||||
|
||||
suspend fun getScope(pos: Pos): ModuleScope {
|
||||
cachedScope?.let { return it }
|
||||
return ModuleScope(inner, pos, packageName).apply {
|
||||
cachedScope = this
|
||||
builder(this)
|
||||
}
|
||||
val ms = ModuleScope(inner, pos, packageName)
|
||||
cachedScope = ms
|
||||
builder.build(ms)
|
||||
return ms
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +94,7 @@ class ImportManager(
|
||||
* @param name package name
|
||||
* @param builder lambda to create actual package using the given [ModuleScope]
|
||||
*/
|
||||
fun addPackage(name: String, builder: suspend (ModuleScope) -> Unit) {
|
||||
fun addPackage(name: String, builder: ModuleBuilder) {
|
||||
op.withLock {
|
||||
if (name in imports)
|
||||
throw IllegalArgumentException("Package $name already exists")
|
||||
@ -102,7 +106,7 @@ class ImportManager(
|
||||
* Bulk [addPackage] with slightly better performance
|
||||
*/
|
||||
@Suppress("unused")
|
||||
fun addPackages(registrationData: List<Pair<String, suspend (ModuleScope) -> Unit>>) {
|
||||
fun addPackages(registrationData: List<Pair<String, ModuleBuilder>>) {
|
||||
op.withLock {
|
||||
for (pp in registrationData) {
|
||||
if (pp.first in imports)
|
||||
@ -129,9 +133,11 @@ class ImportManager(
|
||||
*/
|
||||
fun addSourcePackages(vararg sources: Source) {
|
||||
for (s in sources) {
|
||||
addPackage(s.extractPackageName()) {
|
||||
it.eval(s)
|
||||
}
|
||||
addPackage(s.extractPackageName(), object : ModuleBuilder {
|
||||
override suspend fun build(scope: ModuleScope) {
|
||||
scope.eval(s)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@ -144,7 +150,11 @@ class ImportManager(
|
||||
var source = Source("tmp", s)
|
||||
val packageName = source.extractPackageName()
|
||||
source = Source(packageName, s)
|
||||
addPackage(packageName) { it.eval(source) }
|
||||
addPackage(packageName, object : ModuleBuilder {
|
||||
override suspend fun build(scope: ModuleScope) {
|
||||
scope.eval(source)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -63,13 +63,6 @@ abstract class Statement(
|
||||
|
||||
}
|
||||
|
||||
class ExpressionStatement(
|
||||
val ref: net.sergeych.lyng.obj.ObjRef,
|
||||
override val pos: Pos
|
||||
) : Statement() {
|
||||
override suspend fun execute(scope: Scope): Obj = ref.evalValue(scope)
|
||||
}
|
||||
|
||||
fun Statement.raise(text: String): Nothing {
|
||||
throw ScriptError(pos, text)
|
||||
}
|
||||
@ -79,16 +72,16 @@ fun Statement.require(cond: Boolean, message: () -> String) {
|
||||
if (!cond) raise(message())
|
||||
}
|
||||
|
||||
fun statement(pos: Pos, isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend (Scope) -> Obj): Statement =
|
||||
fun statement(pos: Pos, isStaticConst: Boolean = false, isConst: Boolean = false, f: ScopeCallable): Statement =
|
||||
object : Statement(isStaticConst, isConst) {
|
||||
override val pos: Pos = pos
|
||||
override suspend fun execute(scope: Scope): Obj = f(scope)
|
||||
override suspend fun execute(scope: Scope): Obj = f.call(scope)
|
||||
}
|
||||
|
||||
fun statement(isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend Scope.() -> Obj): Statement =
|
||||
fun statement(isStaticConst: Boolean = false, isConst: Boolean = false, f: ScopeCallable): Statement =
|
||||
object : Statement(isStaticConst, isConst) {
|
||||
override val pos: Pos = Pos.builtIn
|
||||
override suspend fun execute(scope: Scope): Obj = f(scope)
|
||||
override suspend fun execute(scope: Scope): Obj = f.call(scope)
|
||||
}
|
||||
|
||||
object NopStatement: Statement(true, true, ObjType.Void) {
|
||||
|
||||
@ -41,11 +41,11 @@ object ObjLynonClass : ObjClass("Lynon") {
|
||||
|
||||
init {
|
||||
addClassConst("test", ObjString("test_const"))
|
||||
addClassFn("encode") {
|
||||
encodeAny(this, requireOnlyArg<Obj>())
|
||||
addClassFn("encode") { scp ->
|
||||
encodeAny(scp, scp.requireOnlyArg<Obj>())
|
||||
}
|
||||
addClassFn("decode") {
|
||||
decodeAny(this, requireOnlyArg<Obj>())
|
||||
addClassFn("decode") { scp ->
|
||||
decodeAny(scp, scp.requireOnlyArg<Obj>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ class BindingHighlightTest {
|
||||
// Find the specific usage inside string-literal invocation: "%s is directory"(name)
|
||||
val pattern = "\"%s is directory\"(name)"
|
||||
val lineIdx = text.indexOf(pattern)
|
||||
assertTrue(lineIdx >= 0, "Pattern with string invoke should be present in the snippet")
|
||||
assertTrue(lineIdx >= 0, "Pattern with string invokeCallable should be present in the snippet")
|
||||
val nameStart = lineIdx + pattern.indexOf("name")
|
||||
val nameEnd = nameStart + "name".length
|
||||
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.lyng.Benchmarks
|
||||
import net.sergeych.lyng.eval
|
||||
import net.sergeych.lyng.obj.ObjInt
|
||||
import kotlin.time.TimeSource
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class NestedRangeBenchmarkTest {
|
||||
@Test
|
||||
fun benchmarkHappyNumbersNestedRanges() = runTest {
|
||||
if (!Benchmarks.enabled) return@runTest
|
||||
val script = """
|
||||
fun naiveCountHappyNumbers() {
|
||||
var count = 0
|
||||
for( n1 in 0..9 )
|
||||
for( n2 in 0..9 )
|
||||
for( n3 in 0..9 )
|
||||
for( n4 in 0..9 )
|
||||
for( n5 in 0..9 )
|
||||
for( n6 in 0..9 )
|
||||
if( n1 + n2 + n3 == n4 + n5 + n6 ) count++
|
||||
count
|
||||
}
|
||||
naiveCountHappyNumbers()
|
||||
""".trimIndent()
|
||||
|
||||
val start = TimeSource.Monotonic.markNow()
|
||||
val result = eval(script) as ObjInt
|
||||
val elapsedMs = start.elapsedNow().inWholeMilliseconds
|
||||
println("[DEBUG_LOG] [BENCH] nested-happy elapsed=${elapsedMs} ms")
|
||||
assertEquals(55252L, result.value)
|
||||
}
|
||||
}
|
||||
@ -865,8 +865,8 @@ class OOTest {
|
||||
callBar
|
||||
""".trimIndent()) as Statement
|
||||
val s2 = Script.newScope()
|
||||
assertEquals(44L, fn.invoke(scope, fn).toKotlin(s2))
|
||||
assertEquals(45L, fn.invoke(s2, fn).toKotlin(s2))
|
||||
assertEquals(44L, fn.invokeCallable(scope, fn).toKotlin(s2))
|
||||
assertEquals(45L, fn.invokeCallable(s2, fn).toKotlin(s2))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -911,19 +911,4 @@ class OOTest {
|
||||
assertEquals("{\"a\":\"foo\",\"b\":\"bar\"}",T("foo", "bar").toJsonString())
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAssignToUnqualifiedParams() = runTest {
|
||||
eval("""
|
||||
class T(x) {
|
||||
fun setx(v) { x = v }
|
||||
fun incr(v) { x += v }
|
||||
}
|
||||
val t = T(1)
|
||||
t.setx(2)
|
||||
assertEquals(2, t.x)
|
||||
t.incr(3)
|
||||
assertEquals(5, t.x)
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@ -138,10 +138,10 @@ class ScriptTest {
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("TestIterable", ObjIterable).apply {
|
||||
addFn("iterator") {
|
||||
ObjTestIterator(thisAs<ObjTestIterable>())
|
||||
addFn("iterator") { scp ->
|
||||
ObjTestIterator(scp.thisAs<ObjTestIterable>())
|
||||
}
|
||||
addFn("cancelCount") { thisAs<ObjTestIterable>().cancelCount.toObj() }
|
||||
addFn("cancelCount") { scp -> scp.thisAs<ObjTestIterable>().cancelCount.toObj() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,10 +158,10 @@ class ScriptTest {
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("TestIterator", ObjIterator).apply {
|
||||
addFn("hasNext") { thisAs<ObjTestIterator>().hasNext().toObj() }
|
||||
addFn("next") { thisAs<ObjTestIterator>().next() }
|
||||
addFn("cancelIteration") {
|
||||
thisAs<ObjTestIterator>().cancelIteration()
|
||||
addFn("hasNext") { scp -> scp.thisAs<ObjTestIterator>().hasNext().toObj() }
|
||||
addFn("next") { scp -> scp.thisAs<ObjTestIterator>().next() }
|
||||
addFn("cancelIteration") { scp ->
|
||||
scp.thisAs<ObjTestIterator>().cancelIteration()
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
@ -2229,8 +2229,8 @@ class ScriptTest {
|
||||
@Test
|
||||
fun testThrowFromKotlin() = runTest {
|
||||
val c = Script.newScope()
|
||||
c.addFn("callThrow") {
|
||||
raiseIllegalArgument("fromKotlin")
|
||||
c.addFn("callThrow") { scp ->
|
||||
scp.raiseIllegalArgument("fromKotlin")
|
||||
}
|
||||
c.eval(
|
||||
"""
|
||||
@ -2738,8 +2738,8 @@ class ScriptTest {
|
||||
companion object {
|
||||
|
||||
val klass = ObjClass("TestFoo").apply {
|
||||
addFn("test") {
|
||||
thisAs<ObjTestFoo>().value
|
||||
addFn("test") { scp ->
|
||||
scp.thisAs<ObjTestFoo>().value
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4480,7 +4480,7 @@ class ScriptTest {
|
||||
val dummyThis = Obj()
|
||||
// but we should be able to call it directly
|
||||
val otherScope = baseScope.createChildScope()
|
||||
val r = (exports["exportedFunction".toObj()] as Statement).invoke(otherScope, dummyThis, ObjInt(50))
|
||||
val r = (exports["exportedFunction".toObj()] as Statement).invokeCallable(otherScope, dummyThis, ObjInt(50))
|
||||
println(r)
|
||||
assertEquals(51, r.toInt())
|
||||
}
|
||||
@ -5035,13 +5035,5 @@ class ScriptTest {
|
||||
assertEquals(10.0, 15.5.clamp(0.0..10.0))
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEmptySpreadList() = runTest {
|
||||
eval("""
|
||||
fun t(a, tags=[]) { [a, ...tags] }
|
||||
assertEquals( [1], t(1) )
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,99 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.lyng.eval
|
||||
import kotlin.test.Test
|
||||
|
||||
class ValReassignRegressionTest {
|
||||
|
||||
@Test
|
||||
fun reassign_ctor_param_field_should_work() = runTest {
|
||||
eval(
|
||||
"""
|
||||
class Wallet(balance = 0) {
|
||||
fun add(amount) {
|
||||
balance += amount
|
||||
}
|
||||
fun transfer(amount) {
|
||||
val balance = 0
|
||||
add(amount)
|
||||
}
|
||||
fun get() { balance }
|
||||
}
|
||||
val w = Wallet()
|
||||
w.transfer(1)
|
||||
assertEquals(1, w.get())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reassign_field_should_not_see_caller_locals() = runTest {
|
||||
eval(
|
||||
"""
|
||||
class Wallet(balance = 0) {
|
||||
fun add(amount) { balance += amount }
|
||||
fun get() { balance }
|
||||
}
|
||||
fun doTransfer(w, amount) {
|
||||
val balance = 0
|
||||
w.add(amount)
|
||||
}
|
||||
val w = Wallet()
|
||||
doTransfer(w, 2)
|
||||
assertEquals(2, w.get())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reassign_field_should_not_see_caller_param() = runTest {
|
||||
eval(
|
||||
"""
|
||||
class Wallet(balance = 0) {
|
||||
fun add(amount) { balance += amount }
|
||||
fun get() { balance }
|
||||
}
|
||||
fun doTransfer(balance, w, amount) {
|
||||
w.add(amount)
|
||||
}
|
||||
val w = Wallet()
|
||||
doTransfer(0, w, 3)
|
||||
assertEquals(3, w.get())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reassign_field_should_not_see_block_local() = runTest {
|
||||
eval(
|
||||
"""
|
||||
class Wallet(balance = 0) {
|
||||
fun add(amount) { balance += amount }
|
||||
fun get() { balance }
|
||||
}
|
||||
val w = Wallet()
|
||||
run {
|
||||
val balance = 0
|
||||
w.add(4)
|
||||
}
|
||||
assertEquals(4, w.get())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -90,7 +90,7 @@ class DelegationTest {
|
||||
fun testFunDelegation() = runTest {
|
||||
eval("""
|
||||
class ActionDelegate() {
|
||||
fun invoke(thisRef, name, args...) {
|
||||
fun invokeCallable(thisRef, name, args...) {
|
||||
"Called %s with %d args: %s"(name, args.size, args.joinToString(","))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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
|
||||
|
||||
actual object Benchmarks {
|
||||
actual val enabled: Boolean = false
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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
|
||||
|
||||
actual object Benchmarks {
|
||||
actual val enabled: Boolean = run {
|
||||
val p = System.getProperty("LYNG_BENCHMARKS")?.lowercase()
|
||||
val e = System.getenv("BENCHMARKS")?.lowercase()
|
||||
fun parse(v: String?): Boolean =
|
||||
v == "true" || v == "1" || v == "yes"
|
||||
parse(p) || parse(e)
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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
|
||||
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.cinterop.toKString
|
||||
import platform.posix.getenv
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
actual object Benchmarks {
|
||||
actual val enabled: Boolean = run {
|
||||
fun parse(v: String?): Boolean =
|
||||
v == "true" || v == "1" || v == "yes"
|
||||
val b = getenv("BENCHMARKS")?.toKString()?.lowercase()
|
||||
val l = getenv("LYNG_BENCHMARKS")?.toKString()?.lowercase()
|
||||
parse(b) || parse(l)
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* 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
|
||||
|
||||
actual object Benchmarks {
|
||||
actual val enabled: Boolean = false
|
||||
}
|
||||
@ -18,15 +18,15 @@
|
||||
package net.sergeych.lyng
|
||||
|
||||
actual object PerfDefaults {
|
||||
actual val LOCAL_SLOT_PIC: Boolean = true
|
||||
actual val EMIT_FAST_LOCAL_REFS: Boolean = true
|
||||
actual val LOCAL_SLOT_PIC: Boolean = false
|
||||
actual val EMIT_FAST_LOCAL_REFS: Boolean = false
|
||||
|
||||
actual val ARG_BUILDER: Boolean = true
|
||||
actual val SKIP_ARGS_ON_NULL_RECEIVER: Boolean = true
|
||||
actual val SCOPE_POOL: Boolean = true
|
||||
actual val ARG_BUILDER: Boolean = false
|
||||
actual val SKIP_ARGS_ON_NULL_RECEIVER: Boolean = false
|
||||
actual val SCOPE_POOL: Boolean = false
|
||||
|
||||
actual val FIELD_PIC: Boolean = true
|
||||
actual val METHOD_PIC: Boolean = true
|
||||
actual val FIELD_PIC: Boolean = false
|
||||
actual val METHOD_PIC: Boolean = false
|
||||
actual val FIELD_PIC_SIZE_4: Boolean = false
|
||||
actual val METHOD_PIC_SIZE_4: Boolean = false
|
||||
actual val PIC_ADAPTIVE_2_TO_4: Boolean = false
|
||||
|
||||
@ -1,156 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3044:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3076:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3317:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3713:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3724:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3783:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3894:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3950:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:358:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:377:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 261.854157 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 143.359303 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 198.727671 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 165.057842 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1212.62923 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1221.344844 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 911.390453 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 864.74467 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1258.596122 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1215.214754 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 813.8911 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 840.201914 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 721.329794 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 664.626564 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=246.670 ms, ON=247.664 ms, speedup=1.00x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 358.568027 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 357.649314 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 210.029012 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 197.480796 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 189.724828 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 171.944462 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 155.800531 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 159.326021 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 493.764263 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 473.911057 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 414.496391 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 379.154141 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 395.901223 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 361.008923 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 614.851677 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 606.423947 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 322.701469 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 332.466691 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 125.613919 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 127.188579 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 271.994907 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 269.043016 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1224.41111 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 1159.586817 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 494.4744 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 420.160566 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 632.699991 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 558.980979 ms
|
||||
|
||||
BUILD SUCCESSFUL in 32s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,157 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Arguments.kt:171:13 Check for instance is always 'true'.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3044:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3076:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3317:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3713:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3724:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3783:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3894:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3950:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 262.456983 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 143.016118 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 204.504575 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 169.943911 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1249.839264 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1222.298584 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 901.399509 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 862.404202 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1288.885586 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1240.515769 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 818.753611 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 846.609202 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 673.750784 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 656.929851 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=277.571 ms, ON=278.333 ms, speedup=1.00x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 352.770834 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 350.420946 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 203.043167 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 191.784157 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 190.975557 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 173.62457 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 162.948512 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 161.115548 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 481.70436 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 457.081838 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 416.136033 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 377.996669 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 415.789128 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 369.789878 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 615.689206 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 604.213533 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 330.268329 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 331.937563 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 130.221941 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 129.656747 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 280.648819 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 276.585595 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1244.04352 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 1181.395693 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 455.504952 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 388.443547 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 628.199793 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 574.342775 ms
|
||||
|
||||
BUILD SUCCESSFUL in 32s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,156 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3044:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3076:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3317:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3713:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3724:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3783:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3894:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3950:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 261.781459 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 145.930937 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 198.865061 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 166.602828 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1247.05106 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1281.54336 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 883.211818 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 865.689378 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1233.018601 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1481.964038 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 888.881526 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 849.302933 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 665.365 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 663.883057 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=247.421 ms, ON=260.564 ms, speedup=0.95x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 353.794891 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 353.008114 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 202.620604 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 188.753098 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 187.350501 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 172.926716 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 159.856375 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 173.291963 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 484.924666 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 470.462696 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 418.550739 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 377.176886 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 398.385204 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 361.726326 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 606.153624 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 602.269093 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 327.139818 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 326.264549 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 127.960191 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 133.286108 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 289.541793 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 272.736055 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1238.097545 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 1189.624292 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 447.781066 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 373.556778 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 574.938314 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 537.896984 ms
|
||||
|
||||
BUILD SUCCESSFUL in 32s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,156 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3044:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3076:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3320:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3716:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3727:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3786:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3897:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3953:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 253.651654 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 146.390764 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 197.226054 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 168.955589 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1256.240598 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1270.063908 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 896.05655 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 908.729676 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1275.701226 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1262.923161 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 904.80078 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 843.661706 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 693.294337 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 655.907501 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=246.831 ms, ON=249.673 ms, speedup=0.99x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 363.565902 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 357.239034 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 205.439227 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 192.811329 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 190.153039 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 171.03625 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 171.823152 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 172.076498 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 470.255577 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 452.226068 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 425.250966 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 372.065608 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 425.557633 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 398.662616 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 670.172011 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 654.491316 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 368.642342 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 371.610689 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 132.834786 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 128.264586 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 271.281035 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 265.903301 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1239.838114 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 1170.640179 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 440.47053 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 372.095174 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 611.454512 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 553.868896 ms
|
||||
|
||||
BUILD SUCCESSFUL in 32s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,156 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3096:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3128:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3161:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3372:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3768:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3779:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3838:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3949:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:4005:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 268.708055 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 146.48493 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 200.079276 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 163.315912 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1553.293592 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1473.171537 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 1069.276106 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 938.902009 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1272.837347 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1232.000995 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 821.533602 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 845.562175 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 713.778041 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 658.92245 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=258.841 ms, ON=260.836 ms, speedup=0.99x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 359.929596 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 355.440048 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 201.239366 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 193.027976 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 193.231822 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 169.126707 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 152.807956 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 155.12379 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 487.13174 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 458.34973 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 420.451323 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 380.196618 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 407.040834 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 376.63534 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 651.947325 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 665.276754 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 343.185945 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 333.229274 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 128.027033 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 128.223778 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 272.765371 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 267.282587 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1222.526972 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 1156.325094 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 454.25713 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 435.042988 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 646.493027 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 581.51493 ms
|
||||
|
||||
BUILD SUCCESSFUL in 33s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,157 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3044:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3076:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3317:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3713:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3724:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3783:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3894:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3950:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt:169:37 Redundant call of conversion method.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 261.750618 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 146.453823 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 195.212879 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 162.023578 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1500.893007 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1470.571042 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 1069.296265 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 979.876815 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1282.033869 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1219.102212 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 817.077586 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 836.022994 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 694.858051 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 657.045255 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=257.782 ms, ON=248.041 ms, speedup=1.04x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 352.616677 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 342.878941 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 199.536636 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 184.094618 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 192.697462 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 169.343891 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 172.952628 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 175.110539 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 474.235439 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 447.779765 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 416.685434 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 385.882443 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 404.699708 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 363.070008 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 624.839841 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 615.958067 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 329.06723 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 345.786502 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 127.328515 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 128.997015 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 275.285879 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 272.488545 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1007.052847 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 942.271572 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 501.928282 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 431.511816 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 713.844255 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 670.054138 ms
|
||||
|
||||
BUILD SUCCESSFUL in 32s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,157 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3077:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3142:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3350:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3746:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3757:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3816:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3927:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3983:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt:169:37 Redundant call of conversion method.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 255.650854 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 145.478367 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 194.190057 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 161.917102 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1553.057072 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1240.793002 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 944.216355 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 1009.585989 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1539.226472 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1454.032021 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 977.674848 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 990.058604 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 853.990613 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 786.133583 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=268.317 ms, ON=280.306 ms, speedup=0.96x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 373.337982 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 363.041028 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 203.456039 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 189.400538 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 191.685426 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 172.746472 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 172.601148 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 175.298872 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 480.488372 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 449.23481 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 428.089067 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 392.908699 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 409.659747 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 367.216414 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 608.613603 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 626.039278 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 325.012701 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 321.701777 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 127.06677 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 129.773497 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 279.046361 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 271.50303 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1022.352328 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 964.474767 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 496.707269 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 442.890336 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 695.24589 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 579.05104 ms
|
||||
|
||||
BUILD SUCCESSFUL in 34s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,157 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3077:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3142:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3350:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3746:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3757:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3816:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3927:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3983:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt:169:37 Redundant call of conversion method.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 255.197357 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 145.587919 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 192.491336 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 162.773639 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1527.164983 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1468.249877 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 1067.915333 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 1006.785753 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1525.341699 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1272.182191 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 820.632254 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 840.236564 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 688.095527 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 655.496511 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=257.927 ms, ON=256.999 ms, speedup=1.00x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 354.975875 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 345.167837 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 202.94016 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 189.847027 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 194.183153 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 166.705436 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 158.344393 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 171.7144 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 485.762962 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 451.642059 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 422.33805 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 381.000391 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 421.92221 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 374.912331 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 619.019405 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 607.095909 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 344.680073 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 370.68396 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 123.837196 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 127.987498 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 275.825602 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 272.281156 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1004.34663 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 950.919274 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 467.891003 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 380.721475 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 608.237558 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 611.825714 ms
|
||||
|
||||
BUILD SUCCESSFUL in 33s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,156 +0,0 @@
|
||||
Reusing configuration cache.
|
||||
> Task :lynglib:jvmProcessResources NO-SOURCE
|
||||
> Task :lyngio:jvmProcessResources NO-SOURCE
|
||||
> Task :lynglib:jvmTestProcessResources NO-SOURCE
|
||||
> Task :lynglib:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lyngio:kmpPartiallyResolvedDependenciesChecker
|
||||
> Task :lynglib:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lyngio:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmMainResources SKIPPED
|
||||
> Task :lynglib:processJvmTestResources SKIPPED
|
||||
> Task :lyngio:checkKotlinGradlePluginConfigurationErrors SKIPPED
|
||||
> Task :lynglib:generateLyngStdlib
|
||||
> Task :lynglib:generateBuildKonfig
|
||||
|
||||
> Task :lynglib:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:228:25 'when' is exhaustive so 'else' is redundant here.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3044:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3076:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3109:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3317:46 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3713:42 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3724:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3783:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3894:62 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt:3950:66 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Scope.kt:727:31 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:507:50 The corresponding parameter in the supertype 'Statement' is named 'scope'. This may cause problems when calling this function with named arguments.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/Obj.kt:820:57 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:33:32 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:158:39 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:177:64 'val monthNumber: Int' is deprecated. Use the 'month' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:179:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:181:64 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDateTime.kt:266:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:35:31 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:102:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:106:24 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:117:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:119:38 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:123:29 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:125:41 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:139:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:144:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:149:25 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:202:69 'val dayOfMonth: Int' is deprecated. Use the 'day' property instead.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:212:28 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:222:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInstant.kt:234:21 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:432:35 No cast needed.
|
||||
w: file:///home/sergeych/dev/ling_lib/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt:451:35 No cast needed.
|
||||
|
||||
> Task :lynglib:compileJvmMainJava NO-SOURCE
|
||||
> Task :lynglib:jvmMainClasses
|
||||
> Task :lynglib:jvmJar
|
||||
|
||||
> Task :lyngio:compileKotlinJvm
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:192:71 'typealias Instant = Instant' is deprecated. This type is deprecated in favor of `kotlin.time.Instant`.
|
||||
w: file:///home/sergeych/dev/ling_lib/lyngio/src/commonMain/kotlin/net/sergeych/lyng/io/fs/LyngFsModule.kt:315:51 Redundant call of conversion method.
|
||||
|
||||
> Task :lyngio:compileJvmMainJava NO-SOURCE
|
||||
> Task :lyngio:jvmMainClasses
|
||||
> Task :lyngio:jvmJar
|
||||
> Task :lynglib:compileTestKotlinJvm
|
||||
> Task :lynglib:compileJvmTestJava NO-SOURCE
|
||||
> Task :lynglib:jvmTestClasses
|
||||
|
||||
> Task :lynglib:jvmTest
|
||||
|
||||
ArithmeticBenchmarkTest[jvm] > benchmarkIntArithmeticAndComparisons[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=OFF]: 257.626421 ms
|
||||
[DEBUG_LOG] [BENCH] int-sum x400000 [PRIMITIVE_FASTOPS=ON]: 145.74696 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=OFF]: 185.585751 ms
|
||||
[DEBUG_LOG] [BENCH] int-cmp x400000 [PRIMITIVE_FASTOPS=ON]: 163.520035 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1505.046393 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1314.629855 ms
|
||||
|
||||
CallBenchmarkTest[jvm] > benchmarkSimpleFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=OFF]: 894.419862 ms
|
||||
[DEBUG_LOG] [BENCH] calls x300000 [ARG_BUILDER=ON]: 872.837744 ms
|
||||
|
||||
CallMixedArityBenchmarkTest[jvm] > benchmarkMixedArityCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=OFF]: 1240.254948 ms
|
||||
[DEBUG_LOG] [BENCH] mixed-arity x200000 [ARG_BUILDER=ON]: 1212.818849 ms
|
||||
|
||||
CallPoolingBenchmarkTest[jvm] > benchmarkScopePoolingOnFunctionCalls[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=OFF]: 809.588732 ms
|
||||
[DEBUG_LOG] [BENCH] call-pooling x300000 [SCOPE_POOL=ON]: 925.016684 ms
|
||||
|
||||
CallSplatBenchmarkTest[jvm] > benchmarkCallsWithSplatArgs[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=OFF]: 721.186901 ms
|
||||
[DEBUG_LOG] [BENCH] splat-calls x120000 [ARG_BUILDER=ON]: 637.576161 ms
|
||||
|
||||
ConcurrencyCallBenchmarkTest[jvm] > benchmark_multithread_calls_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] ConcurrencyCallBenchmark workers=8 iters=15000 each: OFF=262.726 ms, ON=255.278 ms, speedup=1.03x
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkExpressionChains[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=OFF]: 362.438514 ms
|
||||
[DEBUG_LOG] [BENCH] expr-chain x350000 [RVAL_FASTPATH=ON]: 340.324569 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkListIndexReads[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=OFF]: 195.843032 ms
|
||||
[DEBUG_LOG] [BENCH] list-index x350000 [RVAL_FASTPATH=ON]: 186.899727 ms
|
||||
|
||||
ExpressionBenchmarkTest[jvm] > benchmarkFieldReadPureReceiver[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=OFF]: 184.415897 ms
|
||||
[DEBUG_LOG] [BENCH] field-read x300000 [RVAL_FASTPATH=ON]: 167.959195 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkSumInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=OFF]: 162.448057 ms
|
||||
[DEBUG_LOG] [BENCH] list-sum x200000 [PRIMITIVE_FASTOPS=ON]: 159.74125 ms
|
||||
|
||||
ListOpsBenchmarkTest[jvm] > benchmarkContainsInts[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=OFF]: 481.042413 ms
|
||||
[DEBUG_LOG] [BENCH] list-contains x1000000 [PRIMITIVE_FASTOPS=ON]: 455.885378 ms
|
||||
|
||||
LocalVarBenchmarkTest[jvm] > benchmarkLocalReadsWrites_off_on[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=OFF, FAST_LOCAL=OFF]: 409.51578 ms
|
||||
[DEBUG_LOG] [BENCH] locals x400000 [PIC=ON, FAST_LOCAL=ON]: 372.056401 ms
|
||||
|
||||
MethodPoolingBenchmarkTest[jvm] > benchmarkInstanceMethodCallsWithPooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=OFF]: 388.436636 ms
|
||||
[DEBUG_LOG] [BENCH] method-loop x300000 [SCOPE_POOL=ON]: 361.562638 ms
|
||||
|
||||
MixedBenchmarkTest[jvm] > benchmarkMixedWorkloadRvalFastpath[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=OFF]: 631.060283 ms
|
||||
[DEBUG_LOG] [BENCH] mixed x250000 [RVAL_FASTPATH=ON]: 596.452285 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkMethodPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Method PIC=OFF, POOL=OFF: 325.619575 ms
|
||||
[DEBUG_LOG] [BENCH] Method PIC=ON, POOL=ON: 323.664554 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkFieldGetSetPic[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Field PIC=OFF: 130.20855 ms
|
||||
[DEBUG_LOG] [BENCH] Field PIC=ON: 125.922059 ms
|
||||
|
||||
PicBenchmarkTest[jvm] > benchmarkLoopScopePooling[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=OFF: 265.902703 ms
|
||||
[DEBUG_LOG] [BENCH] Loop Pool=ON: 264.289188 ms
|
||||
|
||||
RangeBenchmarkTest[jvm] > benchmarkIntRangeForIn[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=OFF]: 1218.053408 ms
|
||||
[DEBUG_LOG] [BENCH] range-for-in x5000 (inner 0..999) [PRIMITIVE_FASTOPS=ON]: 1156.935646 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkDynamicPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=OFF]: 433.071618 ms
|
||||
[DEBUG_LOG] [BENCH] regex-dynamic x300000 [REGEX_CACHE=ON]: 371.30824 ms
|
||||
|
||||
RegexBenchmarkTest[jvm] > benchmarkLiteralPatternMatches[jvm] STANDARD_OUT
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=OFF]: 570.399724 ms
|
||||
[DEBUG_LOG] [BENCH] regex-literal x500000 [REGEX_CACHE=ON]: 533.532049 ms
|
||||
|
||||
BUILD SUCCESSFUL in 33s
|
||||
10 actionable tasks: 10 executed
|
||||
Configuration cache entry reused.
|
||||
@ -1,246 +0,0 @@
|
||||
diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt
|
||||
index 0671102..d4cb6ba 100644
|
||||
--- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt
|
||||
+++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjInt.kt
|
||||
@@ -55,7 +55,11 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if (other !is Numeric) return -2
|
||||
- return value.compareTo(other.doubleValue)
|
||||
+ return if (other is ObjInt) {
|
||||
+ value.compareTo(other.value)
|
||||
+ } else {
|
||||
+ doubleValue.compareTo(other.doubleValue)
|
||||
+ }
|
||||
}
|
||||
|
||||
override fun toString(): String = value.toString()
|
||||
@@ -192,4 +196,4 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
}
|
||||
|
||||
fun Int.toObj() = ObjInt.of(this.toLong())
|
||||
-fun Long.toObj() = ObjInt.of(this)
|
||||
\ No newline at end of file
|
||||
+fun Long.toObj() = ObjInt.of(this)
|
||||
diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt
|
||||
index 0c631d0..dc61c66 100644
|
||||
--- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt
|
||||
+++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRange.kt
|
||||
@@ -96,6 +96,30 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
if (other is ObjRange)
|
||||
return containsRange(scope, other)
|
||||
|
||||
+ if (net.sergeych.lyng.PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
+ if (start is ObjInt && end is ObjInt && other is ObjInt) {
|
||||
+ val s = start.value
|
||||
+ val e = end.value
|
||||
+ val v = other.value
|
||||
+ if (v < s) return false
|
||||
+ return if (isEndInclusive) v <= e else v < e
|
||||
+ }
|
||||
+ if (start is ObjChar && end is ObjChar && other is ObjChar) {
|
||||
+ val s = start.value
|
||||
+ val e = end.value
|
||||
+ val v = other.value
|
||||
+ if (v < s) return false
|
||||
+ return if (isEndInclusive) v <= e else v < e
|
||||
+ }
|
||||
+ if (start is ObjString && end is ObjString && other is ObjString) {
|
||||
+ val s = start.value
|
||||
+ val e = end.value
|
||||
+ val v = other.value
|
||||
+ if (v < s) return false
|
||||
+ return if (isEndInclusive) v <= e else v < e
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (start == null && end == null) return true
|
||||
if (start != null) {
|
||||
if (start.compareTo(scope, other) > 0) return false
|
||||
@@ -241,4 +265,3 @@ class ObjRange(val start: Obj?, val end: Obj?, val isEndInclusive: Boolean) : Ob
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt
|
||||
index 2dd0ae6..76e56d4 100644
|
||||
--- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt
|
||||
+++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjRef.kt
|
||||
@@ -152,6 +152,90 @@ class BinaryOpRef(private val op: BinOp, private val left: ObjRef, private val r
|
||||
|
||||
// Primitive fast paths for common cases (guarded by PerfFlags.PRIMITIVE_FASTOPS)
|
||||
if (PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
+ // Fast range equality: avoid compareTo/equals for ObjRange when possible
|
||||
+ if ((op == BinOp.EQ || op == BinOp.NEQ) && a is ObjRange && b is ObjRange) {
|
||||
+ val eq = (a.start == b.start && a.end == b.end)
|
||||
+ if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||
+ return if (op == BinOp.EQ) {
|
||||
+ if (eq) ObjTrue else ObjFalse
|
||||
+ } else {
|
||||
+ if (eq) ObjFalse else ObjTrue
|
||||
+ }
|
||||
+ }
|
||||
+ // Fast membership for common containers
|
||||
+ if (op == BinOp.IN || op == BinOp.NOTIN) {
|
||||
+ val inResult: Boolean? = when (b) {
|
||||
+ is ObjList -> {
|
||||
+ if (a is ObjInt) {
|
||||
+ var i = 0
|
||||
+ val sz = b.list.size
|
||||
+ var found = false
|
||||
+ while (i < sz) {
|
||||
+ val v = b.list[i]
|
||||
+ if (v is ObjInt && v.value == a.value) {
|
||||
+ found = true
|
||||
+ break
|
||||
+ }
|
||||
+ i++
|
||||
+ }
|
||||
+ found
|
||||
+ } else {
|
||||
+ b.list.contains(a)
|
||||
+ }
|
||||
+ }
|
||||
+ is ObjSet -> b.set.contains(a)
|
||||
+ is ObjMap -> b.map.containsKey(a)
|
||||
+ is ObjRange -> {
|
||||
+ when (a) {
|
||||
+ is ObjInt -> {
|
||||
+ val s = b.start as? ObjInt
|
||||
+ val e = b.end as? ObjInt
|
||||
+ val v = a.value
|
||||
+ if (s == null && e == null) null
|
||||
+ else {
|
||||
+ if (s != null && v < s.value) false
|
||||
+ else if (e != null) if (b.isEndInclusive) v <= e.value else v < e.value else true
|
||||
+ }
|
||||
+ }
|
||||
+ is ObjChar -> {
|
||||
+ val s = b.start as? ObjChar
|
||||
+ val e = b.end as? ObjChar
|
||||
+ val v = a.value
|
||||
+ if (s == null && e == null) null
|
||||
+ else {
|
||||
+ if (s != null && v < s.value) false
|
||||
+ else if (e != null) if (b.isEndInclusive) v <= e.value else v < e.value else true
|
||||
+ }
|
||||
+ }
|
||||
+ is ObjString -> {
|
||||
+ val s = b.start as? ObjString
|
||||
+ val e = b.end as? ObjString
|
||||
+ val v = a.value
|
||||
+ if (s == null && e == null) null
|
||||
+ else {
|
||||
+ if (s != null && v < s.value) false
|
||||
+ else if (e != null) if (b.isEndInclusive) v <= e.value else v < e.value else true
|
||||
+ }
|
||||
+ }
|
||||
+ else -> null
|
||||
+ }
|
||||
+ }
|
||||
+ is ObjString -> when (a) {
|
||||
+ is ObjString -> b.value.contains(a.value)
|
||||
+ is ObjChar -> b.value.contains(a.value)
|
||||
+ else -> null
|
||||
+ }
|
||||
+ else -> null
|
||||
+ }
|
||||
+ if (inResult != null) {
|
||||
+ if (PerfFlags.PIC_DEBUG_COUNTERS) PerfStats.primitiveFastOpsHit++
|
||||
+ return if (op == BinOp.IN) {
|
||||
+ if (inResult) ObjTrue else ObjFalse
|
||||
+ } else {
|
||||
+ if (inResult) ObjFalse else ObjTrue
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
// Fast boolean ops when both operands are ObjBool
|
||||
if (a is ObjBool && b is ObjBool) {
|
||||
val r: Obj? = when (op) {
|
||||
@@ -604,7 +688,37 @@ class AssignOpRef(
|
||||
else -> null
|
||||
}
|
||||
if (inPlace != null) return inPlace.asReadonly
|
||||
- val result: Obj = when (op) {
|
||||
+ val fast: Obj? = if (PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
+ when {
|
||||
+ x is ObjInt && y is ObjInt -> {
|
||||
+ val xv = x.value
|
||||
+ val yv = y.value
|
||||
+ when (op) {
|
||||
+ BinOp.PLUS -> ObjInt.of(xv + yv)
|
||||
+ BinOp.MINUS -> ObjInt.of(xv - yv)
|
||||
+ BinOp.STAR -> ObjInt.of(xv * yv)
|
||||
+ BinOp.SLASH -> if (yv != 0L) ObjInt.of(xv / yv) else null
|
||||
+ BinOp.PERCENT -> if (yv != 0L) ObjInt.of(xv % yv) else null
|
||||
+ else -> null
|
||||
+ }
|
||||
+ }
|
||||
+ (x is ObjInt || x is ObjReal) && (y is ObjInt || y is ObjReal) -> {
|
||||
+ val xv = if (x is ObjInt) x.doubleValue else (x as ObjReal).value
|
||||
+ val yv = if (y is ObjInt) y.doubleValue else (y as ObjReal).value
|
||||
+ when (op) {
|
||||
+ BinOp.PLUS -> ObjReal.of(xv + yv)
|
||||
+ BinOp.MINUS -> ObjReal.of(xv - yv)
|
||||
+ BinOp.STAR -> ObjReal.of(xv * yv)
|
||||
+ BinOp.SLASH -> ObjReal.of(xv / yv)
|
||||
+ BinOp.PERCENT -> ObjReal.of(xv % yv)
|
||||
+ else -> null
|
||||
+ }
|
||||
+ }
|
||||
+ x is ObjString && op == BinOp.PLUS -> ObjString(x.value + y.toString())
|
||||
+ else -> null
|
||||
+ }
|
||||
+ } else null
|
||||
+ val result: Obj = fast ?: when (op) {
|
||||
BinOp.PLUS -> x.plus(scope, y)
|
||||
BinOp.MINUS -> x.minus(scope, y)
|
||||
BinOp.STAR -> x.mul(scope, y)
|
||||
@@ -632,7 +746,15 @@ class IncDecRef(
|
||||
// We now treat numbers as immutable and always perform write-back via setAt.
|
||||
// This avoids issues where literals are shared and mutated in-place.
|
||||
// For post-inc: return ORIGINAL value; for pre-inc: return NEW value.
|
||||
- val result = if (isIncrement) v.plus(scope, one) else v.minus(scope, one)
|
||||
+ val result = if (PerfFlags.PRIMITIVE_FASTOPS) {
|
||||
+ when (v) {
|
||||
+ is ObjInt -> if (isIncrement) ObjInt.of(v.value + 1L) else ObjInt.of(v.value - 1L)
|
||||
+ is ObjReal -> if (isIncrement) ObjReal.of(v.value + 1.0) else ObjReal.of(v.value - 1.0)
|
||||
+ else -> if (isIncrement) v.plus(scope, one) else v.minus(scope, one)
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (isIncrement) v.plus(scope, one) else v.minus(scope, one)
|
||||
+ }
|
||||
target.setAt(atPos, scope, result)
|
||||
return (if (isPost) v else result).asReadonly
|
||||
}
|
||||
@@ -1246,8 +1368,8 @@ class IndexRef(
|
||||
val i = idx.toInt()
|
||||
return ObjChar(base.value[i]).asMutable
|
||||
}
|
||||
- // Map[String] fast path (common case); return ObjNull if absent
|
||||
- if (base is ObjMap && idx is ObjString) {
|
||||
+ // Map[String/Int/Char] fast path (common cases); return ObjNull if absent
|
||||
+ if (base is ObjMap && (idx is ObjString || idx is ObjInt || idx is ObjChar)) {
|
||||
val v = base.map[idx] ?: ObjNull
|
||||
return v.asMutable
|
||||
}
|
||||
@@ -1321,8 +1443,8 @@ class IndexRef(
|
||||
val i = idx.toInt()
|
||||
return ObjChar(base.value[i])
|
||||
}
|
||||
- // Map[String] fast path
|
||||
- if (base is ObjMap && idx is ObjString) {
|
||||
+ // Map[String/Int/Char] fast path
|
||||
+ if (base is ObjMap && (idx is ObjString || idx is ObjInt || idx is ObjChar)) {
|
||||
return base.map[idx] ?: ObjNull
|
||||
}
|
||||
if (PerfFlags.INDEX_PIC) {
|
||||
@@ -1393,7 +1515,7 @@ class IndexRef(
|
||||
return
|
||||
}
|
||||
// Direct write fast path for ObjMap + ObjString
|
||||
- if (base is ObjMap && idx is ObjString) {
|
||||
+ if (base is ObjMap && (idx is ObjString || idx is ObjInt || idx is ObjChar)) {
|
||||
base.map[idx] = newValue
|
||||
return
|
||||
}
|
||||
@ -329,7 +329,7 @@
|
||||
<!-- Top-left version ribbon -->
|
||||
<div class="corner-ribbon bg-danger text-white">
|
||||
<span style="margin-left: -5em">
|
||||
v1.2.1!
|
||||
v1.2.0!
|
||||
</span>
|
||||
</div>
|
||||
<!-- Fixed top navbar for the whole site -->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user