Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f357f4039b | |||
| b674ee7c18 | |||
| a4f41f17bf | |||
| 96947aac50 | |||
| 98d6ffe998 | |||
| 74d73540c6 | |||
| 9b580bafb6 | |||
| 062f9e7866 | |||
| 717a79aca2 | |||
| 7b1ba71ef0 | |||
| 8b94432f66 | |||
| 338dc00573 | |||
| d0230c5b89 | |||
| 5dc2159024 | |||
| 0759346e4b | |||
| f848d79d39 | |||
| 52a3a96e3f | |||
| b7dfda2f5d | |||
| 05e15e8e42 | |||
| d4bb186f85 | |||
| 7bc17037f9 |
8
AGENTS.md
Normal file
8
AGENTS.md
Normal file
@ -0,0 +1,8 @@
|
||||
# AI Agent Notes
|
||||
|
||||
## Kotlin/Wasm generation guardrails
|
||||
- Avoid creating suspend lambdas for compiler runtime statements. Prefer explicit `object : Statement()` with `override suspend fun execute(...)`.
|
||||
- Do not use `statement { ... }` or other inline suspend lambdas in compiler hot paths (e.g., parsing/var declarations, initializer thunks).
|
||||
- If you need a wrapper for delegated properties, check for `getValue` explicitly and return a concrete `Statement` object when missing; avoid `onNotFoundResult` lambdas.
|
||||
- If wasmJs browser tests hang, first run `:lynglib:wasmJsNodeTest` and look for wasm compilation errors; hangs usually mean module instantiation failed.
|
||||
- Do not increase test timeouts to mask wasm generation errors; fix the invalid IR instead.
|
||||
@ -2,6 +2,11 @@
|
||||
|
||||
### Unreleased
|
||||
|
||||
- Language: Refined `protected` visibility rules
|
||||
- Ancestor classes can now access `protected` members of their descendants, provided the ancestor also defines or inherits a member with the same name (indicating an override of a member known to the ancestor).
|
||||
- This allows patterns where a base class calls a `protected` method that is implemented in a subclass.
|
||||
- Fixed a regression where self-calls to unmangled members sometimes bypassed visibility checks incorrectly; these are now handled by the refined logic.
|
||||
|
||||
- Language: Added `return` statement
|
||||
- `return [expression]` exits the innermost enclosing callable (function or lambda).
|
||||
- Supports non-local returns using `@label` syntax (e.g., `return@outer 42`).
|
||||
@ -96,7 +101,7 @@
|
||||
- Header-specified constructor arguments are passed to direct bases.
|
||||
- Visibility enforcement under MI:
|
||||
- `private` visible only inside the declaring class body.
|
||||
- `protected` visible inside the declaring class and any of its transitive subclasses; unrelated contexts cannot access it (qualification/casts do not bypass).
|
||||
- `protected` visible inside the declaring class and its transitive subclasses. Additionally, ancestor classes can access protected members of their descendants if it's an override of a member known to the ancestor. Unrelated contexts cannot access it (qualification/casts do not bypass).
|
||||
- Diagnostics improvements:
|
||||
- Missing member/field messages include receiver class and linearization order; hints for `this@Type` or casts when helpful.
|
||||
- Invalid `this@Type` reports that the qualifier is not an ancestor and shows the receiver lineage.
|
||||
|
||||
@ -14,6 +14,7 @@ High-density specification for LLMs. Reference this for all Lyng code generation
|
||||
4. `void` (if loop body never executed and no `else`).
|
||||
- **Implicit Coroutines**: All functions are coroutines. No `async/await`. Use `launch { ... }` (returns `Deferred`) or `flow { ... }`.
|
||||
- **Variables**: `val` (read-only), `var` (mutable). Supports late-init `val` in classes (must be assigned in `init` or body).
|
||||
- **Serialization**: Use `@Transient` attribute before `val`/`var` or constructor parameters to exclude them from Lynon/JSON serialization. Transient fields are also ignored during `==` structural equality checks.
|
||||
- **Null Safety**: `?` (nullable type), `?.` (safe access), `?( )` (safe invoke), `?{ }` (safe block invoke), `?[ ]` (safe index), `?:` or `??` (elvis), `?=` (assign-if-null).
|
||||
- **Equality**: `==` (equals), `!=` (not equals), `===` (ref identity), `!==` (ref not identity).
|
||||
- **Comparison**: `<`, `>`, `<=`, `>=`, `<=>` (shuttle/spaceship, returns -1, 0, 1).
|
||||
@ -32,7 +33,7 @@ High-density specification for LLMs. Reference this for all Lyng code generation
|
||||
val area get = π * r * r
|
||||
```
|
||||
- **Mandatory `override`**: Required for all members existing in the ancestor chain.
|
||||
- **Visibility**: `public` (default), `protected` (subclasses), `private` (this class instance only). `private set` / `protected set` allowed on properties.
|
||||
- **Visibility**: `public` (default), `protected` (subclasses and ancestors for overrides), `private` (this class instance only). `private set` / `protected set` allowed on properties.
|
||||
- **Disambiguation**: `this@Base.member()` or `(obj as Base).member()`. `as` returns a qualified view.
|
||||
- **Abstract/Interface**: `interface` is a synonym for `abstract class`. Both support state and constructors.
|
||||
- **Extensions**: `fun Class.ext()` or `val Class.ext get = ...`. Scope-isolated.
|
||||
@ -93,7 +94,7 @@ m += "c" => 3
|
||||
val [first, middle..., last] = [1, 2, 3, 4, 5]
|
||||
|
||||
// Safe Navigation and Elvis
|
||||
val companyName = person?.job?.company?.name ?? "Freelancer"
|
||||
val companyName = person?.job?.company?.name ?: "Freelancer"
|
||||
```
|
||||
|
||||
## 8. Standard Library Discovery
|
||||
|
||||
@ -45,6 +45,7 @@ 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
|
||||
|
||||
|
||||
43
docs/OOP.md
43
docs/OOP.md
@ -425,7 +425,7 @@ Key rules and features:
|
||||
|
||||
- Visibility
|
||||
- `private`: accessible only inside the declaring class body; not visible in subclasses and cannot be accessed via `this@Type` or casts.
|
||||
- `protected`: accessible in the declaring class and in any of its transitive subclasses (including MI), but not from unrelated contexts; qualification/casts do not bypass it.
|
||||
- `protected`: accessible in the declaring class and in any of its transitive subclasses (including MI). Additionally, ancestor classes can access protected members of their descendants if it's an override of a member known to the ancestor. Protected members are not visible from unrelated contexts; qualification/casts do not bypass it.
|
||||
|
||||
## Abstract Classes and Members
|
||||
|
||||
@ -857,23 +857,44 @@ Private fields are visible only _inside the class instance_:
|
||||
void
|
||||
>>> void
|
||||
|
||||
### Transient fields
|
||||
|
||||
You can mark a field or a constructor parameter as transient using the `@Transient` attribute. Transient members are ignored during serialization (Lynon and JSON) and are also excluded from structural equality (`==`) checks.
|
||||
|
||||
```lyng
|
||||
class Session(@Transient val token, val userId) {
|
||||
@Transient var lastAccess = time.now()
|
||||
var data = Map()
|
||||
}
|
||||
```
|
||||
|
||||
For more details on how transient fields behave during restoration, see the [Serialization Guide](serialization.md).
|
||||
|
||||
### Protected members
|
||||
|
||||
Protected members are available to the declaring class and all of its transitive subclasses (including via MI), but not from unrelated contexts:
|
||||
Protected members are available to the declaring class and all of its transitive subclasses (including via MI). Additionally, an ancestor class can access a `protected` member of its descendant if the ancestor also defines or inherits a member with the same name (i.e., it is an override of something the ancestor knows about).
|
||||
|
||||
```
|
||||
class A() {
|
||||
protected fun ping() { "pong" }
|
||||
}
|
||||
class B() : A() {
|
||||
fun call() { this@A.ping() }
|
||||
Protected members are not available from unrelated contexts:
|
||||
|
||||
```lyng
|
||||
class Base {
|
||||
abstract protected fun foo()
|
||||
|
||||
fun bar() {
|
||||
// Ancestor can see foo() because it's an override
|
||||
// of a member it defines (even as abstract):
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
val b = B()
|
||||
assertEquals("pong", b.call())
|
||||
class Derived : Base {
|
||||
override protected fun foo() { "ok" }
|
||||
}
|
||||
|
||||
assertEquals("ok", Derived().bar())
|
||||
|
||||
// Unrelated access is forbidden, even via cast
|
||||
assertThrows { (b as A).ping() }
|
||||
assertThrows { (Derived() as Base).foo() }
|
||||
```
|
||||
|
||||
It is possible to provide private constructor parameters so they can be
|
||||
|
||||
@ -98,10 +98,11 @@ Exclusive end char ranges are supported too:
|
||||
| isEndInclusive | true for '..' | Bool |
|
||||
| isOpen | at any end | Bool |
|
||||
| isIntRange | both start and end are Int | Bool |
|
||||
| start | | Bool |
|
||||
| end | | Bool |
|
||||
| start | | Any? |
|
||||
| end | | Any? |
|
||||
| size | for finite ranges, see above | Long |
|
||||
| [] | see above | |
|
||||
| | | |
|
||||
|
||||
Ranges are also used with the `clamp(value, range)` function and the `value.clamp(range)` extension method to limit values within boundaries.
|
||||
|
||||
[Iterable]: Iterable.md
|
||||
@ -19,6 +19,7 @@ you can use it's class to ensure type:
|
||||
|-----------------|-------------------------------------------------------------|------|
|
||||
| `.roundToInt()` | round to nearest int like round(x) | Int |
|
||||
| `.toInt()` | convert integer part of real to `Int` dropping decimal part | Int |
|
||||
| `.clamp(range)` | clamp value within range boundaries | Real |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
|
||||
15
docs/ai_notes_wasm_generation_bug.md
Normal file
15
docs/ai_notes_wasm_generation_bug.md
Normal file
@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
@ -20,7 +20,18 @@ Simple classes serialization is supported:
|
||||
assertEquals( "{\"foo\":1,\"bar\":2}", Point(1,2).toJsonString() )
|
||||
>>> void
|
||||
|
||||
Note that mutable members are serialized:
|
||||
Note that mutable members are serialized by default. You can exclude any member (including constructor parameters) from JSON serialization using the `@Transient` attribute:
|
||||
|
||||
import lyng.serialization
|
||||
|
||||
class Point2(@Transient val foo, val bar) {
|
||||
@Transient var reason = 42
|
||||
var visible = 100
|
||||
}
|
||||
assertEquals( "{\"bar\":2,\"visible\":100}", Point2(1,2).toJsonString() )
|
||||
>>> void
|
||||
|
||||
Note that if you override json serialization:
|
||||
|
||||
import lyng.serialization
|
||||
|
||||
|
||||
@ -92,6 +92,7 @@ or transformed `Real` otherwise.
|
||||
| pow(x, y) | ${x^y}$ |
|
||||
| sqrt(x) | $ \sqrt {x}$ |
|
||||
| abs(x) | absolute value of x. Int if x is Int, Real otherwise |
|
||||
| clamp(x, range) | limit x to be inside range boundaries |
|
||||
|
||||
For example:
|
||||
|
||||
@ -102,6 +103,11 @@ For example:
|
||||
// abs() keeps the argument type:
|
||||
assert( abs(-1) is Int)
|
||||
assert( abs(-2.21) == 2.21 )
|
||||
|
||||
// clamp() limits value to the range:
|
||||
assert( clamp(15, 0..10) == 10 )
|
||||
assert( clamp(-5, 0..10) == 0 )
|
||||
assert( 5.clamp(0..10) == 5 )
|
||||
>>> void
|
||||
|
||||
## Scientific constant
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#!/bin/env lyng
|
||||
|
||||
import lyng.io.fs
|
||||
import lyng.stdlib
|
||||
|
||||
val files = Path("../..").list().toList()
|
||||
// most long is longest?
|
||||
|
||||
@ -20,20 +20,37 @@ It is as simple as:
|
||||
assert( text.length > encodedBits.toBuffer().size )
|
||||
>>> void
|
||||
|
||||
Any class you create is serializable by default; lynon serializes first constructor fields, then any `var` member fields:
|
||||
Any class you create is serializable by default; lynon serializes first constructor fields, then any `var` member fields.
|
||||
|
||||
import lyng.serialization
|
||||
## Transient Fields
|
||||
|
||||
class Point(x,y)
|
||||
Sometimes you have fields that should not be serialized, for example, temporary caches, secret data, or derived values that are recomputed in `init` blocks. You can mark such fields with the `@Transient` attribute:
|
||||
|
||||
val p = Lynon.decode( Lynon.encode( Point(5,6) ) )
|
||||
```lyng
|
||||
class MyData(@Transient val tempSecret, val publicData) {
|
||||
@Transient var cachedValue = 0
|
||||
var persistentValue = 42
|
||||
|
||||
assertEquals( 5, p.x )
|
||||
assertEquals( 6, p.y )
|
||||
>>> void
|
||||
init {
|
||||
// cachedValue can be recomputed here upon deserialization
|
||||
cachedValue = computeCache(publicData)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Transient fields:
|
||||
- Are **omitted** from Lynon binary streams.
|
||||
- Are **omitted** from JSON output (via `toJson`).
|
||||
- Are **ignored** during structural equality checks (`==`).
|
||||
- If a transient constructor parameter has a **default value**, it will be restored to that default value during deserialization. Otherwise, it will be `null`.
|
||||
- Class body fields marked as `@Transient` will keep their initial values (or values assigned in `init`) after deserialization.
|
||||
|
||||
just as expected.
|
||||
## Serialization of Objects and Classes
|
||||
|
||||
- **Singleton Objects**: `object` declarations are serializable by name. Their state (mutable fields) is also serialized and restored, respecting `@Transient`.
|
||||
- **Classes**: Class objects themselves can be serialized. They are serialized by their full qualified name. When converted to JSON, a class object includes its public static fields (excluding those marked `@Transient`).
|
||||
|
||||
## Custom Serialization
|
||||
|
||||
Important is to understand that normally `Lynon.decode` wants [BitBuffer], as `Lynon.encode` produces. If you have the regular [Buffer], be sure to convert it:
|
||||
|
||||
|
||||
205
docs/time.md
205
docs/time.md
@ -2,166 +2,105 @@
|
||||
|
||||
Lyng date and time support requires importing `lyng.time` packages. Lyng uses simple yet modern time object models:
|
||||
|
||||
- `Instant` class for time stamps with platform-dependent resolution
|
||||
- `Duration` to represent amount of time not depending on the calendar, e.g. in absolute units (milliseconds, seconds,
|
||||
hours, days)
|
||||
- `Instant` class for absolute time stamps with platform-dependent resolution.
|
||||
- `DateTime` class for calendar-aware points in time within a specific time zone.
|
||||
- `Duration` to represent amount of time not depending on the calendar (e.g., milliseconds, seconds).
|
||||
|
||||
## Time instant: `Instant`
|
||||
|
||||
Represent some moment of time not depending on the calendar (calendar for example may b e changed, daylight saving time
|
||||
can be for example introduced or dropped). It is similar to `TIMESTAMP` in SQL or `Instant` in Kotlin. Some moment of
|
||||
time; not the calendar date.
|
||||
Represent some moment of time not depending on the calendar. It is similar to `TIMESTAMP` in SQL or `Instant` in Kotlin.
|
||||
|
||||
Instant is comparable to other Instant. Subtracting instants produce `Duration`, period in time that is not dependent on
|
||||
the calendar, e.g. absolute time period.
|
||||
|
||||
It is possible to add or subtract `Duration` to and from `Instant`, that gives another `Instant`.
|
||||
|
||||
Instants are converted to and from `Real` number of seconds before or after Unix Epoch, 01.01.1970. Constructor with
|
||||
single number parameter constructs from such number of seconds,
|
||||
and any instance provide `.epochSeconds` member:
|
||||
### Constructing and converting
|
||||
|
||||
import lyng.time
|
||||
|
||||
// default constructor returns time now:
|
||||
val t1 = Instant()
|
||||
val t2 = Instant()
|
||||
assert( t2 - t1 < 1.millisecond )
|
||||
assert( t2.epochSeconds - t1.epochSeconds < 0.001 )
|
||||
>>> void
|
||||
|
||||
## Constructing
|
||||
// constructing from a number is treated as seconds since unix epoch:
|
||||
val t2 = Instant(1704110400) // 2024-01-01T12:00:00Z
|
||||
|
||||
import lyng.time
|
||||
// from RFC3339 string:
|
||||
val t3 = Instant("2024-01-01T12:00:00.123456Z")
|
||||
|
||||
// empty constructor gives current time instant using system clock:
|
||||
val now = Instant()
|
||||
// truncation:
|
||||
val t4 = t3.truncateToMinute
|
||||
assertEquals(t4.toRFC3339(), "2024-01-01T12:00:00Z")
|
||||
|
||||
// constructor with Instant instance makes a copy:
|
||||
assertEquals( now, Instant(now) )
|
||||
// to localized DateTime (uses system default TZ if not specified):
|
||||
val dt = t3.toDateTime("+02:00")
|
||||
assertEquals(dt.hour, 14)
|
||||
|
||||
// constructing from a number is trated as seconds since unix epoch:
|
||||
val copyOfNow = Instant( now.epochSeconds )
|
||||
|
||||
// note that instant resolution is higher that Real can hold
|
||||
// so reconstructed from real slightly differs:
|
||||
assert( abs( (copyOfNow - now).milliseconds ) < 0.01 )
|
||||
>>> void
|
||||
|
||||
The resolution of system clock could be more precise and double precision real number of `Real`, keep it in mind.
|
||||
|
||||
## Comparing and calculating periods
|
||||
|
||||
import lyng.time
|
||||
|
||||
val now = Instant()
|
||||
|
||||
// you cam add or subtract periods, and compare
|
||||
assert( now - 5.minutes < now )
|
||||
val oneHourAgo = now - 1.hour
|
||||
assertEquals( now, oneHourAgo + 1.hour)
|
||||
|
||||
>>> void
|
||||
|
||||
## Getting the max precision
|
||||
|
||||
Normally, subtracting instants gives precision to microseconds, which is well inside the jitter
|
||||
the language VM adds. Still `Instant()` or `Instant.now()` capture most precise system timer at hand and provide inner
|
||||
value of 12 bytes, up to nanoseconds (hopefully). To access it use:
|
||||
|
||||
import lyng.time
|
||||
|
||||
// capture time
|
||||
val now = Instant.now()
|
||||
|
||||
// this is Int value, number of whole epoch
|
||||
// milliseconds to the moment, it fits 8 bytes Int well
|
||||
val seconds = now.epochWholeSeconds
|
||||
assert(seconds is Int)
|
||||
|
||||
// and this is Int value of nanoseconds _since_ the epochMillis,
|
||||
// it effectively add 4 more mytes int:
|
||||
val nanos = now.nanosecondsOfSecond
|
||||
assert(nanos is Int)
|
||||
assert( nanos in 0..999_999_999 )
|
||||
|
||||
// we can construct epochSeconds from these parts:
|
||||
assertEquals( now.epochSeconds, nanos * 1e-9 + seconds )
|
||||
>>> void
|
||||
|
||||
## Truncating to more realistic precision
|
||||
|
||||
Full precision Instant is way too long and impractical to store, especially when serializing,
|
||||
so it is possible to truncate it to milliseconds, microseconds or seconds:
|
||||
|
||||
import lyng.time
|
||||
import lyng.serialization
|
||||
|
||||
// max supported size (now microseconds for serialized value):
|
||||
// note that encoding return _bit array_ and this is a _bit size_:
|
||||
val s0 = Lynon.encode(Instant.now()).size
|
||||
|
||||
// shorter: milliseconds only
|
||||
val s1 = Lynon.encode(Instant.now().truncateToMillisecond()).size
|
||||
|
||||
// truncated to seconds, good for file mtime, etc:
|
||||
val s2 = Lynon.encode(Instant.now().truncateToSecond()).size
|
||||
assert( s1 < s0 )
|
||||
assert( s2 < s1 )
|
||||
>>> void
|
||||
|
||||
## Formatting instants
|
||||
|
||||
You can freely use `Instant` in string formatting. It supports usual sprintf-style formats:
|
||||
|
||||
import lyng.time
|
||||
val now = Instant()
|
||||
|
||||
// will be something like "now: 12:10:05"
|
||||
val currentTimeOnly24 = "now: %tT"(now)
|
||||
|
||||
// we can extract epoch second with formatting too,
|
||||
// this was since early C time
|
||||
|
||||
// get epoch while seconds from formatting
|
||||
val unixEpoch = "Now is %ts since unix epoch"(now)
|
||||
|
||||
// and it is the same as now.epochSeconds, int part:
|
||||
assertEquals( unixEpoch, "Now is %d since unix epoch"(now.epochSeconds.toInt()) )
|
||||
>>> void
|
||||
|
||||
See
|
||||
the [complete list of available formats](https://github.com/sergeych/mp_stools?tab=readme-ov-file#datetime-formatting)
|
||||
and the [formatting reference](https://github.com/sergeych/mp_stools?tab=readme-ov-file#printf--sprintf): it all works
|
||||
in Lyng as `"format"(args...)`!
|
||||
|
||||
## Instant members
|
||||
### Instant members
|
||||
|
||||
| member | description |
|
||||
|--------------------------------|---------------------------------------------------------|
|
||||
| epochSeconds: Real | positive or negative offset in seconds since Unix epoch |
|
||||
| epochWholeSeconds: Int | same, but in _whole seconds_. Slightly faster |
|
||||
| nanosecondsOfSecond: Int | offset from epochWholeSeconds in nanos (1) |
|
||||
| nanosecondsOfSecond: Int | offset from epochWholeSeconds in nanos |
|
||||
| isDistantFuture: Bool | true if it `Instant.distantFuture` |
|
||||
| isDistantPast: Bool | true if it `Instant.distantPast` |
|
||||
| truncateToSecond: Intant | create new instnce truncated to second |
|
||||
| truncateToMillisecond: Instant | truncate new instance with to millisecond |
|
||||
| truncateToMinute: Instant | create new instance truncated to minute |
|
||||
| truncateToSecond: Instant | create new instance truncated to second |
|
||||
| truncateToMillisecond: Instant | truncate new instance to millisecond |
|
||||
| truncateToMicrosecond: Instant | truncate new instance to microsecond |
|
||||
| toRFC3339(): String | format as RFC3339 string (UTC) |
|
||||
| toDateTime(tz?): DateTime | localize to a TimeZone (ID string or offset seconds) |
|
||||
|
||||
(1)
|
||||
: The value of nanoseconds is to be added to `epochWholeSeconds` to get exact time point. It is in 0..999_999_999 range.
|
||||
The precise time instant value therefore needs as for now 12 bytes integer; we might use bigint later (it is planned to
|
||||
be added)
|
||||
## Calendar time: `DateTime`
|
||||
|
||||
## Class members
|
||||
`DateTime` represents a point in time in a specific timezone. It provides access to calendar components like year,
|
||||
month, and day.
|
||||
|
||||
### Constructing
|
||||
|
||||
import lyng.time
|
||||
|
||||
// Current time in system default timezone
|
||||
val now = DateTime.now()
|
||||
|
||||
// Specific timezone
|
||||
val offsetTime = DateTime.now("+02:00")
|
||||
|
||||
// From Instant
|
||||
val dt = Instant().toDateTime("Z")
|
||||
|
||||
// By components (year, month, day, hour=0, minute=0, second=0, timeZone="UTC")
|
||||
val dt2 = DateTime(2024, 1, 1, 12, 0, 0, "Z")
|
||||
|
||||
// From RFC3339 string
|
||||
val dt3 = DateTime.parseRFC3339("2024-01-01T12:00:00+02:00")
|
||||
|
||||
### DateTime members
|
||||
|
||||
| member | description |
|
||||
|--------------------------------|----------------------------------------------|
|
||||
| Instant.now() | create new instance with current system time |
|
||||
| Instant.distantPast: Instant | most distant instant in past |
|
||||
| Instant.distantFuture: Instant | most distant instant in future |
|
||||
|----------------------------------|-----------------------------------------------|
|
||||
| year: Int | year component |
|
||||
| month: Int | month component (1..12) |
|
||||
| day: Int | day of month (alias `dayOfMonth`) |
|
||||
| hour: Int | hour component (0..23) |
|
||||
| minute: Int | minute component (0..59) |
|
||||
| second: Int | second component (0..59) |
|
||||
| dayOfWeek: Int | day of week (1=Monday, 7=Sunday) |
|
||||
| timeZone: String | timezone ID string |
|
||||
| toInstant(): Instant | convert back to absolute Instant |
|
||||
| toUTC(): DateTime | shortcut to convert to UTC |
|
||||
| toTimeZone(tz): DateTime | convert to another timezone |
|
||||
| addMonths(n): DateTime | add/subtract months (normalizes end of month) |
|
||||
| addYears(n): DateTime | add/subtract years |
|
||||
| toRFC3339(): String | format with timezone offset |
|
||||
| static now(tz?): DateTime | create DateTime with current time |
|
||||
| static parseRFC3339(s): DateTime | parse RFC3339 string |
|
||||
|
||||
# `Duraion` class
|
||||
### Arithmetic and normalization
|
||||
|
||||
`DateTime` handles calendar arithmetic correctly:
|
||||
|
||||
val leapDay = Instant("2024-02-29T12:00:00Z").toDateTime("Z")
|
||||
val nextYear = leapDay.addYears(1)
|
||||
assertEquals(nextYear.day, 28) // Feb 29, 2024 -> Feb 28, 2025
|
||||
|
||||
# `Duration` class
|
||||
|
||||
Represent absolute time distance between two `Instant`.
|
||||
|
||||
|
||||
@ -1484,6 +1484,9 @@ A typical set of String functions includes:
|
||||
| lower(), lowercase() | change case to unicode upper |
|
||||
| upper(), uppercase() | change case to unicode lower |
|
||||
| trim() | trim space chars from both ends |
|
||||
| isEmpty() | true if string is empty |
|
||||
| isNotEmpty() | true if string is not empty |
|
||||
| isBlank() | true if empty or contains only whitespace |
|
||||
| startsWith(prefix) | true if starts with a prefix |
|
||||
| endsWith(prefix) | true if ends with a prefix |
|
||||
| last() | get last character of a string or throw |
|
||||
@ -1701,7 +1704,7 @@ assertEquals(null, (buzz as? Foo)?.runA())
|
||||
|
||||
Notes:
|
||||
- Resolution order uses C3 MRO (active): deterministic, monotonic order suitable for diamonds and complex hierarchies. Example: for `class D() : B(), C()` where both `B()` and `C()` derive from `A()`, the C3 order is `D → B → C → A`. The first visible match wins.
|
||||
- `private` is visible only inside the declaring class; `protected` is visible from the declaring class and any of its transitive subclasses. Qualialsofication (`this@Type`) or casts do not bypass visibility.
|
||||
- `private` is visible only inside the declaring class; `protected` is visible from the declaring class and its subclasses. Additionally, ancestors can access protected members of descendants if they override a member known to the ancestor. Qualification (`this@Type`) or casts do not bypass visibility.
|
||||
- Safe‑call `?.` works with `as?` for optional dispatch.
|
||||
|
||||
## Extension members
|
||||
|
||||
27
docs/wasm_generation_bug.md
Normal file
27
docs/wasm_generation_bug.md
Normal file
@ -0,0 +1,27 @@
|
||||
# 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.
|
||||
@ -24,6 +24,9 @@ class Person(private var _age: Int) {
|
||||
### Private and Protected Setters
|
||||
You can now restrict the visibility of a property's or field's setter using `private set` or `protected set`. This allows members to be publicly readable but only writable from within the declaring class or its subclasses.
|
||||
|
||||
### Refined Protected Visibility
|
||||
Ancestor classes can now access `protected` members of their descendants if it is an override of a member known to the ancestor. This enables base classes to call protected methods that are implemented or overridden in subclasses.
|
||||
|
||||
```lyng
|
||||
class Counter {
|
||||
var count = 0
|
||||
@ -168,6 +171,41 @@ settings["theme"] ?= "dark"
|
||||
|
||||
The operator returns the final value of the receiver (the original value if it was not `null`, or the new value if the assignment occurred).
|
||||
|
||||
### Transient Attribute (`@Transient`)
|
||||
The `@Transient` attribute can now be applied to class fields, constructor parameters, and static fields to exclude them from serialization.
|
||||
|
||||
```lyng
|
||||
class MyData(@Transient val tempSecret, val publicData) {
|
||||
@Transient var cachedValue = 0
|
||||
var persistentValue = 42
|
||||
}
|
||||
```
|
||||
|
||||
Key features:
|
||||
- **Serialization**: Transient members are omitted from both Lynon binary streams and JSON output.
|
||||
- **Structural Equality**: Transient fields are automatically ignored during `==` equality checks.
|
||||
- **Deserialization**: Transient constructor parameters with default values are correctly restored to those defaults upon restoration.
|
||||
|
||||
### Value Clamping (`clamp`)
|
||||
A new `clamp()` function has been added to the standard library to limit a value within a specified range. It is available as both a global function and an extension method on all objects.
|
||||
|
||||
```lyng
|
||||
// Global function
|
||||
clamp(15, 0..10) // returns 10
|
||||
clamp(-5, 0..10) // returns 0
|
||||
|
||||
// Extension method
|
||||
val x = 15
|
||||
x.clamp(0..10) // returns 10
|
||||
|
||||
// Exclusive and open-ended ranges
|
||||
15.clamp(0..<10) // returns 9
|
||||
15.clamp(..10) // returns 10
|
||||
-5.clamp(0..) // returns 0
|
||||
```
|
||||
|
||||
`clamp()` correctly handles inclusive (`..`) and exclusive (`..<`) ranges. For discrete types like `Int` and `Char`, clamping to an exclusive upper bound returns the previous value.
|
||||
|
||||
## Tooling and Infrastructure
|
||||
|
||||
### CLI: Formatting Command
|
||||
|
||||
@ -5,6 +5,7 @@ kotlin = "2.3.0"
|
||||
android-minSdk = "24"
|
||||
android-compileSdk = "34"
|
||||
kotlinx-coroutines = "1.10.2"
|
||||
kotlinx-datetime = "0.6.1"
|
||||
mp_bintools = "0.3.2"
|
||||
firebaseCrashlyticsBuildtools = "3.0.3"
|
||||
okioVersion = "3.10.2"
|
||||
@ -16,6 +17,7 @@ clikt-markdown = { module = "com.github.ajalt.clikt:clikt-markdown", version.ref
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
|
||||
mp_bintools = { module = "net.sergeych:mp_bintools", version.ref = "mp_bintools" }
|
||||
firebase-crashlytics-buildtools = { group = "com.google.firebase", name = "firebase-crashlytics-buildtools", version.ref = "firebaseCrashlyticsBuildtools" }
|
||||
okio = { module = "com.squareup.okio:okio", version.ref = "okioVersion" }
|
||||
|
||||
@ -139,7 +139,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
val e: Int = miniSource.offsetOf(d.range.end)
|
||||
if (offset >= s && offset <= e) {
|
||||
// For enum constant, we don't have detailed docs in MiniAst yet, but we can render a title
|
||||
return "<div class='doc-title'>enum constant ${d.name}.${name}</div>"
|
||||
return renderTitle("enum constant ${d.name}.${name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -361,7 +361,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
"Print values to the standard output and append a newline. Accepts any number of arguments." else
|
||||
"Print values to the standard output without a trailing newline. Accepts any number of arguments."
|
||||
val title = "function $ident(values)"
|
||||
return "<div class='doc-title'>${htmlEscape(title)}</div>" + styledMarkdown(htmlEscape(fallback))
|
||||
return renderTitle(title) + styledMarkdown(htmlEscape(fallback))
|
||||
}
|
||||
// 4b) try class members like ClassName.member with inheritance fallback
|
||||
val lhs = previousWordBefore(text, idRange.startOffset)
|
||||
@ -519,7 +519,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
}
|
||||
}
|
||||
val sb = StringBuilder()
|
||||
sb.append("<div class='doc-title'>").append(htmlEscape(title)).append("</div>")
|
||||
sb.append(renderTitle(title))
|
||||
sb.append(renderDocBody(d.doc))
|
||||
return sb.toString()
|
||||
}
|
||||
@ -527,7 +527,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
private fun renderParamDoc(fn: MiniFunDecl, p: MiniParam): String {
|
||||
val title = "parameter ${p.name}${typeOf(p.type)} in ${fn.name}${signatureOf(fn)}"
|
||||
val sb = StringBuilder()
|
||||
sb.append("<div class='doc-title'>").append(htmlEscape(title)).append("</div>")
|
||||
sb.append(renderTitle(title))
|
||||
|
||||
// Find matching @param tag
|
||||
fn.doc?.tags?.get("param")?.forEach { tag ->
|
||||
@ -549,7 +549,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
val staticStr = if (m.isStatic) "static " else ""
|
||||
val title = "${staticStr}method $className.${m.name}(${params})${ret}"
|
||||
val sb = StringBuilder()
|
||||
sb.append("<div class='doc-title'>").append(htmlEscape(title)).append("</div>")
|
||||
sb.append(renderTitle(title))
|
||||
sb.append(renderDocBody(m.doc))
|
||||
return sb.toString()
|
||||
}
|
||||
@ -560,7 +560,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
val staticStr = if (m.isStatic) "static " else ""
|
||||
val title = "${staticStr}${kind} $className.${m.name}${ts}"
|
||||
val sb = StringBuilder()
|
||||
sb.append("<div class='doc-title'>").append(htmlEscape(title)).append("</div>")
|
||||
sb.append(renderTitle(title))
|
||||
sb.append(renderDocBody(m.doc))
|
||||
return sb.toString()
|
||||
}
|
||||
@ -579,6 +579,10 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
return "(${params})${ret}"
|
||||
}
|
||||
|
||||
private fun renderTitle(title: String): String {
|
||||
return "<div class='doc-title' style='margin-bottom: 0.8em;'>${htmlEscape(title)}</div>"
|
||||
}
|
||||
|
||||
private fun htmlEscape(s: String): String = buildString(s.length) {
|
||||
for (ch in s) append(
|
||||
when (ch) {
|
||||
@ -645,7 +649,7 @@ class LyngDocumentationProvider : AbstractDocumentationProvider() {
|
||||
|
||||
private fun renderOverloads(name: String, overloads: List<MiniFunDecl>): String {
|
||||
val sb = StringBuilder()
|
||||
sb.append("<div class='doc-title'>Overloads for ").append(htmlEscape(name)).append("</div>")
|
||||
sb.append(renderTitle("Overloads for $name"))
|
||||
sb.append("<ul>")
|
||||
overloads.forEach { fn ->
|
||||
sb.append("<li><code>")
|
||||
|
||||
@ -121,12 +121,39 @@ class LyngLexer : LexerBase() {
|
||||
|
||||
// Number
|
||||
if (ch.isDigit()) {
|
||||
// Check for hex: 0x...
|
||||
if (ch == '0' && i + 1 < endOffset && buffer[i + 1] == 'x') {
|
||||
i += 2
|
||||
while (i < endOffset && (buffer[i].isDigit() || buffer[i] in 'a'..'f' || buffer[i] in 'A'..'F')) i++
|
||||
myTokenEnd = i
|
||||
myTokenType = LyngTokenTypes.NUMBER
|
||||
return
|
||||
}
|
||||
|
||||
// Decimal or integer
|
||||
i++
|
||||
var hasDot = false
|
||||
var hasE = false
|
||||
while (i < endOffset) {
|
||||
val c = buffer[i]
|
||||
if (c.isDigit()) { i++; continue }
|
||||
if (c == '.' && !hasDot) { hasDot = true; i++; continue }
|
||||
if (c.isDigit() || c == '_') {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (c == '.' && !hasDot && !hasE) {
|
||||
// Check if it's a fractional part (must be followed by a digit)
|
||||
if (i + 1 < endOffset && buffer[i + 1].isDigit()) {
|
||||
hasDot = true
|
||||
i++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ((c == 'e' || c == 'E') && !hasE) {
|
||||
hasE = true
|
||||
i++
|
||||
if (i < endOffset && (buffer[i] == '+' || buffer[i] == '-')) i++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
myTokenEnd = i
|
||||
@ -161,6 +188,35 @@ class LyngLexer : LexerBase() {
|
||||
// Punctuation
|
||||
if (isPunct(ch)) {
|
||||
i++
|
||||
// Handle common multi-char operators for better highlighting
|
||||
when (ch) {
|
||||
'.' -> {
|
||||
if (i < endOffset && buffer[i] == '.') {
|
||||
i++
|
||||
if (i < endOffset && (buffer[i] == '.' || buffer[i] == '<')) i++
|
||||
}
|
||||
}
|
||||
'=' -> {
|
||||
if (i < endOffset && (buffer[i] == '=' || buffer[i] == '>' || buffer[i] == '~')) {
|
||||
i++
|
||||
if (buffer[i - 1] == '=' && i < endOffset && buffer[i] == '=') i++
|
||||
}
|
||||
}
|
||||
'+', '-', '*', '/', '%', '!', '<', '>', '&', '|', '?', ':', '^' -> {
|
||||
if (i < endOffset) {
|
||||
val next = buffer[i]
|
||||
if (next == '=' || next == ch) {
|
||||
i++
|
||||
if (ch == '<' && next == '=' && i < endOffset && buffer[i] == '>') i++
|
||||
if (ch == '!' && next == '=' && i < endOffset && buffer[i] == '=') i++
|
||||
} else if (ch == '?' && (next == '.' || next == '[' || next == '(' || next == '{' || next == ':' || next == '?')) {
|
||||
i++
|
||||
} else if (ch == '-' && next == '>') {
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
myTokenEnd = i
|
||||
myTokenType = LyngTokenTypes.PUNCT
|
||||
return
|
||||
|
||||
@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
|
||||
// Removed legacy buildscript classpath declarations; plugins are applied via the plugins DSL below
|
||||
|
||||
@ -97,6 +97,7 @@ kotlin {
|
||||
kotlin.srcDir("$buildDir/generated/buildConfig/commonMain/kotlin")
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
|
||||
//put your multiplatform dependencies here
|
||||
api(libs.kotlinx.coroutines.core)
|
||||
api(libs.mp.bintools)
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
@ -71,7 +71,8 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
|
||||
value.byValueCopy(),
|
||||
a.visibility ?: defaultVisibility,
|
||||
recordType = ObjRecord.Type.Argument,
|
||||
declaringClass = declaringClass)
|
||||
declaringClass = declaringClass,
|
||||
isTransient = a.isTransient)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -82,7 +83,8 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
|
||||
value.byValueCopy(),
|
||||
a.visibility ?: defaultVisibility,
|
||||
recordType = ObjRecord.Type.Argument,
|
||||
declaringClass = declaringClass)
|
||||
declaringClass = declaringClass,
|
||||
isTransient = a.isTransient)
|
||||
}
|
||||
|
||||
// Prepare positional args and parameter count, handle tail-block binding
|
||||
@ -239,5 +241,6 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
|
||||
val defaultValue: Statement? = null,
|
||||
val accessType: AccessType? = null,
|
||||
val visibility: Visibility? = null,
|
||||
val isTransient: Boolean = false,
|
||||
)
|
||||
}
|
||||
@ -254,4 +254,3 @@ data class ParsedArgument(
|
||||
fun from(values: Collection<Obj>) = Arguments(values.toList())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
@ -54,14 +54,14 @@ class ClosureScope(val callScope: Scope, val closureScope: Scope) :
|
||||
for (cls in effectiveClass.mro) {
|
||||
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||
if (rec != null && !rec.isAbstract) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass ?: cls, currentClassCtx)) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass ?: cls, currentClassCtx, name)) {
|
||||
return rec.copy(receiver = receiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, root object fallback
|
||||
Obj.rootObjectType.members[name]?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx, name)) {
|
||||
return rec.copy(receiver = receiver)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -112,7 +112,7 @@ open class Scope(
|
||||
}
|
||||
}
|
||||
s.objects[name]?.let { rec ->
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller, name)) return rec
|
||||
}
|
||||
caller?.let { ctx ->
|
||||
s.localBindings[ctx.mangledName(name)]?.let { rec ->
|
||||
@ -120,11 +120,11 @@ open class Scope(
|
||||
}
|
||||
}
|
||||
s.localBindings[name]?.let { rec ->
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller, name)) return rec
|
||||
}
|
||||
s.getSlotIndexOf(name)?.let { idx ->
|
||||
val rec = s.getSlotRecord(idx)
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller)) return rec
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, caller, name)) return rec
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -163,7 +163,7 @@ open class Scope(
|
||||
this.extensions[cls]?.get(name)?.let { return it }
|
||||
}
|
||||
return thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx, name)) {
|
||||
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) null
|
||||
else rec
|
||||
} else null
|
||||
@ -186,7 +186,7 @@ open class Scope(
|
||||
s.extensions[cls]?.get(name)?.let { return it }
|
||||
}
|
||||
s.thisObj.objClass.getInstanceMemberOrNull(name)?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, caller)) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, caller, name)) {
|
||||
if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.Property || rec.isAbstract) {
|
||||
// ignore fields, properties and abstracts here, they will be handled by the caller via readField
|
||||
} else return rec
|
||||
@ -358,14 +358,14 @@ open class Scope(
|
||||
for (cls in effectiveClass.mro) {
|
||||
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||
if (rec != null && !rec.isAbstract) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass ?: cls, currentClassCtx)) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass ?: cls, currentClassCtx, name)) {
|
||||
return rec.copy(receiver = receiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, root object fallback
|
||||
Obj.rootObjectType.members[name]?.let { rec ->
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx)) {
|
||||
if (canAccessMember(rec.visibility, rec.declaringClass, currentClassCtx, name)) {
|
||||
return rec.copy(receiver = receiver)
|
||||
}
|
||||
}
|
||||
@ -392,6 +392,24 @@ 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.
|
||||
*/
|
||||
@ -503,6 +521,7 @@ 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)
|
||||
|
||||
@ -516,7 +535,8 @@ open class Scope(
|
||||
declaringClass: net.sergeych.lyng.obj.ObjClass? = currentClassCtx,
|
||||
isAbstract: Boolean = false,
|
||||
isClosed: Boolean = false,
|
||||
isOverride: Boolean = false
|
||||
isOverride: Boolean = false,
|
||||
isTransient: Boolean = false
|
||||
): ObjRecord {
|
||||
val rec = ObjRecord(
|
||||
value, isMutable, visibility, writeVisibility,
|
||||
@ -524,9 +544,28 @@ open class Scope(
|
||||
type = recordType,
|
||||
isAbstract = isAbstract,
|
||||
isClosed = isClosed,
|
||||
isOverride = isOverride
|
||||
isOverride = isOverride,
|
||||
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
|
||||
@ -556,6 +595,14 @@ 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
|
||||
|
||||
@ -20,10 +20,7 @@ package net.sergeych.lyng
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.yield
|
||||
import net.sergeych.lyng.Script.Companion.defaultImportManager
|
||||
import net.sergeych.lyng.miniast.addConstDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addVoidFnDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportManager
|
||||
import net.sergeych.lyng.stdlib_included.rootLyng
|
||||
@ -162,6 +159,42 @@ class Script(
|
||||
if (x is ObjInt) ObjInt(x.value.absoluteValue) else ObjReal(x.toDouble().absoluteValue)
|
||||
}
|
||||
|
||||
addFnDoc(
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
addVoidFn("assert") {
|
||||
val cond = requiredArg<ObjBool>(0)
|
||||
val message = if (args.size > 1)
|
||||
@ -399,6 +432,12 @@ class Script(
|
||||
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,
|
||||
|
||||
@ -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.
|
||||
@ -25,7 +25,12 @@ enum class Visibility {
|
||||
}
|
||||
|
||||
/** MI-aware visibility check: whether [caller] can access a member declared in [decl] with [visibility]. */
|
||||
fun canAccessMember(visibility: Visibility, decl: net.sergeych.lyng.obj.ObjClass?, caller: net.sergeych.lyng.obj.ObjClass?): Boolean {
|
||||
fun canAccessMember(
|
||||
visibility: Visibility,
|
||||
decl: net.sergeych.lyng.obj.ObjClass?,
|
||||
caller: net.sergeych.lyng.obj.ObjClass?,
|
||||
name: String? = null
|
||||
): Boolean {
|
||||
val res = when (visibility) {
|
||||
Visibility.Public -> true
|
||||
Visibility.Private -> (decl != null && caller === decl)
|
||||
@ -33,7 +38,14 @@ fun canAccessMember(visibility: Visibility, decl: net.sergeych.lyng.obj.ObjClass
|
||||
decl == null -> false
|
||||
caller == null -> false
|
||||
caller === decl -> true
|
||||
else -> (caller.allParentsSet.contains(decl))
|
||||
caller.allParentsSet.contains(decl) -> true
|
||||
name != null && decl.allParentsSet.contains(caller) -> {
|
||||
// Ancestor can access protected member of its descendant if it also has this member
|
||||
// (i.e. it's an override of something the ancestor knows about)
|
||||
val existing = caller.getInstanceMemberOrNull(name, includeAbstract = true)
|
||||
existing != null && (existing.visibility == Visibility.Protected || existing.visibility == Visibility.Public)
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
||||
@ -108,8 +108,9 @@ object LyngFormatter {
|
||||
if (t == "finally") return true
|
||||
|
||||
// Short definition form: fun x() = or val x =
|
||||
if (Regex("^(override\\s+)?(fun|fn)\\b.*=\\s*$").matches(t)) return true
|
||||
if (Regex("^(private\\s+|protected\\s+|public\\s+|override\\s+)?(val|var)\\b.*=\\s*$").matches(t)) return true
|
||||
// We allow optional 'static' as well
|
||||
if (Regex("^(static\\s+)?(override\\s+)?(fun|fn)\\b.*=\\s*$").matches(t)) return true
|
||||
if (Regex("^(static\\s+)?(private\\s+|protected\\s+|public\\s+|override\\s+)?(val|var)\\b.*=\\s*$").matches(t)) return true
|
||||
|
||||
// property accessors ending with ) or =
|
||||
if (isAccessorRelated(t)) {
|
||||
@ -122,7 +123,8 @@ object LyngFormatter {
|
||||
val t = s.trim()
|
||||
if (!t.endsWith("=")) return false
|
||||
// Is it a function or property definition?
|
||||
if (Regex("\\b(fun|fn|val|var)\\b").containsMatchIn(t)) return true
|
||||
// (Note: we exclude 'static' here to avoid double indent if it's already handled)
|
||||
if (Regex("^(override\\s+)?(fun|fn|val|var)\\b").containsMatchIn(t)) return true
|
||||
// Is it an accessor?
|
||||
if (isPropertyAccessor(t)) return true
|
||||
return false
|
||||
|
||||
@ -44,13 +44,22 @@ data class MiniDoc(
|
||||
fun parse(range: MiniRange, lines: Iterable<String>, extraTags: Map<String, List<String>> = emptyMap()): MiniDoc {
|
||||
val parsedTags = mutableMapOf<String, MutableList<String>>()
|
||||
var currentTag: String? = null
|
||||
val currentContent = StringBuilder()
|
||||
val currentContent = mutableListOf<String>()
|
||||
|
||||
fun flush() {
|
||||
currentTag?.let { tag ->
|
||||
parsedTags.getOrPut(tag) { mutableListOf() }.add(currentContent.toString().trim())
|
||||
val trimmedContent = if (currentContent.size > 1) {
|
||||
// First line is common content, we want to trim indent from subsequent lines
|
||||
// based on THEIR common indent.
|
||||
val firstLine = currentContent[0]
|
||||
val remaining = currentContent.drop(1).joinToString("\n").trimIndent()
|
||||
if (remaining.isEmpty()) firstLine else firstLine + "\n" + remaining
|
||||
} else {
|
||||
currentContent.joinToString("\n")
|
||||
}
|
||||
currentContent.setLength(0)
|
||||
parsedTags.getOrPut(tag) { mutableListOf() }.add(trimmedContent.trim())
|
||||
}
|
||||
currentContent.clear()
|
||||
}
|
||||
|
||||
val descriptionLines = mutableListOf<String>()
|
||||
@ -58,26 +67,38 @@ data class MiniDoc(
|
||||
|
||||
for (rawLine in lines) {
|
||||
for (line in rawLine.lines()) {
|
||||
val trimmed = line.trim()
|
||||
// Strip leading '*' and space if present (standard doc comment style)
|
||||
val cleanedLine = line.trim().let {
|
||||
if (it.startsWith("*")) it.substring(1).removePrefix(" ") else line
|
||||
}
|
||||
val trimmed = cleanedLine.trim()
|
||||
if (trimmed.startsWith("@")) {
|
||||
inTags = true
|
||||
flush()
|
||||
val parts = trimmed.substring(1).split(Regex("\\s+"), 2)
|
||||
currentTag = parts[0]
|
||||
currentContent.append(parts.getOrNull(1) ?: "")
|
||||
val tagFirstLine = parts.getOrNull(1) ?: ""
|
||||
if (tagFirstLine.isNotEmpty()) {
|
||||
// Find where the content starts in the cleaned line to preserve relative indentation
|
||||
val contentIndex = cleanedLine.indexOf(tagFirstLine)
|
||||
if (contentIndex >= 0) {
|
||||
currentContent.add(cleanedLine.substring(contentIndex))
|
||||
} else {
|
||||
currentContent.add(tagFirstLine)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (inTags) {
|
||||
if (currentContent.isNotEmpty()) currentContent.append("\n")
|
||||
currentContent.append(line)
|
||||
currentContent.add(cleanedLine)
|
||||
} else {
|
||||
descriptionLines.add(line)
|
||||
descriptionLines.add(cleanedLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
flush()
|
||||
|
||||
val raw = descriptionLines.joinToString("\n").trimEnd()
|
||||
val raw = descriptionLines.joinToString("\n").trimIndent().trim()
|
||||
val summary = raw.lines().firstOrNull { it.isNotBlank() }?.trim()
|
||||
|
||||
val finalTags = parsedTags.toMutableMap()
|
||||
|
||||
@ -113,7 +113,7 @@ open class Obj {
|
||||
if (rec != null && !rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
@ -140,7 +140,7 @@ open class Obj {
|
||||
cls.members[name]?.let { rec ->
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke ${name}: not visible (declared in ${decl.className}, caller ${caller?.className ?: "?"})"))
|
||||
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
@ -429,10 +429,10 @@ open class Obj {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Lyng object to its Kotlin counterpart
|
||||
* Convert a Lyng object to its Kotlin counterpart
|
||||
*/
|
||||
open suspend fun toKotlin(scope: Scope): Any? {
|
||||
return toString()
|
||||
return toString(scope).value
|
||||
}
|
||||
|
||||
fun willMutate(scope: Scope) {
|
||||
@ -482,7 +482,7 @@ open class Obj {
|
||||
cls.members[name]?.let { rec ->
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
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)
|
||||
@ -501,9 +501,8 @@ 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
|
||||
val res = del.invokeInstanceMethod(scope, "getValue", Arguments(th, ObjString(name)), onNotFoundResult = {
|
||||
// If getValue not found, return a wrapper that calls invoke
|
||||
object : Statement() {
|
||||
if (del.objClass.getInstanceMemberOrNull("getValue") == null) {
|
||||
val wrapper = 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
|
||||
@ -511,7 +510,12 @@ open class Obj {
|
||||
return del.invokeInstanceMethod(s, "invoke", 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
|
||||
@ -526,7 +530,7 @@ open class Obj {
|
||||
}
|
||||
val caller = scope.currentClassCtx
|
||||
// Check visibility for non-property members here if they weren't checked before
|
||||
if (!canAccessMember(obj.visibility, decl, caller))
|
||||
if (!canAccessMember(obj.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access field ${name}: not visible (declared in ${decl?.className ?: "?"}, caller ${caller?.className ?: "?"})"))
|
||||
return obj
|
||||
}
|
||||
@ -574,7 +578,7 @@ open class Obj {
|
||||
|
||||
val decl = field.declaringClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(field.effectiveWriteVisibility, decl, caller))
|
||||
if (!canAccessMember(field.effectiveWriteVisibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't assign field ${name}: not visible (declared in ${decl?.className ?: "?"}, caller ${caller?.className ?: "?"})"))
|
||||
if (field.type == ObjRecord.Type.Delegated) {
|
||||
val del = field.delegate ?: scope.raiseError("Internal error: delegated property $name has no delegate")
|
||||
@ -760,6 +764,38 @@ open class Obj {
|
||||
) {
|
||||
thisObj.toJson(this).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)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -17,16 +17,24 @@
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import net.sergeych.lyng.*
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
|
||||
// Simple id generator for class identities (not thread-safe; fine for scripts)
|
||||
private object ClassIdGen { var c: Long = 1L; fun nextId(): Long = c++ }
|
||||
|
||||
val ObjClassType by lazy {
|
||||
ObjClass("Class").apply {
|
||||
object : ObjClass("Class") {
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
val name = decoder.decodeObject(scope, ObjString.type, null) as ObjString
|
||||
return scope.resolveQualifiedIdentifier(name.value)
|
||||
}
|
||||
}.apply {
|
||||
addPropertyDoc(
|
||||
name = "className",
|
||||
doc = "Full name of this class including package if available.",
|
||||
@ -106,8 +114,7 @@ open class ObjClass(
|
||||
val classId: Long = ClassIdGen.nextId()
|
||||
var layoutVersion: Int = 0
|
||||
|
||||
private val mangledNameCache = mutableMapOf<String, String>()
|
||||
fun mangledName(name: String): String = mangledNameCache.getOrPut(name) { "$className::$name" }
|
||||
fun mangledName(name: String): String = "$className::$name"
|
||||
|
||||
/**
|
||||
* Map of public member names to their effective storage keys in instanceScope.objects.
|
||||
@ -120,7 +127,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.Delegated) cls.mangledName(name) else name
|
||||
val key = if (rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField || rec.type == ObjRecord.Type.Delegated) cls.mangledName(name) else name
|
||||
res[name] = key
|
||||
}
|
||||
}
|
||||
@ -259,6 +266,119 @@ 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
|
||||
@ -276,8 +396,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)) {
|
||||
val key = if (v.visibility == Visibility.Private || v.type == ObjRecord.Type.Field || 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 || 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 (!res.containsKey(key)) {
|
||||
res[key] = v
|
||||
}
|
||||
@ -319,12 +439,47 @@ 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) {
|
||||
instance.instanceScope.objects[p.first] = p.second.copy()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance
|
||||
}
|
||||
@ -409,6 +564,10 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -451,6 +610,7 @@ open class ObjClass(
|
||||
isAbstract: Boolean = false,
|
||||
isClosed: Boolean = false,
|
||||
isOverride: Boolean = false,
|
||||
isTransient: Boolean = false,
|
||||
type: ObjRecord.Type = ObjRecord.Type.Field,
|
||||
): ObjRecord {
|
||||
// Validation of override rules: only for non-system declarations
|
||||
@ -461,7 +621,7 @@ open class ObjClass(
|
||||
if (existing != null && existing.declaringClass != this) {
|
||||
// If the existing member is private in the ancestor, it's not visible for overriding.
|
||||
// It should be treated as a new member in this class.
|
||||
if (!existing.visibility.isPublic && !canAccessMember(existing.visibility, existing.declaringClass, this)) {
|
||||
if (!existing.visibility.isPublic && !canAccessMember(existing.visibility, existing.declaringClass, this, name)) {
|
||||
// It's effectively not there for us, so actualOverride remains false
|
||||
} else {
|
||||
actualOverride = true
|
||||
@ -494,6 +654,7 @@ open class ObjClass(
|
||||
isAbstract = isAbstract,
|
||||
isClosed = isClosed,
|
||||
isOverride = isOverride,
|
||||
isTransient = isTransient,
|
||||
type = type
|
||||
)
|
||||
members[name] = rec
|
||||
@ -514,13 +675,14 @@ open class ObjClass(
|
||||
visibility: Visibility = Visibility.Public,
|
||||
writeVisibility: Visibility? = null,
|
||||
pos: Pos = Pos.builtIn,
|
||||
isTransient: Boolean = false,
|
||||
type: ObjRecord.Type = ObjRecord.Type.Field
|
||||
): ObjRecord {
|
||||
initClassScope()
|
||||
val existing = classScope!!.objects[name]
|
||||
if (existing != null)
|
||||
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||
val rec = classScope!!.addItem(name, isMutable, initialValue, visibility, writeVisibility, recordType = type)
|
||||
val rec = classScope!!.addItem(name, isMutable, initialValue, visibility, writeVisibility, recordType = type, isTransient = isTransient)
|
||||
// Structural change: bump layout version for PIC invalidation
|
||||
layoutVersion += 1
|
||||
return rec
|
||||
@ -707,9 +869,23 @@ open class ObjClass(
|
||||
return super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
}
|
||||
|
||||
override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) {
|
||||
if (isAnonymous) scope.raiseError("Cannot serialize anonymous class")
|
||||
encoder.encodeObject(scope, classNameObj, ObjString.type.lynonType())
|
||||
}
|
||||
|
||||
override suspend fun toJson(scope: Scope): JsonElement {
|
||||
val result = mutableMapOf<String, JsonElement>()
|
||||
result["__class_name"] = classNameObj.toJson(scope)
|
||||
classScope?.objects?.forEach { (name, rec) ->
|
||||
if (rec.type.serializable && rec.visibility.isPublic && !rec.isTransient) {
|
||||
result[name] = rec.value.toJson(scope)
|
||||
}
|
||||
}
|
||||
return JsonObject(result)
|
||||
}
|
||||
|
||||
open suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj =
|
||||
scope.raiseNotImplemented()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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.obj
|
||||
|
||||
import kotlinx.datetime.*
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.miniast.addClassFnDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
import net.sergeych.lyng.miniast.type
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
|
||||
class ObjDateTime(val instant: Instant, val timeZone: TimeZone) : Obj() {
|
||||
override val objClass: ObjClass get() = type
|
||||
|
||||
val localDateTime: LocalDateTime by lazy {
|
||||
instant.toLocalDateTime(timeZone)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return localDateTime.toString() + timeZone.toString()
|
||||
}
|
||||
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
for (cls in objClass.mro) {
|
||||
val rec = cls.members[name]
|
||||
if (rec != null) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
val prop = rec.value as? ObjProperty
|
||||
?: (rec.value as? Statement)?.execute(scope) as? ObjProperty
|
||||
if (prop != null) {
|
||||
return ObjRecord(prop.callGetter(scope, this, rec.declaringClass ?: cls), rec.isMutable)
|
||||
}
|
||||
}
|
||||
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 resolveRecord(scope, rec, name, rec.declaringClass ?: cls)
|
||||
}
|
||||
}
|
||||
return super.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun plus(scope: Scope, other: Obj): Obj {
|
||||
return when (other) {
|
||||
is ObjDuration -> ObjDateTime(instant + other.duration, timeZone)
|
||||
else -> super.plus(scope, other)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun minus(scope: Scope, other: Obj): Obj {
|
||||
return when (other) {
|
||||
is ObjDuration -> ObjDateTime(instant - other.duration, timeZone)
|
||||
is ObjDateTime -> ObjDuration(instant - other.instant)
|
||||
is ObjInstant -> ObjDuration(instant - other.instant)
|
||||
else -> super.minus(scope, other)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if (other is ObjDateTime) {
|
||||
return instant.compareTo(other.instant)
|
||||
}
|
||||
if (other is ObjInstant) {
|
||||
return instant.compareTo(other.instant)
|
||||
}
|
||||
return super.compareTo(scope, other)
|
||||
}
|
||||
|
||||
override suspend fun toKotlin(scope: Scope): Any {
|
||||
return localDateTime
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return instant.hashCode() xor timeZone.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is ObjDateTime) return false
|
||||
return instant == other.instant && timeZone == other.timeZone
|
||||
}
|
||||
|
||||
override suspend fun lynonType(): LynonType = LynonType.Other
|
||||
|
||||
override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) {
|
||||
encoder.encodeCached(this) {
|
||||
encodeAny(scope, ObjInstant(instant))
|
||||
encodeCached(timeZone.id) {
|
||||
encodeBinaryData(timeZone.id.encodeToByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun toJson(scope: Scope): JsonElement = JsonPrimitive(toRFC3339())
|
||||
|
||||
fun toRFC3339(): String {
|
||||
val s = localDateTime.toString()
|
||||
val tz = if (timeZone == TimeZone.UTC) "Z" else timeZone.id
|
||||
return if (tz.startsWith("+") || tz.startsWith("-") || tz == "Z") s + tz else s + "[" + tz + "]"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val type = object : ObjClass("DateTime") {
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
val args = scope.args
|
||||
return when (val a0 = args.list.getOrNull(0)) {
|
||||
is ObjInstant -> {
|
||||
val tz = when (val a1 = args.list.getOrNull(1)) {
|
||||
null -> TimeZone.currentSystemDefault()
|
||||
is ObjString -> TimeZone.of(a1.value)
|
||||
is ObjInt -> UtcOffset(seconds = a1.value.toInt()).asTimeZone()
|
||||
else -> scope.raiseIllegalArgument("invalid timezone: $a1")
|
||||
}
|
||||
ObjDateTime(a0.instant, tz)
|
||||
}
|
||||
|
||||
is ObjInt -> {
|
||||
// DateTime(year, month, day, hour=0, minute=0, second=0, timeZone="UTC")
|
||||
val year = a0.value.toInt()
|
||||
val month = args.list.getOrNull(1)?.toInt() ?: scope.raiseIllegalArgument("month is required")
|
||||
val day = args.list.getOrNull(2)?.toInt() ?: scope.raiseIllegalArgument("day is required")
|
||||
val hour = args.list.getOrNull(3)?.toInt() ?: 0
|
||||
val minute = args.list.getOrNull(4)?.toInt() ?: 0
|
||||
val second = args.list.getOrNull(5)?.toInt() ?: 0
|
||||
val tz = when (val a6 = args.list.getOrNull(6)) {
|
||||
null -> TimeZone.UTC
|
||||
is ObjString -> TimeZone.of(a6.value)
|
||||
is ObjInt -> UtcOffset(seconds = a6.value.toInt()).asTimeZone()
|
||||
else -> scope.raiseIllegalArgument("invalid timezone: $a6")
|
||||
}
|
||||
val ldt = LocalDateTime(year, month, day, hour, minute, second)
|
||||
ObjDateTime(ldt.toInstant(tz), tz)
|
||||
}
|
||||
|
||||
is ObjString -> {
|
||||
val instant = Instant.parse(a0.value)
|
||||
ObjDateTime(instant, TimeZone.UTC)
|
||||
}
|
||||
|
||||
else -> scope.raiseIllegalArgument("can't construct DateTime from ${args.inspect(scope)}")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
return decoder.decodeCached {
|
||||
val instant = (decoder.decodeAny(scope) as ObjInstant).instant
|
||||
val tzId = decoder.decodeCached { decoder.unpackBinaryData().decodeToString() }
|
||||
ObjDateTime(instant, TimeZone.of(tzId))
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
addPropertyDoc("year", "The year component.", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.year.toObj() })
|
||||
addPropertyDoc("month", "The month component (1..12).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.monthNumber.toObj() })
|
||||
addPropertyDoc("dayOfMonth", "The day of month component.", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.dayOfMonth.toObj() })
|
||||
addPropertyDoc("day", "Alias to dayOfMonth.", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.dayOfMonth.toObj() })
|
||||
addPropertyDoc("hour", "The hour component (0..23).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.hour.toObj() })
|
||||
addPropertyDoc("minute", "The minute component (0..59).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { thisAs<ObjDateTime>().localDateTime.minute.toObj() })
|
||||
addPropertyDoc("second", "The second component (0..59).", type("lyng.Int"), moduleName = "lyng.time",
|
||||
getter = { 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() })
|
||||
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() })
|
||||
|
||||
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("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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
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 {
|
||||
TimeZone.UTC
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
TimeZone.UTC
|
||||
}
|
||||
|
||||
ObjDateTime(instant, tz)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,36 @@ 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
|
||||
@ -37,6 +67,16 @@ 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)
|
||||
@ -56,6 +96,16 @@ 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)
|
||||
@ -67,8 +117,18 @@ 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 ((scope.thisObj === this && caller != null) || canAccessMember(rec.visibility, cls, caller)) {
|
||||
if (canAccessMember(rec.visibility, cls, caller, name)) {
|
||||
return resolveRecord(scope, rec, name, cls)
|
||||
}
|
||||
}
|
||||
@ -77,8 +137,13 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// 2. Unmangled storage
|
||||
instanceScope.objects[name]?.let { rec ->
|
||||
val decl = rec.declaringClass
|
||||
// Unmangled access is only allowed if it's public OR we are inside the same instance's method
|
||||
if ((scope.thisObj === this && caller != null) || canAccessMember(rec.visibility, decl, caller)) {
|
||||
if (canAccessMember(rec.visibility, decl, caller, name)) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -110,10 +175,15 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetRec === obj) {
|
||||
instanceScope.objects[name]?.let { rec ->
|
||||
// Check if this record in instanceScope is the one we want.
|
||||
@ -135,10 +205,29 @@ 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.isMutable && !rec.isAbstract) {
|
||||
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
|
||||
@ -161,6 +250,19 @@ 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)
|
||||
@ -173,8 +275,21 @@ 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 ((scope.thisObj === this && caller != null) || canAccessMember(rec.effectiveWriteVisibility, cls, caller)) {
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, cls, caller, name)) {
|
||||
updateRecord(scope, rec, name, newValue, cls)
|
||||
return
|
||||
}
|
||||
@ -184,7 +299,15 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// 2. Unmangled storage
|
||||
instanceScope.objects[name]?.let { rec ->
|
||||
val decl = rec.declaringClass
|
||||
if ((scope.thisObj === this && caller != null) || canAccessMember(rec.effectiveWriteVisibility, decl, caller)) {
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
updateRecord(scope, rec, name, newValue, decl)
|
||||
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
|
||||
}
|
||||
@ -226,6 +349,16 @@ 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 ->
|
||||
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
|
||||
@ -242,6 +375,15 @@ 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) {
|
||||
@ -262,13 +404,23 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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. 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 = cls.mangledName(name)
|
||||
val storageName = decl.mangledName(name)
|
||||
val del = instanceScope[storageName]?.delegate ?: rec.delegate
|
||||
?: scope.raiseError("Internal error: delegated member $name has no delegate (tried $storageName)")
|
||||
|
||||
@ -277,12 +429,11 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
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 ?: cls)
|
||||
propVal.invoke(scope, this, args, rec.declaringClass ?: decl)
|
||||
})
|
||||
}
|
||||
val decl = rec.declaringClass ?: cls
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === this) objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller))
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
@ -304,7 +455,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
return resolved.value.invoke(scope, this, args, resolved.declaringClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fall back to super (handles extensions and root fallback)
|
||||
return super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||
@ -339,7 +489,7 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
// values, so we save size of the construction:
|
||||
|
||||
// using objlist allow for some optimizations:
|
||||
val params = meta.params.map { readField(scope, it.name).value }
|
||||
val params = meta.params.filter { !it.isTransient }.map { readField(scope, it.name).value }
|
||||
encoder.encodeAnyList(scope, params)
|
||||
val vars = serializingVars.values.map { it.value }
|
||||
if (vars.isNotEmpty()) {
|
||||
@ -358,8 +508,10 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
val result = mutableMapOf<String, JsonElement>()
|
||||
val meta = objClass.constructorMeta
|
||||
?: scope.raiseError("can't serialize non-serializable object (no constructor meta)")
|
||||
for (entry in meta.params)
|
||||
for (entry in meta.params) {
|
||||
if (!entry.isTransient)
|
||||
result[entry.name] = readField(scope, entry.name).value.toJson(scope)
|
||||
}
|
||||
for (i in serializingVars) {
|
||||
// remove T:: prefix from the field name for JSON
|
||||
val parts = i.key.split("::")
|
||||
@ -378,7 +530,8 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
it.value.type.serializable &&
|
||||
it.value.type == ObjRecord.Type.Field &&
|
||||
it.value.isMutable &&
|
||||
!metaParams.contains(it.key)
|
||||
!metaParams.contains(it.key) &&
|
||||
!it.value.isTransient
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,7 +552,7 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
|
||||
protected val comparableVars: Map<String, ObjRecord> by lazy {
|
||||
instanceScope.objects.filter {
|
||||
it.value.type.comparable && (it.value.type != ObjRecord.Type.Field || it.value.isMutable)
|
||||
it.value.type.comparable && (it.value.type != ObjRecord.Type.Field || it.value.isMutable) && !it.value.isTransient
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,11 +582,19 @@ 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
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
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)
|
||||
}
|
||||
@ -442,7 +603,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
instance.instanceScope[name]?.let { rec ->
|
||||
val decl = rec.declaringClass ?: instance.objClass.findDeclaringClassOf(name)
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
@ -456,7 +617,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
val r = memberFromAncestor(name) ?: scope.raiseError("no such field: $name")
|
||||
val decl = r.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(r.visibility, decl, caller))
|
||||
if (!canAccessMember(r.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't access field $name (declared in ${decl.className})"))
|
||||
|
||||
return instance.resolveRecord(scope, r, name, decl)
|
||||
@ -465,10 +626,22 @@ 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
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller))
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't assign to field $name (declared in ${decl.className})"
|
||||
@ -482,7 +655,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
instance.instanceScope[name]?.let { f ->
|
||||
val decl = f.declaringClass ?: instance.objClass.findDeclaringClassOf(name)
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller))
|
||||
if (!canAccessMember(f.effectiveWriteVisibility, decl, caller, name))
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
"can't assign to field $name (declared in ${decl?.className ?: "?"})"
|
||||
@ -495,7 +668,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
val r = memberFromAncestor(name) ?: scope.raiseError("no such field: $name")
|
||||
val decl = r.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(r.effectiveWriteVisibility, decl, caller))
|
||||
if (!canAccessMember(r.effectiveWriteVisibility, decl, caller, name))
|
||||
ObjIllegalAccessException(scope, "can't assign to field $name (declared in ${decl.className})").raise()
|
||||
if (!r.isMutable) scope.raiseError("can't assign to read-only field: $name")
|
||||
if (r.value.assign(scope, newValue) == null) r.value = newValue
|
||||
@ -511,7 +684,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
memberFromAncestor(name)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: startClass
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method $name (declared in ${decl.className})"))
|
||||
val saved = instance.instanceScope.currentClassCtx
|
||||
instance.instanceScope.currentClassCtx = decl
|
||||
@ -526,7 +699,7 @@ class ObjQualifiedView(val instance: ObjInstance, private val startClass: ObjCla
|
||||
instance.instanceScope[name]?.let { rec ->
|
||||
val decl = rec.declaringClass ?: instance.objClass.findDeclaringClassOf(name)
|
||||
val caller = scope.currentClassCtx
|
||||
if (!canAccessMember(rec.visibility, decl, caller))
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name))
|
||||
scope.raiseError(
|
||||
ObjIllegalAccessException(
|
||||
scope,
|
||||
|
||||
@ -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.
|
||||
@ -28,13 +28,26 @@ import net.sergeych.lynon.LynonType
|
||||
class ObjInstanceClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
||||
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
val args = decoder.decodeAnyList(scope)
|
||||
val actualSize = constructorMeta?.params?.size ?: 0
|
||||
if (args.size > actualSize)
|
||||
scope.raiseIllegalArgument("constructor $name has only $actualSize but serialized version has ${args.size}")
|
||||
val newScope = scope.createChildScope(args = Arguments(args))
|
||||
val instance = createInstance(newScope)
|
||||
initializeInstance(instance, newScope.args, runConstructors = false)
|
||||
val serializedArgs = decoder.decodeAnyList(scope)
|
||||
val meta = constructorMeta ?: scope.raiseError("no constructor meta for $name")
|
||||
val nonTransientCount = meta.params.count { !it.isTransient }
|
||||
if (serializedArgs.size != nonTransientCount)
|
||||
scope.raiseIllegalArgument("constructor $name expects $nonTransientCount non-transient arguments, but serialized version has ${serializedArgs.size}")
|
||||
|
||||
var sIdx = 0
|
||||
val namedArgs = mutableMapOf<String, Obj>()
|
||||
for (p in meta.params) {
|
||||
if (!p.isTransient) {
|
||||
namedArgs[p.name] = serializedArgs[sIdx++]
|
||||
} else if (p.defaultValue == null) {
|
||||
// If transient parameter has no default value, we use ObjNull to avoid "too few arguments" error
|
||||
namedArgs[p.name] = ObjNull
|
||||
}
|
||||
}
|
||||
// Using named arguments allows the constructor to apply default values for transient parameters
|
||||
val newArgs = Arguments(list = emptyList<Obj>(), named = namedArgs)
|
||||
val instance = createInstance(scope.createChildScope(args = newArgs))
|
||||
initializeInstance(instance, newArgs, runConstructors = false)
|
||||
return instance.apply {
|
||||
deserializeStateVars(scope, decoder)
|
||||
invokeInstanceMethod(scope, "onDeserialized") { ObjVoid }
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.datetime.*
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import net.sergeych.lyng.Scope
|
||||
@ -28,7 +29,6 @@ import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonSettings
|
||||
import net.sergeych.lynon.LynonType
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
import kotlin.time.isDistantFuture
|
||||
import kotlin.time.isDistantPast
|
||||
|
||||
@ -122,6 +122,7 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
val nanos = (a0.value - seconds) * 1e9
|
||||
Instant.fromEpochSeconds(seconds, nanos.toLong())
|
||||
}
|
||||
is ObjString -> Instant.parse(a0.value)
|
||||
is ObjInstant -> a0.instant
|
||||
|
||||
else -> {
|
||||
@ -189,6 +190,18 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
moduleName = "lyng.time",
|
||||
getter = { ObjInt(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)
|
||||
}
|
||||
addFnDoc(
|
||||
name = "truncateToSecond",
|
||||
doc = "Truncate this instant to the nearest second.",
|
||||
@ -222,6 +235,43 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
||||
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()
|
||||
}
|
||||
|
||||
addFnDoc(
|
||||
name = "toSortableString",
|
||||
doc = "Alias to toRFC3339.",
|
||||
returns = type("lyng.String"),
|
||||
moduleName = "lyng.time"
|
||||
) {
|
||||
thisAs<ObjInstant>().instant.toString().toObj()
|
||||
}
|
||||
|
||||
addFnDoc(
|
||||
name = "toDateTime",
|
||||
doc = "Convert this absolute instant to a localized DateTime object in the specified time zone. " +
|
||||
"Accepts a timezone ID string (e.g., 'UTC', '+02:00') or an integer offset in seconds. " +
|
||||
"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")
|
||||
}
|
||||
ObjDateTime(thisAs<ObjInstant>().instant, tz)
|
||||
}
|
||||
|
||||
// class members
|
||||
|
||||
addClassConst("distantFuture", distantFuture)
|
||||
|
||||
@ -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()
|
||||
@ -159,13 +163,19 @@ class ObjInt(val value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val cache = Array(256) { ObjInt((it - 128).toLong(), true) }
|
||||
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)
|
||||
}
|
||||
|
||||
fun of(value: Long): ObjInt {
|
||||
return if (value in -128L..127L) cache[(value + 128).toInt()]
|
||||
return if (value in CACHE_LOW..CACHE_HIGH) cache[(value - CACHE_LOW).toInt()]
|
||||
else ObjInt(value)
|
||||
}
|
||||
|
||||
internal fun cacheArray(): Array<ObjInt> = cache
|
||||
|
||||
val Zero = of(0)
|
||||
val One = of(1)
|
||||
val type = object : ObjClass("Int") {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -58,7 +58,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(x)
|
||||
if (isCharRange) ObjChar(x.toInt().toChar()) else ObjInt.of(x)
|
||||
}
|
||||
else {
|
||||
scope.raiseError(ObjIterationFinishedException(scope))
|
||||
@ -83,13 +83,18 @@ 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) ObjInt(cur++.toLong())
|
||||
if (cur < endExclusive) {
|
||||
if (useCache && cache != null) cache[cur++ - cacheLow] else ObjInt(cur++.toLong())
|
||||
}
|
||||
else scope.raiseError(ObjIterationFinishedException(scope))
|
||||
|
||||
companion object {
|
||||
|
||||
@ -152,6 +152,80 @@ 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 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) {
|
||||
@ -381,7 +455,7 @@ class CastRef(
|
||||
}
|
||||
|
||||
/** Qualified `this@Type`: resolves to a view of current `this` starting dispatch from the ancestor Type. */
|
||||
class QualifiedThisRef(private val typeName: String, private val atPos: Pos) : ObjRef {
|
||||
class QualifiedThisRef(val typeName: String, private val atPos: Pos) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
val t = scope[typeName]?.value as? ObjClass
|
||||
?: scope.raiseError("unknown type $typeName")
|
||||
@ -403,6 +477,188 @@ class QualifiedThisRef(private val typeName: String, private val atPos: Pos) : O
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun resolveQualifiedThisInstance(scope: Scope, typeName: String): Pair<ObjInstance, ObjClass> {
|
||||
val t = scope[typeName]?.value as? ObjClass
|
||||
?: scope.raiseError("unknown type $typeName")
|
||||
var s: Scope? = scope
|
||||
while (s != null) {
|
||||
val inst = s.thisObj as? ObjInstance
|
||||
if (inst != null && (inst.objClass === t || inst.objClass.allParentsSet.contains(t))) {
|
||||
return inst to t
|
||||
}
|
||||
s = s.parent
|
||||
}
|
||||
scope.raiseClassCastError(
|
||||
"No instance of type ${t.className} found in the scope chain"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this@Type.name` access using slot maps when possible.
|
||||
*/
|
||||
class QualifiedThisFieldSlotRef(
|
||||
private val typeName: String,
|
||||
val name: String,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
val (inst, startClass) = resolveQualifiedThisInstance(scope, typeName)
|
||||
if (isOptional && inst == ObjNull) return ObjNull.asMutable
|
||||
|
||||
if (startClass !== inst.objClass) {
|
||||
return ObjQualifiedView(inst, startClass).readField(scope, name)
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
inst.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return inst.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
inst.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return inst.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = inst.objClass.publicMemberResolution[name] ?: name
|
||||
inst.fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
inst.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: inst.objClass.findDeclaringClassOf(name) ?: inst.objClass
|
||||
return inst.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
|
||||
return inst.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
val (inst, startClass) = resolveQualifiedThisInstance(scope, typeName)
|
||||
if (isOptional && inst == ObjNull) return
|
||||
|
||||
if (startClass !== inst.objClass) {
|
||||
ObjQualifiedView(inst, startClass).writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
inst.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
writeDirectOrFallback(scope, inst, rec, name, newValue, caller)
|
||||
return
|
||||
}
|
||||
}
|
||||
inst.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
inst.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = inst.objClass.publicMemberResolution[name] ?: name
|
||||
inst.fieldRecordForKey(key)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: inst.objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
writeDirectOrFallback(scope, inst, rec, name, newValue, decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
inst.methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
inst.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
inst.writeField(scope, name, newValue)
|
||||
}
|
||||
|
||||
private suspend fun writeDirectOrFallback(
|
||||
scope: Scope,
|
||||
inst: ObjInstance,
|
||||
rec: ObjRecord,
|
||||
name: String,
|
||||
newValue: Obj,
|
||||
decl: ObjClass?
|
||||
) {
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
if (!rec.isMutable && rec.value !== ObjUnset) {
|
||||
ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
}
|
||||
if (rec.value.assign(scope, newValue) == null) rec.value = newValue
|
||||
} else {
|
||||
inst.writeField(scope, name, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this@Type.method(...)` calls using slots when the qualifier is the
|
||||
* dynamic class. Otherwise falls back to a qualified view dispatch.
|
||||
*/
|
||||
class QualifiedThisMethodSlotCallRef(
|
||||
private val typeName: String,
|
||||
private val name: String,
|
||||
private val args: List<ParsedArgument>,
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
val (inst, startClass) = resolveQualifiedThisInstance(scope, typeName)
|
||||
if (isOptional && inst == ObjNull) return ObjNull
|
||||
val callArgs = args.toArguments(scope, tailBlock)
|
||||
|
||||
if (startClass !== inst.objClass) {
|
||||
return ObjQualifiedView(inst, startClass).invokeInstanceMethod(scope, name, callArgs, null)
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
inst.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, inst, caller)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(inst.instanceScope, inst, callArgs, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = inst.objClass.publicMemberResolution[name] ?: name
|
||||
inst.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: inst.objClass.findDeclaringClassOf(name) ?: inst.objClass
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === inst) inst.objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method $name (declared in ${decl.className})"))
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, inst, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(inst.instanceScope, inst, callArgs, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inst.invokeInstanceMethod(scope, name, callArgs)
|
||||
}
|
||||
}
|
||||
|
||||
/** Assignment compound op: target op= value */
|
||||
class AssignOpRef(
|
||||
private val op: BinOp,
|
||||
@ -422,7 +678,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)
|
||||
@ -450,7 +736,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
|
||||
}
|
||||
@ -691,9 +985,20 @@ class FieldRef(
|
||||
if (effectiveKey != null) {
|
||||
rKey1 = key; rVer1 = ver; rGetter1 = { obj, sc ->
|
||||
if (obj is ObjInstance && obj.objClass === cls) {
|
||||
val rec = obj.instanceScope.objects[effectiveKey]
|
||||
val slot = cls.fieldSlotForKey(effectiveKey)
|
||||
if (slot != null) {
|
||||
val idx = slot.slot
|
||||
val rec = if (idx >= 0 && idx < obj.fieldSlots.size) obj.fieldSlots[idx] else null
|
||||
if (rec != null &&
|
||||
(rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) &&
|
||||
!rec.isAbstract) {
|
||||
rec
|
||||
} else obj.readField(sc, name)
|
||||
} else {
|
||||
val rec = obj.fieldRecordForKey(effectiveKey) ?: obj.instanceScope.objects[effectiveKey]
|
||||
if (rec != null && rec.type != ObjRecord.Type.Delegated) rec
|
||||
else obj.readField(sc, name)
|
||||
}
|
||||
} else obj.readField(sc, name)
|
||||
}
|
||||
} else {
|
||||
@ -809,10 +1114,24 @@ class FieldRef(
|
||||
if (effectiveKey != null) {
|
||||
wKey1 = key; wVer1 = ver; wSetter1 = { obj, sc, nv ->
|
||||
if (obj is ObjInstance && obj.objClass === cls) {
|
||||
val rec = obj.instanceScope.objects[effectiveKey]
|
||||
if (rec != null && rec.effectiveWriteVisibility == Visibility.Public && rec.isMutable && rec.type == ObjRecord.Type.Field) {
|
||||
val slot = cls.fieldSlotForKey(effectiveKey)
|
||||
if (slot != null) {
|
||||
val idx = slot.slot
|
||||
val rec = if (idx >= 0 && idx < obj.fieldSlots.size) obj.fieldSlots[idx] else null
|
||||
if (rec != null &&
|
||||
rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
rec.isMutable &&
|
||||
(rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) &&
|
||||
!rec.isAbstract) {
|
||||
if (rec.value.assign(sc, nv) == null) rec.value = nv
|
||||
} else obj.writeField(sc, name, nv)
|
||||
} else {
|
||||
val rec = obj.fieldRecordForKey(effectiveKey) ?: obj.instanceScope.objects[effectiveKey]
|
||||
if (rec != null && rec.effectiveWriteVisibility == Visibility.Public && rec.isMutable &&
|
||||
(rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField)) {
|
||||
if (rec.value.assign(sc, nv) == null) rec.value = nv
|
||||
} else obj.writeField(sc, name, nv)
|
||||
}
|
||||
} else obj.writeField(sc, name, nv)
|
||||
}
|
||||
} else {
|
||||
@ -890,6 +1209,113 @@ class FieldRef(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this.name` access using slot maps.
|
||||
* Falls back to normal member resolution when needed.
|
||||
*/
|
||||
class ThisFieldSlotRef(
|
||||
val name: String,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
val th = scope.thisObj
|
||||
if (th == ObjNull && isOptional) return ObjNull.asMutable
|
||||
if (th !is ObjInstance) return th.readField(scope, name)
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
th.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name) ?: th.objClass
|
||||
return th.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
|
||||
return th.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
val th = scope.thisObj
|
||||
if (th == ObjNull && isOptional) return
|
||||
if (th !is ObjInstance) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
th.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
writeDirectOrFallback(scope, th, rec, name, newValue, caller)
|
||||
return
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
writeDirectOrFallback(scope, th, rec, name, newValue, decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
th.writeField(scope, name, newValue)
|
||||
}
|
||||
|
||||
private suspend fun writeDirectOrFallback(
|
||||
scope: Scope,
|
||||
inst: ObjInstance,
|
||||
rec: ObjRecord,
|
||||
name: String,
|
||||
newValue: Obj,
|
||||
decl: ObjClass?
|
||||
) {
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
if (!rec.isMutable && rec.value !== ObjUnset) {
|
||||
ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
}
|
||||
if (rec.value.assign(scope, newValue) == null) rec.value = newValue
|
||||
} else {
|
||||
inst.writeField(scope, name, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to index access (a[i]) with optional chaining.
|
||||
*/
|
||||
@ -1133,7 +1559,7 @@ class IndexRef(
|
||||
/**
|
||||
* R-value reference that wraps a Statement (used during migration for expressions parsed as Statement).
|
||||
*/
|
||||
class StatementRef(private val statement: Statement) : ObjRef {
|
||||
class StatementRef(internal val statement: Statement) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord = statement.execute(scope).asReadonly
|
||||
}
|
||||
|
||||
@ -1336,37 +1762,51 @@ class MethodCallRef(
|
||||
is ObjInstance -> {
|
||||
// Prefer resolved class member to avoid per-call lookup on hit
|
||||
// BUT only if it's NOT a root object member (which can be shadowed by extensions)
|
||||
var hierarchyMember: ObjRecord? = null
|
||||
val cls0 = base.objClass
|
||||
val keyInScope = cls0.publicMemberResolution[name]
|
||||
if (keyInScope != null) {
|
||||
val rec = base.instanceScope.objects[keyInScope]
|
||||
if (rec != null && rec.type == ObjRecord.Type.Fun) {
|
||||
hierarchyMember = rec
|
||||
}
|
||||
}
|
||||
val methodSlot = if (keyInScope != null) cls0.methodSlotForKey(keyInScope) else null
|
||||
val fastRec = if (methodSlot != null) {
|
||||
val idx = methodSlot.slot
|
||||
if (idx >= 0 && idx < base.methodSlots.size) base.methodSlots[idx] else null
|
||||
} else if (keyInScope != null) {
|
||||
base.methodRecordForKey(keyInScope) ?: base.instanceScope.objects[keyInScope]
|
||||
} else null
|
||||
val resolved = if (fastRec != null) null else cls0.resolveInstanceMember(name)
|
||||
|
||||
if (hierarchyMember == null) {
|
||||
for (cls in base.objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val rec = cls.members[name] ?: cls.classScope?.objects?.get(name)
|
||||
if (rec != null && !rec.isAbstract && rec.type != ObjRecord.Type.Field) {
|
||||
hierarchyMember = rec
|
||||
break
|
||||
val targetRec = when {
|
||||
fastRec != null && fastRec.type == ObjRecord.Type.Fun -> fastRec
|
||||
resolved != null && resolved.record.type == ObjRecord.Type.Fun && !resolved.record.isAbstract -> resolved.record
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hierarchyMember != null) {
|
||||
val visibility = hierarchyMember.visibility
|
||||
val callable = hierarchyMember.value
|
||||
val decl = hierarchyMember.declaringClass ?: base.objClass
|
||||
if (targetRec != null) {
|
||||
val visibility = targetRec.visibility
|
||||
val decl = targetRec.declaringClass ?: (resolved?.declaringClass ?: cls0)
|
||||
if (methodSlot != null && targetRec.type == ObjRecord.Type.Fun) {
|
||||
val slotIndex = methodSlot.slot
|
||||
mKey1 = key; mVer1 = ver; mInvoker1 = { obj, sc, a ->
|
||||
val inst = obj as ObjInstance
|
||||
if (!visibility.isPublic && !canAccessMember(visibility, decl, sc.currentClassCtx))
|
||||
if (inst.objClass === cls0) {
|
||||
val rec = if (slotIndex >= 0 && slotIndex < inst.methodSlots.size) inst.methodSlots[slotIndex] else null
|
||||
if (rec != null && rec.type == ObjRecord.Type.Fun && !rec.isAbstract) {
|
||||
if (!visibility.isPublic && !canAccessMember(visibility, decl, sc.currentClassCtx, name))
|
||||
sc.raiseError(ObjIllegalAccessException(sc, "can't invoke non-public method $name"))
|
||||
rec.value.invoke(inst.instanceScope, inst, a, decl)
|
||||
} else {
|
||||
obj.invokeInstanceMethod(sc, name, a)
|
||||
}
|
||||
} else {
|
||||
obj.invokeInstanceMethod(sc, name, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val callable = targetRec.value
|
||||
mKey1 = key; mVer1 = ver; mInvoker1 = { obj, sc, a ->
|
||||
val inst = obj as ObjInstance
|
||||
if (!visibility.isPublic && !canAccessMember(visibility, decl, sc.currentClassCtx, name))
|
||||
sc.raiseError(ObjIllegalAccessException(sc, "can't invoke non-public method $name"))
|
||||
callable.invoke(inst.instanceScope, inst, a)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to name-based lookup per call (handles extensions and root members)
|
||||
mKey1 = key; mVer1 = ver; mInvoker1 = { obj, sc, a -> obj.invokeInstanceMethod(sc, name, a) }
|
||||
@ -1399,6 +1839,57 @@ class MethodCallRef(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for direct `this.method(...)` calls using slot maps.
|
||||
* Falls back to normal invoke semantics when needed.
|
||||
*/
|
||||
class ThisMethodSlotCallRef(
|
||||
private val name: String,
|
||||
private val args: List<ParsedArgument>,
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
val base = scope.thisObj
|
||||
if (base == ObjNull && isOptional) return ObjNull
|
||||
val callArgs = args.toArguments(scope, tailBlock)
|
||||
if (base !is ObjInstance) return base.invokeInstanceMethod(scope, name, callArgs)
|
||||
|
||||
val caller = scope.currentClassCtx
|
||||
if (caller != null) {
|
||||
val mangled = caller.mangledName(name)
|
||||
base.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private && !rec.isAbstract) {
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, base, caller)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(base.instanceScope, base, callArgs, caller)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val key = base.objClass.publicMemberResolution[name] ?: name
|
||||
base.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: base.objClass.findDeclaringClassOf(name) ?: base.objClass
|
||||
val effectiveCaller = caller ?: if (scope.thisObj === base) base.objClass else null
|
||||
if (!canAccessMember(rec.visibility, decl, effectiveCaller, name))
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "can't invoke method $name (declared in ${decl.className})"))
|
||||
if (rec.type == ObjRecord.Type.Property) {
|
||||
if (callArgs.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, base, decl)
|
||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
||||
return rec.value.invoke(base.instanceScope, base, callArgs, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.invokeInstanceMethod(scope, name, callArgs)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to a local/visible variable by name (Phase A: scope lookup).
|
||||
*/
|
||||
@ -1447,7 +1938,7 @@ class LocalVarRef(val name: String, private val atPos: Pos) : ObjRef {
|
||||
val slot = if (hit) cachedSlot else resolveSlot(scope)
|
||||
if (slot >= 0) {
|
||||
val rec = scope.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx)) {
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
// Not visible via slot, fallback to other lookups
|
||||
} else {
|
||||
if (PerfFlags.PIC_DEBUG_COUNTERS) {
|
||||
@ -1499,7 +1990,7 @@ class LocalVarRef(val name: String, private val atPos: Pos) : ObjRef {
|
||||
val slot = if (cachedFrameId == scope.frameId && cachedSlot >= 0 && cachedSlot < scope.slotCount()) cachedSlot else resolveSlot(scope)
|
||||
if (slot >= 0) {
|
||||
val rec = scope.getSlotRecord(slot)
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx)) {
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.assign(rec, name, newValue)
|
||||
return
|
||||
}
|
||||
@ -1608,7 +2099,7 @@ class FastLocalVarRef(
|
||||
val actualOwner = cachedOwnerScope
|
||||
if (slot >= 0 && actualOwner != null) {
|
||||
val rec = actualOwner.getSlotRecord(slot)
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx)) {
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
if (PerfFlags.PIC_DEBUG_COUNTERS) {
|
||||
if (ownerValid) PerfStats.fastLocalHit++ else PerfStats.fastLocalMiss++
|
||||
}
|
||||
@ -1652,7 +2143,7 @@ class FastLocalVarRef(
|
||||
val actualOwner = cachedOwnerScope
|
||||
if (slot >= 0 && actualOwner != null) {
|
||||
val rec = actualOwner.getSlotRecord(slot)
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx)) {
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
return scope.resolve(rec, name)
|
||||
}
|
||||
}
|
||||
@ -1698,7 +2189,7 @@ class FastLocalVarRef(
|
||||
val actualOwner = cachedOwnerScope
|
||||
if (slot >= 0 && actualOwner != null) {
|
||||
val rec = actualOwner.getSlotRecord(slot)
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx)) {
|
||||
if (rec.declaringClass == null || canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.assign(rec, name, newValue)
|
||||
return
|
||||
}
|
||||
@ -1729,6 +2220,274 @@ class FastLocalVarRef(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier reference in class context that prefers member slots on `this` after local lookup.
|
||||
* Falls back to normal scope lookup for globals/outer scopes.
|
||||
*/
|
||||
class ImplicitThisMemberRef(
|
||||
val name: String,
|
||||
val atPos: Pos
|
||||
) : ObjRef {
|
||||
private fun resolveInstanceFieldRecord(th: ObjInstance, caller: ObjClass?): ObjRecord? {
|
||||
if (caller == null) return null
|
||||
for (cls in th.objClass.mro) {
|
||||
if (cls.className == "Obj") break
|
||||
val rec = cls.members[name] ?: continue
|
||||
if (rec.isAbstract) continue
|
||||
val decl = rec.declaringClass ?: cls
|
||||
if (!canAccessMember(rec.visibility, decl, caller, name)) continue
|
||||
val key = decl.mangledName(name)
|
||||
th.fieldRecordForKey(key)?.let { return it }
|
||||
th.instanceScope.objects[key]?.let { return it }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
block(name)
|
||||
}
|
||||
|
||||
override fun forEachVariableWithPos(block: (String, Pos) -> Unit) {
|
||||
block(name, atPos)
|
||||
}
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
scope.pos = atPos
|
||||
val caller = scope.currentClassCtx
|
||||
val th = scope.thisObj
|
||||
|
||||
// 1) locals in the same `this` chain
|
||||
var s: Scope? = scope
|
||||
while (s != null && s.thisObj === th) {
|
||||
scope.tryGetLocalRecord(s, name, caller)?.let { return it }
|
||||
s = s.parent
|
||||
}
|
||||
|
||||
// 2) member slots on this instance
|
||||
if (th is ObjInstance) {
|
||||
// private member access for current class context
|
||||
caller?.let { c ->
|
||||
val mangled = c.mangledName(name)
|
||||
th.fieldRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(mangled)?.let { rec ->
|
||||
if (rec.visibility == Visibility.Private) {
|
||||
return th.resolveRecord(scope, rec, name, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolveInstanceFieldRecord(th, caller)?.let { return it }
|
||||
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract)
|
||||
return rec
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (!rec.isAbstract) {
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name) ?: th.objClass
|
||||
return th.resolveRecord(scope, rec, name, decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3) fallback to normal scope resolution (globals/outer scopes)
|
||||
scope[name]?.let { return it }
|
||||
try {
|
||||
return th.readField(scope, name)
|
||||
} catch (e: ExecutionError) {
|
||||
if ((e.message ?: "").contains("no such field: $name")) scope.raiseSymbolNotFound(name)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
val rec = get(scope)
|
||||
return scope.resolve(rec, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
scope.pos = atPos
|
||||
val caller = scope.currentClassCtx
|
||||
val th = scope.thisObj
|
||||
|
||||
// 1) locals in the same `this` chain
|
||||
var s: Scope? = scope
|
||||
while (s != null && s.thisObj === th) {
|
||||
val rec = scope.tryGetLocalRecord(s, name, caller)
|
||||
if (rec != null) {
|
||||
scope.assign(rec, name, newValue)
|
||||
return
|
||||
}
|
||||
s = s.parent
|
||||
}
|
||||
|
||||
// 2) member slots on this instance
|
||||
if (th is ObjInstance) {
|
||||
val key = th.objClass.publicMemberResolution[name] ?: name
|
||||
th.fieldRecordForKey(key)?.let { rec ->
|
||||
val decl = rec.declaringClass ?: th.objClass.findDeclaringClassOf(name)
|
||||
if (canAccessMember(rec.effectiveWriteVisibility, decl, caller, name)) {
|
||||
if ((rec.type == ObjRecord.Type.Field || rec.type == ObjRecord.Type.ConstructorField) && !rec.isAbstract) {
|
||||
if (!rec.isMutable && rec.value !== ObjUnset) {
|
||||
ObjIllegalAssignmentException(scope, "can't reassign val $name").raise()
|
||||
}
|
||||
if (rec.value.assign(scope, newValue) == null) rec.value = newValue
|
||||
} else {
|
||||
th.writeField(scope, name, newValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
th.methodRecordForKey(key)?.let { rec ->
|
||||
if (rec.effectiveWriteVisibility == Visibility.Public &&
|
||||
(rec.type == ObjRecord.Type.Property || rec.type == ObjRecord.Type.Delegated)) {
|
||||
th.writeField(scope, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resolveInstanceFieldRecord(th, caller)?.let { rec ->
|
||||
scope.assign(rec, name, newValue)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 3) fallback to normal scope resolution
|
||||
scope[name]?.let { stored ->
|
||||
scope.assign(stored, name, newValue)
|
||||
return
|
||||
}
|
||||
th.writeField(scope, name, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path for implicit member calls in class bodies: `foo(...)` resolves locals first,
|
||||
* then falls back to member lookup on `this`.
|
||||
*/
|
||||
class ImplicitThisMethodCallRef(
|
||||
private val name: String,
|
||||
private val args: List<ParsedArgument>,
|
||||
private val tailBlock: Boolean,
|
||||
private val isOptional: Boolean,
|
||||
private val atPos: Pos
|
||||
) : ObjRef {
|
||||
private val memberRef = ImplicitThisMemberRef(name, atPos)
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord = evalValue(scope).asReadonly
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
scope.pos = atPos
|
||||
val callee = memberRef.evalValue(scope)
|
||||
if (callee == ObjNull && isOptional) return ObjNull
|
||||
val callArgs = args.toArguments(scope, tailBlock)
|
||||
val usePool = PerfFlags.SCOPE_POOL
|
||||
return if (usePool) {
|
||||
scope.withChildFrame(callArgs) { child ->
|
||||
callee.callOn(child)
|
||||
}
|
||||
} else {
|
||||
callee.callOn(scope.createChildScope(scope.pos, callArgs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct local slot reference with known slot index and lexical depth.
|
||||
* Depth=0 means current scope, depth=1 means parent scope, etc.
|
||||
*/
|
||||
class LocalSlotRef(
|
||||
val name: String,
|
||||
private val slot: Int,
|
||||
private val depth: Int,
|
||||
private val atPos: Pos,
|
||||
) : ObjRef {
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
block(name)
|
||||
}
|
||||
|
||||
private val fallbackRef = LocalVarRef(name, atPos)
|
||||
private var cachedFrameId: Long = 0L
|
||||
private var cachedOwner: Scope? = null
|
||||
private var cachedOwnerVerified: Boolean = false
|
||||
|
||||
private fun resolveOwner(scope: Scope): Scope? {
|
||||
if (cachedOwner != null && cachedFrameId == scope.frameId && cachedOwnerVerified) {
|
||||
val cached = cachedOwner!!
|
||||
val candidate = if (depth == 0) scope else {
|
||||
var s: Scope? = scope
|
||||
var remaining = depth
|
||||
while (s != null && remaining > 0) {
|
||||
s = s.parent
|
||||
remaining--
|
||||
}
|
||||
s
|
||||
}
|
||||
if (candidate === cached && candidate?.getSlotIndexOf(name) == slot) return cached
|
||||
}
|
||||
var s: Scope? = scope
|
||||
var remaining = depth
|
||||
while (s != null && remaining > 0) {
|
||||
s = s.parent
|
||||
remaining--
|
||||
}
|
||||
if (s == null || s.getSlotIndexOf(name) != slot) {
|
||||
cachedOwner = null
|
||||
cachedOwnerVerified = false
|
||||
cachedFrameId = scope.frameId
|
||||
return null
|
||||
}
|
||||
cachedOwner = s
|
||||
cachedOwnerVerified = true
|
||||
cachedFrameId = scope.frameId
|
||||
return s
|
||||
}
|
||||
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
scope.pos = atPos
|
||||
val owner = resolveOwner(scope) ?: return fallbackRef.get(scope)
|
||||
if (slot < 0 || slot >= owner.slotCount()) return fallbackRef.get(scope)
|
||||
val rec = owner.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||
}
|
||||
return rec
|
||||
}
|
||||
|
||||
override suspend fun evalValue(scope: Scope): Obj {
|
||||
scope.pos = atPos
|
||||
val owner = resolveOwner(scope) ?: return fallbackRef.evalValue(scope)
|
||||
if (slot < 0 || slot >= owner.slotCount()) return fallbackRef.evalValue(scope)
|
||||
val rec = owner.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||
}
|
||||
return scope.resolve(rec, name)
|
||||
}
|
||||
|
||||
override suspend fun setAt(pos: Pos, scope: Scope, newValue: Obj) {
|
||||
scope.pos = atPos
|
||||
val owner = resolveOwner(scope) ?: run {
|
||||
fallbackRef.setAt(pos, scope, newValue)
|
||||
return
|
||||
}
|
||||
if (slot < 0 || slot >= owner.slotCount()) {
|
||||
fallbackRef.setAt(pos, scope, newValue)
|
||||
return
|
||||
}
|
||||
val rec = owner.getSlotRecord(slot)
|
||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||
}
|
||||
scope.assign(rec, name, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
||||
override fun forEachVariable(block: (String) -> Unit) {
|
||||
for (e in entries) {
|
||||
@ -1862,9 +2621,9 @@ class MapLiteralRef(private val entries: List<MapLiteralEntry>) : ObjRef {
|
||||
* Range literal: left .. right or left ..< right. Right may be omitted in certain contexts.
|
||||
*/
|
||||
class RangeRef(
|
||||
private val left: ObjRef?,
|
||||
private val right: ObjRef?,
|
||||
private val isEndInclusive: Boolean
|
||||
internal val left: ObjRef?,
|
||||
internal val right: ObjRef?,
|
||||
internal val isEndInclusive: Boolean
|
||||
) : ObjRef {
|
||||
override suspend fun get(scope: Scope): ObjRecord {
|
||||
return evalValue(scope).asReadonly
|
||||
@ -1910,7 +2669,15 @@ class AssignRef(
|
||||
val v = value.evalValue(scope)
|
||||
// For properties, we should not call get() on target because it invokes the getter.
|
||||
// Instead, we call setAt directly.
|
||||
if (target is FieldRef || target is IndexRef || target is LocalVarRef || target is FastLocalVarRef || target is BoundLocalVarRef) {
|
||||
if (target is FieldRef ||
|
||||
target is IndexRef ||
|
||||
target is LocalVarRef ||
|
||||
target is FastLocalVarRef ||
|
||||
target is BoundLocalVarRef ||
|
||||
target is LocalSlotRef ||
|
||||
target is ThisFieldSlotRef ||
|
||||
target is QualifiedThisFieldSlotRef ||
|
||||
target is ImplicitThisMemberRef) {
|
||||
target.setAt(atPos, scope, v)
|
||||
} else {
|
||||
val rec = target.get(scope)
|
||||
|
||||
@ -301,6 +301,18 @@ data class ObjString(val value: String) : Obj() {
|
||||
) {
|
||||
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())
|
||||
}
|
||||
addFnDoc(
|
||||
name = "matches",
|
||||
doc = "Whether this string matches the given regular expression or pattern string.",
|
||||
|
||||
@ -63,6 +63,13 @@ 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)
|
||||
}
|
||||
|
||||
@ -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.lynon
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.Obj
|
||||
import net.sergeych.lyng.obj.ObjClass
|
||||
import net.sergeych.lyng.obj.ObjInstance
|
||||
import net.sergeych.lyng.obj.ObjString
|
||||
|
||||
open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSettings.default) {
|
||||
@ -79,15 +80,16 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe
|
||||
private suspend fun decodeClassObj(scope: Scope): ObjClass {
|
||||
val className = decodeObject(scope, ObjString.type, null) as ObjString
|
||||
return scope.get(className.value)?.value?.let {
|
||||
if (it !is ObjClass)
|
||||
if (it is ObjClass) return it
|
||||
if (it is ObjInstance && it.objClass.className == className.value) return it.objClass
|
||||
scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}")
|
||||
it
|
||||
} ?: run {
|
||||
// Use Scope API that mirrors compiler-emitted ObjRef chain for qualified identifiers
|
||||
val evaluated = scope.resolveQualifiedIdentifier(className.value)
|
||||
if (evaluated !is ObjClass)
|
||||
if (evaluated is ObjClass) return evaluated
|
||||
if (evaluated is ObjInstance && evaluated.objClass.className == className.value) return evaluated.objClass
|
||||
scope.raiseClassCastError("Expected obj class but got ${evaluated::class.simpleName}")
|
||||
evaluated
|
||||
evaluated as ObjClass // unreachable but for compiler
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -528,4 +528,52 @@ class MiniAstTest {
|
||||
assertTrue(xParam.contains("first line of x"), "should contain first line")
|
||||
assertTrue(xParam.contains("second line of x"), "should contain second line")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun enum_minidocs_and_semicolon_robustness() = runTest {
|
||||
val code = """
|
||||
/** Enum doc */
|
||||
enum E { A };
|
||||
|
||||
/** Next doc */
|
||||
class C {}
|
||||
""".trimIndent()
|
||||
val (_, sink) = compileWithMini(code)
|
||||
val mini = sink.build()
|
||||
assertNotNull(mini)
|
||||
|
||||
val en = mini.declarations.filterIsInstance<MiniEnumDecl>().firstOrNull { it.name == "E" }
|
||||
assertNotNull(en)
|
||||
assertNotNull(en.doc)
|
||||
assertEquals("Enum doc", en.doc.summary)
|
||||
|
||||
val cl = mini.declarations.filterIsInstance<MiniClassDecl>().firstOrNull { it.name == "C" }
|
||||
assertNotNull(cl)
|
||||
assertNotNull(cl.doc)
|
||||
assertEquals("Next doc", cl.doc.summary)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun empty_enum_support() = runTest {
|
||||
val code = "enum E {}"
|
||||
val (_, sink) = compileWithMini(code)
|
||||
val mini = sink.build()
|
||||
assertNotNull(mini)
|
||||
assertTrue(mini.declarations.any { it.name == "E" && it is MiniEnumDecl })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun modifiers_with_comment_robustness() = runTest {
|
||||
val code = """
|
||||
class X {
|
||||
static /** doc */ fun f() {}
|
||||
}
|
||||
""".trimIndent()
|
||||
val (_, sink) = compileWithMini(code)
|
||||
val mini = sink.build()
|
||||
assertNotNull(mini)
|
||||
val cls = mini.declarations.filterIsInstance<MiniClassDecl>().firstOrNull { it.name == "X" }
|
||||
assertNotNull(cls)
|
||||
assertTrue(cls.members.any { it.name == "f" })
|
||||
}
|
||||
}
|
||||
|
||||
51
lynglib/src/commonTest/kotlin/NestedRangeBenchmarkTest.kt
Normal file
51
lynglib/src/commonTest/kotlin/NestedRangeBenchmarkTest.kt
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.lyng.Script
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.eval
|
||||
import net.sergeych.lyng.obj.ObjInstance
|
||||
import net.sergeych.lyng.obj.ObjList
|
||||
@ -776,4 +777,153 @@ class OOTest {
|
||||
|
||||
assertEquals("success", result.toString(), "Parameter 'id' should shadow method 'id' in block")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOverrideVisibilityRules1() = runTest {
|
||||
val scope = Script.newScope()
|
||||
scope.eval("""
|
||||
interface Base {
|
||||
abstract protected fun foo()
|
||||
|
||||
fun bar() {
|
||||
// it must see foo() as it is protected and
|
||||
// is declared here (even as abstract):
|
||||
foo()
|
||||
}
|
||||
}
|
||||
class Derived : Base {
|
||||
protected val suffix = "!"
|
||||
|
||||
private fun fooPrivateImpl() = "bar"
|
||||
|
||||
override protected fun foo() {
|
||||
// it should access own private and all protected memberes here:
|
||||
fooPrivateImpl() + suffix
|
||||
}
|
||||
}
|
||||
class Derived2: Base {
|
||||
private var value = 42
|
||||
|
||||
private fun fooPrivateImpl() = value
|
||||
|
||||
override protected fun foo() {
|
||||
fooPrivateImpl()
|
||||
value++
|
||||
}
|
||||
}
|
||||
assertEquals("bar!", Derived().bar())
|
||||
val d = Derived2()
|
||||
assertEquals(42, d.bar())
|
||||
assertEquals(43, d.bar())
|
||||
""".trimIndent())
|
||||
scope.createChildScope().eval("""
|
||||
assertEquals("bar!", Derived().bar())
|
||||
assertEquals(42, Derived2().bar())
|
||||
""".trimIndent())
|
||||
}
|
||||
@Test
|
||||
fun testOverrideVisibilityRules2() = runTest {
|
||||
val scope = Script.newScope()
|
||||
val fn = scope.eval("""
|
||||
interface Base {
|
||||
abstract fun foo()
|
||||
|
||||
fun bar() {
|
||||
// it must see foo() as it is protected and
|
||||
// is declared here (even as abstract):
|
||||
foo()
|
||||
}
|
||||
}
|
||||
class Derived : Base {
|
||||
protected val suffix = "!"
|
||||
|
||||
private fun fooPrivateImpl() = "bar"
|
||||
|
||||
override fun foo() {
|
||||
// it should access own private and all protected memberes here:
|
||||
fooPrivateImpl() + suffix
|
||||
}
|
||||
}
|
||||
class Derived2: Base {
|
||||
private var value = 42
|
||||
|
||||
private fun fooPrivateImpl() = value
|
||||
|
||||
override fun foo() {
|
||||
fooPrivateImpl()
|
||||
value++
|
||||
}
|
||||
}
|
||||
assertEquals("bar!", Derived().bar())
|
||||
val d = Derived2()
|
||||
|
||||
fun callBar() = d.bar()
|
||||
|
||||
assertEquals(42, callBar())
|
||||
assertEquals(43, callBar())
|
||||
|
||||
callBar
|
||||
""".trimIndent()) as Statement
|
||||
val s2 = Script.newScope()
|
||||
assertEquals(44L, fn.invoke(scope, fn).toKotlin(s2))
|
||||
assertEquals(45L, fn.invoke(s2, fn).toKotlin(s2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToStringWithTransients() = runTest {
|
||||
eval("""
|
||||
class C(amount,@Transient transient=0) {
|
||||
val l by lazy { transient + amount }
|
||||
fun lock() {
|
||||
if( transient < 10 )
|
||||
C(amount).also { it.transient = transient + 10 }
|
||||
else
|
||||
this
|
||||
}
|
||||
}
|
||||
println(C(1))
|
||||
println(C(1).lock().amount)
|
||||
println(C(1).lock().lock().amount)
|
||||
""".trimIndent())
|
||||
}
|
||||
@Test
|
||||
fun testToStringWithTransient() = runTest {
|
||||
eval("""
|
||||
class C(amount,@Transient transient=0) {
|
||||
val l by lazy { transient + amount }
|
||||
fun lock() {
|
||||
if( transient < 10 )
|
||||
C(amount).also { it.transient = transient + 10 }
|
||||
else
|
||||
this
|
||||
}
|
||||
}
|
||||
println(C(1))
|
||||
println(C(1).lock().amount)
|
||||
println(C(1).lock().lock().amount)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToJsonString() = runTest {
|
||||
eval("""
|
||||
class T(a,b,@Transient c=0)
|
||||
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())
|
||||
}
|
||||
}
|
||||
@ -3169,6 +3169,19 @@ class ScriptTest {
|
||||
assertEquals( n1 - now, 7.seconds )
|
||||
assertEquals( now - n1, -7.seconds )
|
||||
|
||||
val t3 = Instant("2024-01-01T12:00:00.123456Z")
|
||||
val t4 = t3.truncateToMinute
|
||||
assertEquals(t4.toRFC3339(), "2024-01-01T12:00:00Z")
|
||||
assertEquals(
|
||||
"2024-01-01T12:00:00Z",
|
||||
Instant("2024-01-01T12:00:59.999Z").truncateToMinute().toRFC3339()
|
||||
)
|
||||
|
||||
val t5 = t3.truncateToSecond
|
||||
assertEquals(t5.toRFC3339(), "2024-01-01T12:00:00Z")
|
||||
|
||||
val t6 = t3.truncateToMillisecond
|
||||
assertEquals(t6.toRFC3339(), "2024-01-01T12:00:00.123Z")
|
||||
""".trimIndent()
|
||||
)
|
||||
delay(1000)
|
||||
@ -3209,6 +3222,137 @@ class ScriptTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDateTimeComprehensive() = runTest {
|
||||
eval("""
|
||||
import lyng.time
|
||||
import lyng.serialization
|
||||
|
||||
// 1. Timezone variations
|
||||
val t1 = Instant("2024-01-01T12:00:00Z")
|
||||
|
||||
val dtZ = t1.toDateTime("Z")
|
||||
assertEquals(dtZ.timeZone, "Z")
|
||||
assertEquals(dtZ.hour, 12)
|
||||
|
||||
val dtP2 = t1.toDateTime("+02:00")
|
||||
assertEquals(dtP2.timeZone, "+02:00")
|
||||
assertEquals(dtP2.hour, 14)
|
||||
|
||||
val dtM330 = t1.toDateTime("-03:30")
|
||||
assertEquals(dtM330.timeZone, "-03:30")
|
||||
assertEquals(dtM330.hour, 8)
|
||||
assertEquals(dtM330.minute, 30)
|
||||
|
||||
// 2. RFC3339 representations
|
||||
// Note: ObjDateTime.toString() currently uses localDateTime.toString() + timeZone.toString()
|
||||
// We should verify what it actually produces.
|
||||
val s1 = dtP2.toRFC3339()
|
||||
// kotlinx-datetime LocalDateTime.toString() is ISO8601
|
||||
// TimeZone.toString() for offsets is usually the offset string itself
|
||||
println("dtP2 RFC3339: " + s1)
|
||||
|
||||
// 3. Parsing
|
||||
val t2 = Instant("2024-02-29T10:00:00+01:00")
|
||||
assertEquals(t2.toDateTime("Z").hour, 9)
|
||||
|
||||
// val dt3 = DateTime(t1, "Europe/Prague")
|
||||
// assertEquals(dt3.timeZone, "Europe/Prague")
|
||||
|
||||
// 4. Serialization (Lynon)
|
||||
val bin = Lynon.encode(dtP2)
|
||||
val dtP2_dec = Lynon.decode(bin)
|
||||
assertEquals(dtP2, dtP2_dec)
|
||||
assertEquals(dtP2_dec.hour, 14)
|
||||
assertEquals(dtP2_dec.timeZone, "+02:00")
|
||||
|
||||
// 5. Serialization (JSON)
|
||||
// val json = Lynon.toJson(dtM330) // toJson is not on Lynon yet
|
||||
// println("JSON: " + json)
|
||||
|
||||
// 6. Arithmetic edge cases
|
||||
val leapDay = Instant("2024-02-29T12:00:00Z").toDateTime("Z")
|
||||
val nextYear = leapDay.addYears(1)
|
||||
assertEquals(nextYear.year, 2025)
|
||||
assertEquals(nextYear.month, 2)
|
||||
assertEquals(nextYear.day, 28) // Normalized
|
||||
|
||||
val monthEnd = Instant("2024-01-31T12:00:00Z").toDateTime("Z")
|
||||
val nextMonth = monthEnd.addMonths(1)
|
||||
assertEquals(nextMonth.month, 2)
|
||||
assertEquals(nextMonth.day, 29) // 2024 is leap year
|
||||
|
||||
// 7. Day of week
|
||||
assertEquals(Instant("2024-01-01T12:00:00Z").toDateTime("Z").dayOfWeek, 1) // Monday
|
||||
assertEquals(Instant("2024-01-07T12:00:00Z").toDateTime("Z").dayOfWeek, 7) // Sunday
|
||||
|
||||
// 8. DateTime to/from Instant
|
||||
val inst = dtP2.toInstant()
|
||||
assertEquals(inst, t1)
|
||||
assertEquals(dtP2.toEpochSeconds(), t1.epochWholeSeconds)
|
||||
|
||||
// 9. toUTC and toTimeZone
|
||||
val dtUTC = dtP2.toUTC()
|
||||
assertEquals(dtUTC.timeZone, "UTC")
|
||||
assertEquals(dtUTC.hour, 12)
|
||||
|
||||
val dtPrague = dtUTC.toTimeZone("+01:00")
|
||||
// Equivalent to Prague winter
|
||||
assertEquals(dtPrague.hour, 13)
|
||||
|
||||
// 10. Component-based constructor
|
||||
val dtComp = DateTime(2024, 5, 20, 15, 30, 45, "+02:00")
|
||||
assertEquals(dtComp.year, 2024)
|
||||
assertEquals(dtComp.month, 5)
|
||||
assertEquals(dtComp.day, 20)
|
||||
assertEquals(dtComp.hour, 15)
|
||||
assertEquals(dtComp.minute, 30)
|
||||
assertEquals(dtComp.second, 45)
|
||||
assertEquals(dtComp.timeZone, "+02:00")
|
||||
|
||||
// 11. parseRFC3339
|
||||
val dtParsed = DateTime.parseRFC3339("2024-05-20T15:30:45+02:00")
|
||||
assertEquals(dtParsed.year, 2024)
|
||||
assertEquals(dtParsed.hour, 15)
|
||||
assertEquals(dtParsed.timeZone, "+02:00")
|
||||
|
||||
val dtParsedZ = DateTime.parseRFC3339("2024-05-20T15:30:45Z")
|
||||
assertEquals(dtParsedZ.timeZone, "Z")
|
||||
assertEquals(dtParsedZ.hour, 15)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInstantComponents() = runTest {
|
||||
eval("""
|
||||
import lyng.time
|
||||
val t1 = Instant("1970-05-06T07:11:56Z")
|
||||
val dt = t1.toDateTime("Z")
|
||||
assertEquals(dt.year, 1970)
|
||||
assertEquals(dt.month, 5)
|
||||
assertEquals(dt.day, 6)
|
||||
assertEquals(dt.hour, 7)
|
||||
assertEquals(dt.minute, 11)
|
||||
assertEquals(dt.second, 56)
|
||||
assertEquals(dt.dayOfWeek, 3) // 1970-05-06 was Wednesday
|
||||
assertEquals("1970-05-06T07:11:56Z", t1.toRFC3339())
|
||||
assertEquals("1970-05-06T07:11:56Z", t1.toSortableString())
|
||||
|
||||
val dt2 = dt.toTimeZone("+02:00")
|
||||
assertEquals(dt2.hour, 9)
|
||||
assertEquals(dt2.timeZone, "+02:00")
|
||||
|
||||
val dt3 = dt.addMonths(1)
|
||||
assertEquals(dt3.month, 6)
|
||||
assertEquals(dt3.day, 6)
|
||||
|
||||
val dt4 = dt.addYears(1)
|
||||
assertEquals(dt4.year, 1971)
|
||||
|
||||
assertEquals(dt.toInstant(), t1)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoubleImports() = runTest {
|
||||
val s = Scope.new()
|
||||
@ -4855,5 +4999,49 @@ class ScriptTest {
|
||||
assertEquals(["bar"], A().f2("bar"))
|
||||
""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClamp() = runTest {
|
||||
eval("""
|
||||
// Global clamp
|
||||
assertEquals(5, clamp(5, 0..10))
|
||||
assertEquals(0, clamp(-5, 0..10))
|
||||
assertEquals(10, clamp(15, 0..10))
|
||||
|
||||
// Extension clamp
|
||||
assertEquals(5, 5.clamp(0..10))
|
||||
assertEquals(0, (-5).clamp(0..10))
|
||||
assertEquals(10, 15.clamp(0..10))
|
||||
|
||||
// Exclusive range
|
||||
assertEquals(9, 15.clamp(0..<10))
|
||||
assertEquals(0, (-5).clamp(0..<10))
|
||||
|
||||
// Open-ended range
|
||||
assertEquals(10, 15.clamp(..10))
|
||||
assertEquals(-5, (-5).clamp(..10))
|
||||
assertEquals(5, 5.clamp(0..))
|
||||
assertEquals(0, (-5).clamp(0..))
|
||||
|
||||
// Character range
|
||||
assertEquals('e', 'e'.clamp('a'..'z'))
|
||||
assertEquals('a', ' '.clamp('a'..'z'))
|
||||
assertEquals('z', '}'.clamp('a'..'z'))
|
||||
assertEquals('y', '}'.clamp('a'..<'z'))
|
||||
|
||||
// Real numbers (boundaries are inclusive in current impl for Real)
|
||||
assertEquals(5.5, 5.5.clamp(0.0..10.0))
|
||||
assertEquals(0.0, (-1.5).clamp(0.0..10.0))
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
99
lynglib/src/commonTest/kotlin/ValReassignRegressionTest.kt
Normal file
99
lynglib/src/commonTest/kotlin/ValReassignRegressionTest.kt
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
241
lynglib/src/commonTest/kotlin/net/sergeych/lyng/TransientTest.kt
Normal file
241
lynglib/src/commonTest/kotlin/net/sergeych/lyng/TransientTest.kt
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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.coroutines.test.runTest
|
||||
import net.sergeych.lyng.obj.ObjInstance
|
||||
import net.sergeych.lyng.obj.ObjInt
|
||||
import net.sergeych.lyng.obj.ObjNull
|
||||
import net.sergeych.lyng.obj.toBool
|
||||
import net.sergeych.lynon.lynonDecodeAny
|
||||
import net.sergeych.lynon.lynonEncodeAny
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class TransientTest {
|
||||
|
||||
@Test
|
||||
fun testTransient() = runTest {
|
||||
val script = """
|
||||
class TestTransient(@Transient val a, val b) {
|
||||
@Transient var c = 10
|
||||
var d = 20
|
||||
|
||||
fun check() {
|
||||
a == 1 && b == 2 && c == 10 && d == 20
|
||||
}
|
||||
}
|
||||
|
||||
val t = TestTransient(1, 2)
|
||||
t.c = 30
|
||||
t.d = 40
|
||||
t
|
||||
""".trimIndent()
|
||||
|
||||
val scope = Scope()
|
||||
val t = scope.eval(script) as ObjInstance
|
||||
|
||||
// Check initial state
|
||||
assertEquals(1, (t.readField(scope, "a").value as ObjInt).value)
|
||||
assertEquals(2, (t.readField(scope, "b").value as ObjInt).value)
|
||||
assertEquals(30, (t.readField(scope, "c").value as ObjInt).value)
|
||||
assertEquals(40, (t.readField(scope, "d").value as ObjInt).value)
|
||||
|
||||
// Serialize
|
||||
val serialized = lynonEncodeAny(scope, t)
|
||||
println("[DEBUG_LOG] Serialized size: ${serialized.size}")
|
||||
|
||||
// Deserialized
|
||||
val t2 = lynonDecodeAny(scope, serialized) as ObjInstance
|
||||
|
||||
// b and d should be preserved
|
||||
assertEquals(2, (t2.readField(scope, "b").value as ObjInt).value)
|
||||
assertEquals(40, (t2.readField(scope, "d").value as ObjInt).value)
|
||||
|
||||
// a and c should be transient (lost or default/null)
|
||||
// For constructor args, we currently set ObjNull if transient
|
||||
assertEquals(ObjNull, t2.readField(scope, "a").value)
|
||||
// For class fields, if it's transient it's not serialized, so it gets its initial value during construction
|
||||
assertEquals(10, (t2.readField(scope, "c").value as ObjInt).value)
|
||||
|
||||
// Check JSON
|
||||
val json = t.toJson(scope).toString()
|
||||
println("[DEBUG_LOG] JSON: $json")
|
||||
assertFalse(json.contains("\"a\":"))
|
||||
assertFalse(json.contains("\"c\":"))
|
||||
assertNotNull(json.contains("\"b\":2"))
|
||||
assertNotNull(json.contains("\"d\":40"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTransientDefaultAndEquality() = runTest {
|
||||
val script = """
|
||||
class TestExt(@Transient val a = 100, val b) {
|
||||
@Transient var c = 200
|
||||
var d = 300
|
||||
}
|
||||
|
||||
val t1 = TestExt(b: 2)
|
||||
t1.c = 300
|
||||
t1.d = 400
|
||||
|
||||
val t2 = TestExt(a: 50, b: 2)
|
||||
t2.c = 500
|
||||
t2.d = 400
|
||||
|
||||
// Equality should ignore transient fields a and c
|
||||
val equal = (t1 == t2)
|
||||
|
||||
[t1, t2, equal]
|
||||
""".trimIndent()
|
||||
|
||||
val scope = Scope()
|
||||
val result = (scope.eval(script) as net.sergeych.lyng.obj.ObjList).list
|
||||
val t1 = result[0] as ObjInstance
|
||||
val t2 = result[1] as ObjInstance
|
||||
val equal = result[2].toBool()
|
||||
|
||||
assertEquals(true, equal, "Objects should be equal despite different transient fields")
|
||||
|
||||
// Serialize t1
|
||||
val serialized = lynonEncodeAny(scope, t1)
|
||||
val t1d = lynonDecodeAny(scope, serialized) as ObjInstance
|
||||
|
||||
// a should have its default value 100, not null or 10
|
||||
assertEquals(100, (t1d.readField(scope, "a").value as ObjInt).value)
|
||||
// c should have its initial value 200
|
||||
assertEquals(200, (t1d.readField(scope, "c").value as ObjInt).value)
|
||||
// b and d should be preserved
|
||||
assertEquals(2, (t1d.readField(scope, "b").value as ObjInt).value)
|
||||
assertEquals(400, (t1d.readField(scope, "d").value as ObjInt).value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStaticTransient() = runTest {
|
||||
val script = """
|
||||
class TestStatic {
|
||||
@Transient static var x = 10
|
||||
static var y = 20
|
||||
}
|
||||
TestStatic.x = 30
|
||||
TestStatic.y = 40
|
||||
TestStatic
|
||||
""".trimIndent()
|
||||
val scope = Scope()
|
||||
scope.eval(script)
|
||||
// Static fields aren't serialized yet, but we ensure the parser accepts it
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTransientSize() = runTest {
|
||||
val script = """
|
||||
class Data1(val a, val b) {
|
||||
var c = 30
|
||||
}
|
||||
class Data2(val a, val b, @Transient val x) {
|
||||
var c = 30
|
||||
@Transient var y = 40
|
||||
}
|
||||
|
||||
val d1 = Data1(10, 20)
|
||||
val d2 = Data2(10, 20, 100)
|
||||
d2.y = 200
|
||||
|
||||
[d1, d2]
|
||||
""".trimIndent()
|
||||
|
||||
val scope = Scope()
|
||||
val result = (scope.eval(script) as net.sergeych.lyng.obj.ObjList).list
|
||||
val d1 = result[0] as ObjInstance
|
||||
val d2 = result[1] as ObjInstance
|
||||
|
||||
val s1 = lynonEncodeAny(scope, d1)
|
||||
val s2 = lynonEncodeAny(scope, d2)
|
||||
|
||||
println("[DEBUG_LOG] Data1 size: ${s1.size}")
|
||||
println("[DEBUG_LOG] Data2 size: ${s2.size}")
|
||||
|
||||
assertEquals(s1.size, s2.size, "Serialized sizes should match because transient fields are not serialized")
|
||||
|
||||
val j1 = d1.toJson(scope).toString()
|
||||
val j2 = d2.toJson(scope).toString()
|
||||
|
||||
println("[DEBUG_LOG] Data1 JSON: $j1")
|
||||
println("[DEBUG_LOG] Data2 JSON: $j2")
|
||||
|
||||
assertEquals(j1.length, j2.length, "JSON lengths should match")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testObjectTransient() = runTest {
|
||||
val script = """
|
||||
object MyObject {
|
||||
@Transient var temp = 10
|
||||
var persistent = 20
|
||||
}
|
||||
MyObject.temp = 30
|
||||
MyObject.persistent = 40
|
||||
MyObject
|
||||
""".trimIndent()
|
||||
|
||||
val scope = Scope()
|
||||
val obj = scope.eval(script) as ObjInstance
|
||||
|
||||
val serialized = lynonEncodeAny(scope, obj)
|
||||
val deserialized = lynonDecodeAny(scope, serialized) as ObjInstance
|
||||
|
||||
// persistent should be 40
|
||||
assertEquals(40, (deserialized.readField(scope, "persistent").value as ObjInt).value)
|
||||
// temp should be restored to 10
|
||||
assertEquals(10, (deserialized.readField(scope, "temp").value as ObjInt).value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStaticTransientToJson() = runTest {
|
||||
val script = """
|
||||
class TestStatic {
|
||||
@Transient static var s1 = 10
|
||||
static var s2 = 20
|
||||
private static var s3 = 30
|
||||
}
|
||||
TestStatic
|
||||
""".trimIndent()
|
||||
|
||||
val scope = Scope()
|
||||
val cls = scope.eval(script) as net.sergeych.lyng.obj.ObjClass
|
||||
|
||||
val json = cls.toJson(scope).toString()
|
||||
println("[DEBUG_LOG] Class JSON: $json")
|
||||
|
||||
// s2 should be in JSON
|
||||
assertNotNull(json.contains("\"s2\":20"))
|
||||
// s1 should NOT be in JSON (transient)
|
||||
assertFalse(json.contains("\"s1\":"))
|
||||
// s3 should NOT be in JSON (private)
|
||||
assertFalse(json.contains("\"s3\":"))
|
||||
// __class_name should be there
|
||||
assertNotNull(json.contains("\"__class_name\":\"TestStatic\""))
|
||||
|
||||
// Test serialization/deserialization of the class itself
|
||||
val serialized = lynonEncodeAny(scope, cls)
|
||||
val deserialized = lynonDecodeAny(scope, serialized) as net.sergeych.lyng.obj.ObjClass
|
||||
assertEquals(cls, deserialized)
|
||||
}
|
||||
}
|
||||
@ -882,6 +882,22 @@ class LyngFormatterTest {
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val cfg = LyngFormatConfig(indentSize = 4, continuationIndentSize = 4)
|
||||
val out = LyngFormatter.reindent(src, cfg)
|
||||
assertEquals(expected, out)
|
||||
}
|
||||
@Test
|
||||
fun multlinedShortFunIndentation() {
|
||||
val src = """
|
||||
static fun create(walletId, trId, amount) =
|
||||
Cells.createNew(Commission(amount) => ["commission", "w:" + walletId, "tr:" + trId, createdTag(), "pending"])
|
||||
""".trimIndent()
|
||||
|
||||
val expected = """
|
||||
static fun create(walletId, trId, amount) =
|
||||
Cells.createNew(Commission(amount) => ["commission", "w:" + walletId, "tr:" + trId, createdTag(), "pending"])
|
||||
""".trimIndent()
|
||||
|
||||
val cfg = LyngFormatConfig(indentSize = 4, continuationIndentSize = 4)
|
||||
val out = LyngFormatter.reindent(src, cfg)
|
||||
assertEquals(expected, out)
|
||||
|
||||
22
lynglib/src/jsMain/kotlin/net/sergeych/lyng/BenchmarksJs.kt
Normal file
22
lynglib/src/jsMain/kotlin/net/sergeych/lyng/BenchmarksJs.kt
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
156
notes/bench_baseline.txt
Normal file
156
notes/bench_baseline.txt
Normal file
@ -0,0 +1,156 @@
|
||||
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.
|
||||
157
notes/bench_phase3_args_builder.txt
Normal file
157
notes/bench_phase3_args_builder.txt
Normal file
@ -0,0 +1,157 @@
|
||||
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.
|
||||
156
notes/bench_phase3_args_builder_v2.txt
Normal file
156
notes/bench_phase3_args_builder_v2.txt
Normal file
@ -0,0 +1,156 @@
|
||||
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.
|
||||
156
notes/bench_phase3_block_hints.txt
Normal file
156
notes/bench_phase3_block_hints.txt
Normal file
@ -0,0 +1,156 @@
|
||||
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.
|
||||
156
notes/bench_phase_next_loop_list.txt
Normal file
156
notes/bench_phase_next_loop_list.txt
Normal file
@ -0,0 +1,156 @@
|
||||
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.
|
||||
157
notes/bench_phase_range_cache.txt
Normal file
157
notes/bench_phase_range_cache.txt
Normal file
@ -0,0 +1,157 @@
|
||||
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.
|
||||
157
notes/bench_phase_range_iter_cache.txt
Normal file
157
notes/bench_phase_range_iter_cache.txt
Normal file
@ -0,0 +1,157 @@
|
||||
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.
|
||||
157
notes/bench_phase_range_loop_cache.txt
Normal file
157
notes/bench_phase_range_loop_cache.txt
Normal file
@ -0,0 +1,157 @@
|
||||
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.
|
||||
156
notes/bench_pruned.txt
Normal file
156
notes/bench_pruned.txt
Normal file
@ -0,0 +1,156 @@
|
||||
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.
|
||||
246
notes/perf_patch_slotB_A_current.diff
Normal file
246
notes/perf_patch_slotB_A_current.diff
Normal file
@ -0,0 +1,246 @@
|
||||
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
|
||||
}
|
||||
@ -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.
|
||||
@ -118,7 +118,7 @@ fun App() {
|
||||
Div({ classes("col-12", if (isDocsRoute) "col-lg-9" else "col-lg-12") }) {
|
||||
when {
|
||||
route.isBlank() -> HomePage()
|
||||
route == "tryling" -> TryLyngPage()
|
||||
route.startsWith("tryling") -> TryLyngPage(route)
|
||||
route.startsWith("search") -> SearchPage(route)
|
||||
!isDocsRoute -> ReferencePage()
|
||||
else -> DocsPage(
|
||||
|
||||
@ -15,7 +15,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.delay
|
||||
import net.sergeych.lyngweb.ensureBootstrapCodeBlocks
|
||||
import net.sergeych.lyngweb.highlightLyngHtml
|
||||
import net.sergeych.lyngweb.htmlEscape
|
||||
@ -23,6 +25,141 @@ import org.jetbrains.compose.web.dom.*
|
||||
|
||||
@Composable
|
||||
fun HomePage() {
|
||||
val samples = remember {
|
||||
listOf(
|
||||
"""
|
||||
// Everything is an expression
|
||||
val x = 10
|
||||
val status = if (x > 0) "Positive" else "Zero or Negative"
|
||||
|
||||
// Even loops return values!
|
||||
val result = for (i in 1..5) {
|
||||
if (i == 3) break "Found 3!"
|
||||
} else "Not found"
|
||||
|
||||
println("Result: " + result)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Functional power with ranges and collections
|
||||
val squares = (1..10)
|
||||
.filter { it % 2 == 0 }
|
||||
.map { it * it }
|
||||
|
||||
println("Even squares: " + squares)
|
||||
// Output: [4, 16, 36, 64, 100]
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Flexible map literals and shorthands
|
||||
val id = 101
|
||||
val name = "Lyng"
|
||||
val base = { id:, name: } // Shorthand for id: id, name: name
|
||||
|
||||
val full = { ...base, version: "1.0", status: "active" }
|
||||
println(full)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Modern null safety
|
||||
var config = null
|
||||
config ?= { timeout: 30 } // Assign only if null
|
||||
|
||||
val timeout = config?.timeout ?: 60
|
||||
println("Timeout is: " + timeout)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Destructuring with splat operator
|
||||
val [first, middle..., last] = [1, 2, 3, 4, 5, 6]
|
||||
|
||||
println("First: " + first)
|
||||
println("Middle: " + middle)
|
||||
println("Last: " + last)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Diamond-safe Multiple Inheritance (C3 MRO)
|
||||
interface Logger {
|
||||
fun log(m) = println("[LOG] " + m)
|
||||
}
|
||||
interface Auth {
|
||||
fun login(u) = println("Login: " + u)
|
||||
}
|
||||
|
||||
class App() : Logger, Auth {
|
||||
fun run() {
|
||||
log("Starting...")
|
||||
login("admin")
|
||||
}
|
||||
}
|
||||
App().run()
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Extension functions and properties
|
||||
fun String.shout() = this.toUpperCase() + "!!!"
|
||||
|
||||
println("hello".shout())
|
||||
|
||||
val List.second get = this[1]
|
||||
println([10, 20, 30].second)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Non-local returns from closures
|
||||
fun findFirst(list, predicate) {
|
||||
list.forEach {
|
||||
if (predicate(it)) return@findFirst it
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
val found = findFirst([1, 5, 8, 12]) { it > 10 }
|
||||
println("Found: " + found)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Easy operator overloading
|
||||
class Vector(val x, val y) {
|
||||
override fun plus(other) = Vector(x + other.x, y + other.y)
|
||||
override fun toString() = "Vector(%g, %g)"(x, y)
|
||||
}
|
||||
|
||||
val v1 = Vector(1, 2)
|
||||
val v2 = Vector(3, 4)
|
||||
println(v1 + v2)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Property delegation to Map
|
||||
class User() {
|
||||
var name by Map()
|
||||
}
|
||||
|
||||
val u = User()
|
||||
u.name = "Sergey"
|
||||
println("User name: " + u.name)
|
||||
""".trimIndent(),
|
||||
"""
|
||||
// Implicit coroutines: parallelism without ceremony
|
||||
import lyng.time
|
||||
|
||||
val d1 = launch {
|
||||
delay(100.milliseconds)
|
||||
"Task A finished"
|
||||
}
|
||||
val d2 = launch {
|
||||
delay(50.milliseconds)
|
||||
"Task B finished"
|
||||
}
|
||||
|
||||
println(d1.await())
|
||||
println(d2.await())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
var currentSlide by remember { mutableStateOf((samples.indices).random()) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
ensureSlideshowStyles()
|
||||
while (true) {
|
||||
delay(7000)
|
||||
currentSlide = (currentSlide + 1) % samples.size
|
||||
}
|
||||
}
|
||||
// Hero section
|
||||
Section({ classes("py-4", "py-lg-5") }) {
|
||||
Div({ classes("text-center") }) {
|
||||
@ -44,7 +181,7 @@ fun HomePage() {
|
||||
}
|
||||
}
|
||||
// CTA buttons
|
||||
Div({ classes("d-flex", "justify-content-center", "gap-2", "mb-4") }) {
|
||||
Div({ classes("d-flex", "justify-content-center", "gap-2", "mb-2") }) {
|
||||
A(attrs = {
|
||||
classes("btn", "btn-primary", "btn-lg")
|
||||
attr("href", "#/docs/tutorial.md")
|
||||
@ -72,48 +209,26 @@ fun HomePage() {
|
||||
}
|
||||
}
|
||||
|
||||
// Code sample
|
||||
val code = """
|
||||
// Create, transform, and verify — the Lyng way
|
||||
import lyng.stdlib
|
||||
|
||||
fun findFirstPositive(list) {
|
||||
list.forEach {
|
||||
if (it > 0) return@findFirstPositive it
|
||||
// Code sample slideshow
|
||||
Div({
|
||||
classes("markdown-body", "mt-0", "slide-container", "position-relative")
|
||||
onClick {
|
||||
window.location.hash = "#tryling?code=" + encodeURIComponent(samples[currentSlide])
|
||||
}
|
||||
null
|
||||
}
|
||||
assertEquals(42, findFirstPositive([-1, 42, -5]))
|
||||
|
||||
val data = 1..5 // or [1,2,3,4,5]
|
||||
val evens2 = data.filter { it % 2 == 0 }.map { it * it }
|
||||
assertEquals([4, 16], evens2)
|
||||
|
||||
// Map literal with identifier keys, shorthand, and spread
|
||||
val base = { a: 1, b: 2 }
|
||||
val patch = { b: 3, c: }
|
||||
val m = { "a": 0, ...base, ...patch, d: 4 }
|
||||
assertEquals(1, m["a"]) // base overwrites 0
|
||||
|
||||
// Object expressions: anonymous classes on the fly
|
||||
val worker = object : Runnable {
|
||||
override fun run() = println("Working...")
|
||||
}
|
||||
worker.run()
|
||||
|
||||
// User-defined exceptions: real classes with custom fields
|
||||
class MyError(val code, m) : Exception(m)
|
||||
try {
|
||||
throw MyError(500, "Something failed")
|
||||
} catch (e: MyError) {
|
||||
println("Error " + e.code + ": " + e.message)
|
||||
}
|
||||
>>> void
|
||||
""".trimIndent()
|
||||
val mapHtml = "<pre><code>" + htmlEscape(code) + "</code></pre>"
|
||||
Div({ classes("markdown-body", "mt-3") }) {
|
||||
}) {
|
||||
Small({
|
||||
classes("position-absolute", "top-0", "end-0", "m-2", "text-muted", "fw-light", "try-hint")
|
||||
}) {
|
||||
Text("click to try")
|
||||
}
|
||||
key(currentSlide) {
|
||||
val slideCode = samples[currentSlide]
|
||||
val mapHtml = "<pre><code>" + htmlEscape(slideCode) + "</code></pre>"
|
||||
Div({ classes("slide-animation") }) {
|
||||
UnsafeRawHtml(highlightLyngHtml(ensureBootstrapCodeBlocks(mapHtml)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Short features list
|
||||
Div({ classes("row", "g-4", "mt-1") }) {
|
||||
@ -147,3 +262,36 @@ try {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ensureSlideshowStyles() {
|
||||
if (window.document.getElementById("slideshow-styles") != null) return
|
||||
val style = window.document.createElement("style") as org.w3c.dom.HTMLStyleElement
|
||||
style.id = "slideshow-styles"
|
||||
style.textContent = """
|
||||
@keyframes slideIn {
|
||||
from { opacity: 0; transform: translateX(30px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
}
|
||||
.slide-animation {
|
||||
animation: slideIn 0.4s ease-out;
|
||||
}
|
||||
.slide-container {
|
||||
min-height: 320px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
background-color: var(--bs-body-bg);
|
||||
}
|
||||
.slide-container:hover {
|
||||
transform: scale(1.005);
|
||||
}
|
||||
.try-hint {
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.slide-container:hover .try-hint {
|
||||
opacity: 1;
|
||||
}
|
||||
""".trimIndent()
|
||||
window.document.head!!.appendChild(style)
|
||||
}
|
||||
|
||||
@ -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,20 +18,30 @@
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.coroutines.launch
|
||||
import net.sergeych.lyng.LyngVersion
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Script
|
||||
import net.sergeych.lyng.ScriptError
|
||||
import net.sergeych.lyngweb.EditorWithOverlay
|
||||
import org.jetbrains.compose.web.dom.*
|
||||
|
||||
@Composable
|
||||
fun TryLyngPage() {
|
||||
fun TryLyngPage(route: String) {
|
||||
val scope = rememberCoroutineScope()
|
||||
var code by remember {
|
||||
val initialCode = remember(route) {
|
||||
val params = route.substringAfter('?', "")
|
||||
val codeParam = params.split('&').find { it.startsWith("code=") }?.substringAfter('=')
|
||||
if (codeParam != null) {
|
||||
try {
|
||||
decodeURIComponent(codeParam)
|
||||
} catch (_: Throwable) {
|
||||
null
|
||||
}
|
||||
} else null
|
||||
}
|
||||
var code by remember(initialCode) {
|
||||
mutableStateOf(
|
||||
"""
|
||||
initialCode ?: """
|
||||
// Welcome to Lyng! Edit and run.
|
||||
// Try changing the data and press Ctrl+Enter or click Run.
|
||||
import lyng.stdlib
|
||||
|
||||
val data = 1..5 // or [1, 2, 3, 4, 5]
|
||||
data.filter { it % 2 == 0 }.map { it * it }
|
||||
@ -54,16 +64,16 @@ fun TryLyngPage() {
|
||||
val printed = StringBuilder()
|
||||
try {
|
||||
// Create a fresh module scope each run so imports and vars are clean
|
||||
val s = Scope.new()
|
||||
val s = Script.newScope()
|
||||
// Capture printed output from Lyng `print`/`println` into the UI result window
|
||||
s.addVoidFn("print") {
|
||||
for ((i, a) in args.withIndex()) {
|
||||
for ((i, a) in this.args.withIndex()) {
|
||||
if (i > 0) printed.append(' ')
|
||||
printed.append(a.toString(this).value)
|
||||
}
|
||||
}
|
||||
s.addVoidFn("println") {
|
||||
for ((i, a) in args.withIndex()) {
|
||||
for ((i, a) in this.args.withIndex()) {
|
||||
if (i > 0) printed.append(' ')
|
||||
printed.append(a.toString(this).value)
|
||||
}
|
||||
@ -118,9 +128,8 @@ fun TryLyngPage() {
|
||||
}
|
||||
|
||||
fun resetCode() {
|
||||
code = """
|
||||
code = initialCode ?: """
|
||||
// Welcome to Lyng! Edit and run.
|
||||
import lyng.stdlib
|
||||
[1,2,3].map { it * 10 }
|
||||
""".trimIndent()
|
||||
output = null
|
||||
|
||||
@ -329,7 +329,7 @@
|
||||
<!-- Top-left version ribbon -->
|
||||
<div class="corner-ribbon bg-danger text-white">
|
||||
<span style="margin-left: -5em">
|
||||
v1.2.0!
|
||||
v1.2.1!
|
||||
</span>
|
||||
</div>
|
||||
<!-- Fixed top navbar for the whole site -->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user