update version, site and docs

This commit is contained in:
Sergey Chernov 2026-02-16 19:29:14 +03:00
parent c5b8871c3a
commit afa4b20070
9 changed files with 192 additions and 52 deletions

View File

@ -1,6 +1,31 @@
## Changelog ## 1.5.0-SNAPSHOT
### Unreleased ### Language Features
- Added `return` statement with local and non-local exit support (`return@label`).
- Support for `abstract` classes, methods, and variables.
- Introduced `interface` as a synonym for `abstract class`.
- Multiple Inheritance (MI) completed and enabled by default (C3 MRO).
- Class properties with custom accessors (`get`, `set`).
- Restricted setter visibility (`private set`, `protected set`).
- Late-initialized `val` fields in classes with `Unset` protection.
- Named arguments (`name: value`) and named splats (`...Map`).
- Assign-if-null operator `?=`.
- Refined `protected` visibility rules and `closed` modifier.
- Transient attribute `@Transient` for serialization and equality.
- Unified Delegation model for `val`, `var`, and `fun`.
- Singleton objects (`object`) and object expressions.
### Standard Library
- Added `with(self, block)` for scoped execution.
- Added `clamp()` function and extension.
- Improved `Exception` and `StackTraceEntry` reporting.
### Tooling and IDE
- **CLI**: Added `fmt` as a first-class subcommand for code formatting.
- **IDEA Plugin**: Lightweight autocompletion (experimental), improved docs, and Grazie integration.
- **Highlighters**: Updated TextMate bundle and website highlighters for new syntax.
### Detailed Changes:
- Language: Refined `protected` visibility rules - 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). - 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).
@ -109,16 +134,6 @@
- Documentation updated (docs/OOP.md and tutorial quick-start) to reflect MI with active C3 MRO. - Documentation updated (docs/OOP.md and tutorial quick-start) to reflect MI with active C3 MRO.
Notes:
- Existing single-inheritance code continues to work; resolution reduces to the single base.
- If code previously relied on non-deterministic parent set iteration, C3 MRO provides a predictable order; disambiguate explicitly if needed using `this@Type`/casts.
# Changelog
All notable changes to this project will be documented in this file.
## Unreleased
- CLI: Added `fmt` as a first-class Clikt subcommand. - CLI: Added `fmt` as a first-class Clikt subcommand.
- Default behavior: formats files to stdout (no in-place edits by default). - Default behavior: formats files to stdout (no in-place edits by default).
- Options: - Options:

View File

@ -1,4 +1,4 @@
# Lyng Language AI Specification (V1.3) # Lyng Language AI Specification (V1.5.0-SNAPSHOT)
High-density specification for LLMs. Reference this for all Lyng code generation. High-density specification for LLMs. Reference this for all Lyng code generation.

View File

@ -48,7 +48,7 @@ assertEquals(A.One, A.E.One)
- [Language home](https://lynglang.com) - [Language home](https://lynglang.com)
- [introduction and tutorial](docs/tutorial.md) - start here please - [introduction and tutorial](docs/tutorial.md) - start here please
- [What's New in 1.3](docs/whats_new_1_3.md) - [What's New in 1.5](docs/whats_new_1_5.md)
- [Testing and Assertions](docs/Testing.md) - [Testing and Assertions](docs/Testing.md)
- [Filesystem and Processes (lyngio)](docs/lyngio.md) - [Filesystem and Processes (lyngio)](docs/lyngio.md)
- [Return Statement](docs/return_statement.md) - [Return Statement](docs/return_statement.md)
@ -64,7 +64,7 @@ assertEquals(A.One, A.E.One)
```kotlin ```kotlin
// update to current please: // update to current please:
val lyngVersion = "0.6.1-SNAPSHOT" val lyngVersion = "1.5.0-SNAPSHOT"
repositories { repositories {
// ... // ...
@ -177,7 +177,7 @@ Designed to add scripting to kotlin multiplatform application in easy and effici
# Language Roadmap # Language Roadmap
We are now at **v1.0**: basic optimization performed, battery included: standard library is 90% here, initial 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. support in HTML, popular editors, and IDEA; tools to syntax highlight and format code are ready. It was released closed to schedule.
Ready features: Ready features:
@ -217,7 +217,7 @@ Ready features:
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 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.
## plan: towards v1.5 Enhancing ## plan: towards v2.0 Next Generation
- [x] site with integrated interpreter to give a try - [x] site with integrated interpreter to give a try
- [x] kotlin part public API good docs, integration focused - [x] kotlin part public API good docs, integration focused

View File

@ -1,7 +1,7 @@
# What's New in Lyng # What's New in Lyng
This document highlights the latest additions and improvements to the Lyng language and its ecosystem. 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_3.md`. For a programmer-focused migration summary, see `docs/whats_new_1_5.md`.
## Language Features ## Language Features
@ -102,7 +102,7 @@ Singleton objects are declared using the `object` keyword. They provide a conven
```lyng ```lyng
object Config { object Config {
val version = "1.2.3" val version = "1.5.0-SNAPSHOT"
fun show() = println("Config version: " + version) fun show() = println("Config version: " + version)
} }

93
docs/whats_new_1_5.md Normal file
View File

@ -0,0 +1,93 @@
# What's New in Lyng 1.5 (vs 1.3.* / master)
This document summarizes the significant changes and new features introduced in the 1.5.0-SNAPSHOT development cycle.
## Highlights
- **The `return` Statement**: Added support for local and non-local returns using labels.
- **Abstract Classes and Interfaces**: Full support for `abstract` members and the `interface` keyword.
- **Class Properties with Accessors**: Define `val` and `var` properties with custom `get()` and `set()`.
- **Restricted Setter Visibility**: Use `private set` and `protected set` on fields and properties.
- **Late-initialized `val`**: Support for `val` fields that are initialized in `init` blocks or class bodies.
- **Named Arguments and Splats**: Improved call-site readability with `name: value` and map-based splats.
- **Refined Visibility**: Improved `protected` access and `closed` modifier for better encapsulation.
## Language Features
### The `return` Statement
You can now exit from the innermost enclosing callable (function or lambda) using `return`. Lyng also supports non-local returns to outer scopes using labels.
```lyng
fun findFirst<T>(list: Iterable<T>, predicate: (T)->Bool): T? {
list.forEach {
if (predicate(it)) return@findFirst it
}
null
}
```
### Abstract Classes and Interfaces
Lyng now supports the `abstract` modifier for classes and their members. `interface` is introduced as a synonym for `abstract class`, allowing for rich multi-inheritance patterns.
```lyng
interface Shape {
abstract val area: Real
fun describe() = "Area: %g"(area)
}
class Circle(val radius: Real) : Shape {
override val area get = Math.PI * radius * radius
}
```
### Class Properties with Accessors
Properties can now have custom getters and setters. They do not have automatic backing fields, making them perfect for computed values or delegation.
```lyng
class Rectangle(var width: Real, var height: Real) {
val area: Real get() = width * height
var squareSize: Real
get() = area
set(v) {
width = sqrt(v)
height = width
}
}
```
### Named Arguments and Named Splats
Improve call-site clarity by specifying argument names. You can also expand a Map into named arguments using the splat operator.
```lyng
fun configure(timeout: Int, retry: Int = 3) { ... }
configure(timeout: 5000, retry: 5)
val options = { timeout: 1000, retry: 1 }
configure(...options)
```
### Modern Operators
The `?=` operator allows for concise "assign if null" logic.
```lyng
var cache: Map? = null
cache ?= { "status": "ok" } // Only assigns if cache is null
```
## Tooling and IDE
- **IDEA Plugin**: Significant improvements to autocompletion, documentation tooltips, and natural language support (Grazie integration).
- **CLI**: The `lyng fmt` command is now a first-class tool for formatting code with various options like `--check` and `--in-place`.
- **Performance**: Ongoing optimizations in the bytecode VM and compiler for faster execution and smaller footprint.
## Migration Guide (from 1.3.*)
1. **Check Visibility**: Refined `protected` and `private` rules may catch previously undetected invalid accesses.
2. **Override Keyword**: Ensure all members that override ancestor declarations are marked with the `override` keyword (now mandatory).
3. **Return in Shorthand**: Remember that `return` is forbidden in `=` shorthand functions; use block syntax if you need early exit.
## References
- `docs/OOP.md`
- `docs/return_statement.md`
- `docs/tutorial.md`

View File

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

View File

@ -29,8 +29,8 @@ fun HomePage() {
listOf( listOf(
""" """
// Everything is an expression // Everything is an expression
val x = 10 val x: Int = 10
val status = if (x > 0) "Positive" else "Zero or Negative" val status: String = if (x > 0) "Positive" else "Zero or Negative"
// Even loops return values! // Even loops return values!
val result = for (i in 1..5) { val result = for (i in 1..5) {
@ -40,8 +40,8 @@ fun HomePage() {
println("Result: " + result) println("Result: " + result)
""".trimIndent(), """.trimIndent(),
""" """
// Functional power with ranges and collections // Functional power with generics and collections
val squares = (1..10) val squares: List<Int> = (1..10)
.filter { it % 2 == 0 } .filter { it % 2 == 0 }
.map { it * it } .map { it * it }
@ -49,20 +49,43 @@ fun HomePage() {
// Output: [4, 16, 36, 64, 100] // Output: [4, 16, 36, 64, 100]
""".trimIndent(), """.trimIndent(),
""" """
// Generics and type aliases
typealias Num = Int | Real
class Box<out T: Num>(val value: T) {
fun get(): T = value
}
val intBox = Box(42)
val realBox = Box(3.14)
println("Boxes: " + intBox.get() + ", " + realBox.get())
""".trimIndent(),
"""
// Strict compile-time types and symbol resolution
fun greet(name: String, count: Int) {
for (i in 1..count) {
println("Hello, " + name + "!")
}
}
greet("Lyng", 3)
// greet(10, "error") // This would be a compile-time error!
""".trimIndent(),
"""
// Flexible map literals and shorthands // Flexible map literals and shorthands
val id = 101 val id = 101
val name = "Lyng" val name = "Lyng"
val base = { id:, name: } // Shorthand for id: id, name: name val base = { id:, name: } // Shorthand for id: id, name: name
val full = { ...base, version: "1.0", status: "active" } val full = { ...base, version: "1.5.0-SNAPSHOT", status: "active" }
println(full) println(full)
""".trimIndent(), """.trimIndent(),
""" """
// Modern null safety // Modern null safety
var config = null var config: Map<String, Int>? = null
config ?= { timeout: 30 } // Assign only if null config ?= { timeout: 30 } // Assign only if null
val timeout = config?.timeout ?: 60 val timeout = config?["timeout"] ?: 60
println("Timeout is: " + timeout) println("Timeout is: " + timeout)
""".trimIndent(), """.trimIndent(),
""" """
@ -76,10 +99,10 @@ fun HomePage() {
""" """
// Diamond-safe Multiple Inheritance (C3 MRO) // Diamond-safe Multiple Inheritance (C3 MRO)
interface Logger { interface Logger {
fun log(m) = println("[LOG] " + m) fun log(m: String) = println("[LOG] " + m)
} }
interface Auth { interface Auth {
fun login(u) = println("Login: " + u) fun login(u: String) = println("Login: " + u)
} }
class App() : Logger, Auth { class App() : Logger, Auth {
@ -92,30 +115,30 @@ fun HomePage() {
""".trimIndent(), """.trimIndent(),
""" """
// Extension functions and properties // Extension functions and properties
fun String.shout() = this.toUpperCase() + "!!!" fun String.shout(): String = this.uppercase() + "!!!"
println("hello".shout()) println("hello".shout())
val List.second get = this[1] val List<T>.second: T get() = this[1]
println([10, 20, 30].second) println([10, 20, 30].second)
""".trimIndent(), """.trimIndent(),
""" """
// Non-local returns from closures // Non-local returns from closures
fun findFirst(list, predicate) { fun findFirst<T>(list: Iterable<T>, predicate: (T)->Bool): T? {
list.forEach { list.forEach {
if (predicate(it)) return@findFirst it if (predicate(it)) return@findFirst it
} }
null null
} }
val found = findFirst([1, 5, 8, 12]) { it > 10 } val found: Int? = findFirst([1, 5, 8, 12]) { it > 10 }
println("Found: " + found) println("Found: " + found)
""".trimIndent(), """.trimIndent(),
""" """
// Easy operator overloading // Easy operator overloading
class Vector(val x, val y) { class Vector(val x: Real, val y: Real) {
override fun plus(other) = Vector(x + other.x, y + other.y) override fun plus(other: Vector): Vector = Vector(x + other.x, y + other.y)
override fun toString() = "Vector(%g, %g)"(x, y) override fun toString(): String = "Vector(%g, %g)"(x, y)
} }
val v1 = Vector(1, 2) val v1 = Vector(1, 2)
@ -125,7 +148,7 @@ fun HomePage() {
""" """
// Property delegation to Map // Property delegation to Map
class User() { class User() {
var name by Map() var name: String by Map()
} }
val u = User() val u = User()
@ -165,17 +188,18 @@ fun HomePage() {
Div({ classes("text-center") }) { Div({ classes("text-center") }) {
H1({ classes("display-5", "fw-bold", "mb-3") }) { Text("Welcome to Lyng") } H1({ classes("display-5", "fw-bold", "mb-3") }) { Text("Welcome to Lyng") }
P({ classes("lead", "text-muted", "mb-4") }) { P({ classes("lead", "text-muted", "mb-4") }) {
Text("A lightweight, expressive scripting language designed for clarity, composability, and fun. ") Text("A lightweight, expressive scripting language with strict static typing and functional power. ")
Br() Br()
Text("Run it anywhere Kotlin runs — share logic across JS, JVM, and more.") Text("Run it anywhere Kotlin runs — share logic across JS, JVM, and more.")
} }
Div({ classes("d-flex", "justify-content-center", "gap-2", "flex-wrap", "mb-4") }) { Div({ classes("d-flex", "justify-content-center", "gap-2", "flex-wrap", "mb-4") }) {
// Benefits pills // Benefits pills
listOf( listOf(
"Clean, familiar syntax", "Strict static typing",
"Generics & Type Aliases",
"Implicit coroutines",
"both FP and OOP", "both FP and OOP",
"Batteries-included standard library", "Batteries-included standard library"
"Embeddable and testable"
).forEach { b -> ).forEach { b ->
Span({ classes("badge", "text-bg-secondary", "rounded-pill") }) { Text(b) } Span({ classes("badge", "text-bg-secondary", "rounded-pill") }) { Text(b) }
} }
@ -233,7 +257,7 @@ fun HomePage() {
// Short features list // Short features list
Div({ classes("row", "g-4", "mt-1") }) { Div({ classes("row", "g-4", "mt-1") }) {
listOf( listOf(
Triple("Fast to learn", "Familiar constructs and readable patterns — be productive in minutes.", "lightning"), Triple("Safe and Robust", "Strict compile-time resolution, generics, and null safety catch errors early.", "shield-check"),
Triple("Portable", "Runs wherever Kotlin runs: reuse logic across platforms.", "globe2"), Triple("Portable", "Runs wherever Kotlin runs: reuse logic across platforms.", "globe2"),
Triple("Pragmatic", "A standard library that solves real problems without ceremony.", "gear-fill") Triple("Pragmatic", "A standard library that solves real problems without ceremony.", "gear-fill")
).forEach { (title, text, icon) -> ).forEach { (title, text, icon) ->

View File

@ -22,6 +22,7 @@ import net.sergeych.lyng.Script
import net.sergeych.lyng.ScriptError import net.sergeych.lyng.ScriptError
import net.sergeych.lyng.highlight.TextRange import net.sergeych.lyng.highlight.TextRange
import net.sergeych.lyng.miniast.CompletionItem import net.sergeych.lyng.miniast.CompletionItem
import net.sergeych.lyng.requireScope
import net.sergeych.lyng.tools.LyngDiagnostic import net.sergeych.lyng.tools.LyngDiagnostic
import net.sergeych.lyng.tools.LyngDiagnosticSeverity import net.sergeych.lyng.tools.LyngDiagnosticSeverity
import net.sergeych.lyng.tools.LyngSymbolInfo import net.sergeych.lyng.tools.LyngSymbolInfo
@ -48,11 +49,18 @@ fun TryLyngPage(route: String) {
var code by remember(initialCode) { var code by remember(initialCode) {
mutableStateOf( mutableStateOf(
initialCode ?: """ initialCode ?: """
// Welcome to Lyng! Edit and run. // Welcome to Lyng! Modern scripting with strict types and generics.
// Try changing the data and press Ctrl+Enter or click Run.
typealias Numeric = Int | Real
val data = 1..5 // or [1, 2, 3, 4, 5]
data.filter { it % 2 == 0 }.map { it * it } fun process<T: Numeric>(items: List<T>): List<T> {
items.filter { it > 0 }.map { it * it }
}
val data: List<Int> = [-2, -1, 0, 1, 2]
println("Processed: " + process(data))
// Try changing data or adding Real numbers!
""".trimIndent() """.trimIndent()
) )
} }
@ -94,13 +102,13 @@ fun TryLyngPage(route: String) {
s.addVoidFn("print") { s.addVoidFn("print") {
for ((i, a) in this.args.withIndex()) { for ((i, a) in this.args.withIndex()) {
if (i > 0) printed.append(' ') if (i > 0) printed.append(' ')
printed.append(a.toString(this).value) printed.append(a.toString(this.requireScope()).value)
} }
} }
s.addVoidFn("println") { s.addVoidFn("println") {
for ((i, a) in this.args.withIndex()) { for ((i, a) in this.args.withIndex()) {
if (i > 0) printed.append(' ') if (i > 0) printed.append(' ')
printed.append(a.toString(this).value) printed.append(a.toString(this.requireScope()).value)
} }
printed.append('\n') printed.append('\n')
} }
@ -154,8 +162,8 @@ fun TryLyngPage(route: String) {
fun resetCode() { fun resetCode() {
code = initialCode ?: """ code = initialCode ?: """
// Welcome to Lyng! Edit and run. // Welcome to Lyng! Modern scripting with strict types and generics.
[1,2,3].map { it * 10 } [1, 2, 3].map { it * 10 }
""".trimIndent() """.trimIndent()
output = null output = null
error = null error = null

View File

@ -329,7 +329,7 @@
<!-- Top-left version ribbon --> <!-- Top-left version ribbon -->
<div class="corner-ribbon bg-danger text-white"> <div class="corner-ribbon bg-danger text-white">
<span style="margin-left: -5em"> <span style="margin-left: -5em">
v1.2.0! v1.5.0-SNAPSHOT!
</span> </span>
</div> </div>
<!-- Fixed top navbar for the whole site --> <!-- Fixed top navbar for the whole site -->