v1.5.4 release

This commit is contained in:
Sergey Chernov 2026-04-05 06:34:30 +03:00
parent 657c0c5d18
commit 214f1aec9e
5 changed files with 217 additions and 13 deletions

View File

@ -48,6 +48,7 @@ assertEquals(A.E.One, A.One)
- [Language home](https://lynglang.com)
- [introduction and tutorial](docs/tutorial.md) - start here please
- [Latest release notes (1.5.4)](docs/whats_new.md)
- [What's New in 1.5](docs/whats_new_1_5.md)
- [Testing and Assertions](docs/Testing.md)
- [Filesystem and Processes (lyngio)](docs/lyngio.md)
@ -63,8 +64,7 @@ assertEquals(A.E.One, A.One)
### Add dependency to your project
```kotlin
// update to current please:
val lyngVersion = "1.5.0-SNAPSHOT"
val lyngVersion = "1.5.4"
repositories {
// ...
@ -184,8 +184,7 @@ Designed to add scripting to kotlin multiplatform application in easy and effici
# Language Roadmap
We are now at **v1.5.0-SNAPSHOT** (stable development cycle): basic optimization performed, battery included: standard library is 90% here, initial
support in HTML, popular editors, and IDEA; tools to syntax highlight and format code are ready. It was released closed to schedule.
The current stable release is **v1.5.4**: the 1.5 cycle is feature-complete, compiler/runtime stabilization work is in, and the language, tooling, and site are aligned around the current release.
Ready features:
@ -222,7 +221,7 @@ Ready features:
- [x] assign-if-null operator `?=`
- [x] user-defined exception classes
All of this is documented in the [language site](https://lynglang.com) and locally [docs/language.md](docs/tutorial.md). the current nightly builds published on the site and in the private maven repository.
All of this is documented on the [language site](https://lynglang.com) and locally in [docs/tutorial.md](docs/tutorial.md). The site reflects the current release, while development snapshots continue in the private Maven repository.
## plan: towards v2.0 Next Generation

View File

@ -1,10 +1,75 @@
# What's New in Lyng
This document highlights the latest additions and improvements to the Lyng language and its ecosystem.
For a programmer-focused migration summary, see `docs/whats_new_1_5.md`.
This document highlights the current Lyng release, **1.5.4**, and the broader additions from the 1.5 cycle.
It is intentionally user-facing: new language features, new modules, new tools, and the practical things you can build with them.
For a programmer-focused migration summary across 1.5.x, see `docs/whats_new_1_5.md`.
## Release 1.5.4 Highlights
- `1.5.4` is the stabilization release for the 1.5 feature set.
- The 1.5 line now brings together richer ranges and loops, interpolation, math modules, immutable and observable collections, richer `lyngio`, and much better CLI/IDE support.
- `1.5.4` specifically fixes user-visible issues around decimal arithmetic, mixed numeric flows, list behavior, and observable list hooks.
- The docs, homepage samples, and release metadata now point at the current stable version.
## User Highlights Across 1.5.x
- Descending ranges and loops with `downTo` / `downUntil`
- String interpolation with `$name` and `${expr}`
- Decimal arithmetic, matrices/vectors, and complex numbers
- Immutable collections and opt-in `ObservableList`
- Rich `lyngio` modules for console, HTTP, WebSocket, TCP, and UDP
- CLI improvements including the built-in formatter `lyng fmt`
- Better IDE support and stronger docs around the released feature set
## Language Features
### Descending Ranges and Loops
Lyng ranges are no longer just ascending. You can now write explicit descending ranges with inclusive or exclusive lower bounds.
```lyng
assertEquals([5,4,3,2,1], (5 downTo 1).toList())
assertEquals([5,4,3,2], (5 downUntil 1).toList())
for (i in 10 downTo 1 step 3) {
println(i)
}
```
This also works for characters:
```lyng
assertEquals(['e','c','a'], ('e' downTo 'a' step 2).toList())
```
See [Range](Range.md).
### String Interpolation
Lyng 1.5.1 added built-in string interpolation:
- `$name`
- `${expr}`
Literal dollar forms are explicit too:
- `\$` -> `$`
- `$$` -> `$`
```lyng
val name = "Lyng"
assertEquals("hello, Lyng!", "hello, $name!")
assertEquals("sum=3", "sum=${1+2}")
assertEquals("\$name", "\$name")
assertEquals("\$name", "$$name")
```
If you need legacy literal-dollar behavior in a file, add:
```lyng
// feature: interpolation: off
```
See [Tutorial](tutorial.md).
### Matrix and Vector Module (`lyng.matrix`)
Lyng now ships a dense linear algebra module with immutable double-precision `Matrix` and `Vector` types.
@ -82,6 +147,21 @@ The distinction between `Real -> Decimal` and exact decimal parsing is explicit
See [Decimal](Decimal.md).
### Complex Numbers (`lyng.complex`)
Lyng also ships a complex-number module for ordinary arithmetic in the complex plane.
```lyng
import lyng.complex
assertEquals(Complex(1.0, 2.0), 1 + 2.i)
assertEquals(Complex(2.0, 2.0), 2.i + 2)
val z = 1 + π.i
println(z.exp())
```
See [Complex](Complex.md).
### Binary Operator Interop Registry
Lyng now provides a general mechanism for mixed binary operators through `lyng.operators`.
@ -216,7 +296,7 @@ Singleton objects are declared using the `object` keyword. They provide a conven
```lyng
object Config {
val version = "1.5.0-SNAPSHOT"
val version = "1.5.4"
fun show() = println("Config version: " + version)
}
@ -339,8 +419,124 @@ x.clamp(0..10) // returns 10
`clamp()` correctly handles inclusive (`..`) and exclusive (`..<`) ranges. For discrete types like `Int` and `Char`, clamping to an exclusive upper bound returns the previous value.
### Immutable Collections
Lyng 1.5 adds immutable collection types for APIs that should not expose mutable state through aliases:
- `ImmutableList`
- `ImmutableSet`
- `ImmutableMap`
```lyng
val a = ImmutableList(1,2,3)
val b = a + 4
assertEquals(ImmutableList(1,2,3), a)
assertEquals(ImmutableList(1,2,3,4), b)
```
See [ImmutableList](ImmutableList.md), [ImmutableSet](ImmutableSet.md), and [ImmutableMap](ImmutableMap.md).
### Observable Mutable Lists
For reactive-style code, `lyng.observable` provides `ObservableList` with hooks and change streams.
```lyng
import lyng.observable
val xs = [1,2].observable()
xs.onChange { println("changed") }
xs += 3
```
You can validate or reject mutations in `beforeChange`, listen in `onChange`, and consume structured change events from `changes()`.
See [ObservableList](ObservableList.md).
### Random API
The standard library now includes a built-in random API plus deterministic seeded generators.
```lyng
val rng = Random.seeded(1234)
assert(rng.next(1..10) in 1..10)
assert(rng.next('a'..<'f') in 'a'..<'f')
```
Use:
- `Random.nextInt()`
- `Random.nextFloat()`
- `Random.next(range)`
- `Random.seeded(seed)`
## Tooling and Infrastructure
### Rich Console Apps with `lyng.io.console`
`lyngio` now includes a real console module for terminal applications:
- TTY detection
- screen clearing and cursor movement
- alternate screen buffer
- raw input mode
- typed key and resize events
```lyng
import lyng.io.console
Console.enterAltScreen()
Console.clear()
Console.moveTo(1, 1)
Console.write("Hello from Lyng console app")
Console.flush()
Console.leaveAltScreen()
```
The repository includes a full interactive Tetris sample built on this API.
See [lyng.io.console](lyng.io.console.md).
### HTTP, WebSocket, TCP, and UDP in `lyngio`
`lyngio` grew from filesystem/process support into a broader application-facing I/O library. In 1.5.x it includes:
- `lyng.io.http` for HTTP/HTTPS client calls
- `lyng.io.ws` for WebSocket clients
- `lyng.io.net` for raw TCP/UDP transport
HTTP example:
```lyng
import lyng.io.http
val r = Http.get("https://example.com")
println(r.status)
println(r.text())
```
TCP example:
```lyng
import lyng.io.net
val socket = Net.tcpConnect("127.0.0.1", 4040)
socket.writeUtf8("ping")
socket.flush()
println(socket.readLine())
socket.close()
```
WebSocket example:
```lyng
import lyng.io.ws
val ws = Ws.connect("wss://example.com/socket")
ws.sendText("hello")
println(ws.receive())
ws.close()
```
These modules are capability-gated and host-installed, keeping Lyng safe by default while making networked scripts practical when enabled.
See [lyngio overview](lyngio.md), [lyng.io.http](lyng.io.http.md), [lyng.io.ws](lyng.io.ws.md), and [lyng.io.net](lyng.io.net.md).
### CLI: Formatting Command
A new `fmt` subcommand has been added to the Lyng CLI.
@ -350,6 +546,15 @@ lyng fmt --in-place MyFile.lyng # Format file in-place
lyng fmt --check MyFile.lyng # Check if file needs formatting
```
### CLI: Better Terminal Workflows
The CLI is no longer just a script launcher. In the 1.5 line it also gained:
- built-in formatter support
- integrated `lyng.io.console` support for terminal programs
- downloadable packaged distributions for easier local use
This makes CLI-first scripting and console applications much more practical than in earlier releases.
### IDEA Plugin: Autocompletion
Experimental lightweight autocompletion is now available in the IntelliJ plugin. It features type-aware member suggestions and inheritance-aware completion.

View File

@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
group = "net.sergeych"
version = "1.5.4-SNAPSHOT"
version = "1.5.4"
// Removed legacy buildscript classpath declarations; plugins are applied via the plugins DSL below

View File

@ -104,15 +104,15 @@ class WebsiteSamplesTest {
val name = "Lyng"
val base = { id:, name: } // Shorthand for id: id, name: name
val full = { ...base, version: "1.5.0-SNAPSHOT", status: "active" }
val full = { ...base, version: "1.5.4", status: "stable" }
full
""".trimIndent())
assertTrue(result is ObjMap)
val m = result.map
assertEquals(101L, (m[ObjString("id")] as ObjInt).value)
assertEquals("Lyng", (m[ObjString("name")] as ObjString).value)
assertEquals("1.5.0-SNAPSHOT", (m[ObjString("version")] as ObjString).value)
assertEquals("active", (m[ObjString("status")] as ObjString).value)
assertEquals("1.5.4", (m[ObjString("version")] as ObjString).value)
assertEquals("stable", (m[ObjString("status")] as ObjString).value)
}
@Test

View File

@ -159,7 +159,7 @@ fun HomePage() {
val id = 101
val name = "Lyng"
val base = { id:, name: }
val full = { ...base, status: "active", tags: ["typed", "portable"] }
val full = { ...base, version: "1.5.4", status: "stable", tags: ["typed", "portable"] }
println(full)
""".trimIndent()