migrated stdlib to separate .lyng files and added build-time generation of Kotlin constants. reduced noise in plugin

This commit is contained in:
sergeych committed 2025-12-04 12:26:38 +01:00
1 parent 6a6de83972
commit b8f27c7a18
6 files changed
+334 -183

No files matched your search

+66
View File
@@ -110,6 +110,72 @@ kotlin {
}
}
// ---- Build-time generation of stdlib text from .lyng files into a Kotlin constant ----
// The .lyng source of the stdlib lives here (module-relative path):
val lyngStdlibDir = layout.projectDirectory.dir("stdlib/lyng")
// The generated Kotlin source will be placed here and added to commonMain sources:
val generatedLyngStdlibDir = layout.buildDirectory.dir("generated/source/lyngStdlib/commonMain/kotlin")
val generateLyngStdlib by tasks.registering {
group = "build"
description = "Generate Kotlin source with embedded lyng stdlib text"
inputs.dir(lyngStdlibDir)
outputs.dir(generatedLyngStdlibDir)
// Simpler: opt out of configuration cache for this ad-hoc generator task
notCompatibleWithConfigurationCache("Uses dynamic file IO in doLast; trivial generator")
doLast {
val targetPkg = "net.sergeych.lyng.stdlib_included"
val targetDir = generatedLyngStdlibDir.get().asFile.resolve(targetPkg.replace('.', '/'))
targetDir.mkdirs()
val files = lyngStdlibDir.asFileTree.matching { include("**/*.lyng") }.files.sortedBy { it.name }
val content = if (files.isEmpty()) "" else buildString {
files.forEachIndexed { idx, f ->
val text = f.readText()
if (idx > 0) append("\n\n")
append(text)
}
}
// Emit as a regular quoted Kotlin string to avoid triple-quote edge cases
fun escapeForQuoted(s: String): String = buildString {
for (ch in s) when (ch) {
'\\' -> append("\\\\")
'"' -> append("\\\"")
'\n' -> append("\\n")
'\r' -> {} // drop CR
'\t' -> append("\\t")
else -> append(ch)
}
}
val body = escapeForQuoted(content)
val sb = StringBuilder()
sb.append("package ").append(targetPkg).append("\n\n")
sb.append("@Suppress(\"Unused\", \"MemberVisibilityCanBePrivate\")\n")
sb.append("internal val rootLyng = \"")
sb.append(body)
sb.append("\"\n")
targetDir.resolve("root_lyng.generated.kt").writeText(sb.toString())
}
}
// Add the generated directory to commonMain sources
kotlin.sourceSets.named("commonMain") {
kotlin.srcDir(generatedLyngStdlibDir)
}
// Ensure ALL Kotlin compilations (all targets/variants) depend on the generator
kotlin.targets.configureEach {
compilations.configureEach {
compileTaskProvider.configure {
dependsOn(generateLyngStdlib)
}
}
}
android {
namespace = "org.jetbrains.kotlinx.multiplatform.library.template"
compileSdk = libs.versions.android.compileSdk.get().toInt()
@@ -14,182 +14,11 @@
* limitations under the License.
*
*/
package net.sergeych.lyng.stdlib_included
internal val rootLyng = """
package lyng.stdlib
fun cached(builder) {
var calculated = false
var value = null
{
if( !calculated ) {
value = builder()
calculated = true
}
value
}
}
fun Iterable.filter(predicate) {
val list = this
flow {
for( item in list ) {
if( predicate(item) ) {ln
emit(item)
}
}
}
}
fun Iterable.drop(n) {
var cnt = 0
filter { cnt++ >= n }
}
fun Iterable.first() {
val i = iterator()
if( !i.hasNext() ) throw NoSuchElementException()
i.next().also { i.cancelIteration() }
}
fun Iterable.last() {
var found = false
var element = null
for( i in this ) {
element = i
found = true
}
if( !found ) throw NoSuchElementException()
element
}
fun Iterable.dropLast(n) {
val list = this
val buffer = RingBuffer(n)
flow {
for( item in list ) {
if( buffer.size == n )
emit( buffer.first() )
buffer += item
}
}
}
fun Iterable.takeLast(n) {
val buffer = RingBuffer(n)
for( item in this ) buffer += item
buffer
}
fun Iterable.joinToString(prefix=" ", transformer=null) {
var result = null
for( part in this ) {
val transformed = transformer?(part)?.toString() ?: part.toString()
if( result == null ) result = transformed
else result += prefix + transformed
}
result ?: ""
}
fun Iterable.any(predicate): Bool {
for( i in this ) {
if( predicate(i) )
break true
} else false
}
fun Iterable.all(predicate): Bool {
!any { !predicate(it) }
}
fun Iterable.sum() {
val i = iterator()
if( i.hasNext() ) {
var result = i.next()
while( i.hasNext() ) result += i.next()
result
}
else null
}
fun Iterable.sumOf(f) {
val i = iterator()
if( i.hasNext() ) {
var result = f(i.next())
while( i.hasNext() ) result += f(i.next())
result
}
else null
}
fun Iterable.minOf( lambda ) {
val i = iterator()
var minimum = lambda( i.next() )
while( i.hasNext() ) {
val x = lambda(i.next())
if( x < minimum ) minimum = x
}
minimum
}
/*
Return maximum value of the given function applied to elements of the collection.
*/
fun Iterable.maxOf( lambda ) {
val i = iterator()
var maximum = lambda( i.next() )
while( i.hasNext() ) {
val x = lambda(i.next())
if( x > maximum ) maximum = x
}
maximum
}
fun Iterable.sorted() {
sortedWith { a, b -> a <=> b }
}
fun Iterable.sortedBy(predicate) {
sortedWith { a, b -> predicate(a) <=> predicate(b) }
}
fun Iterable.shuffled() {
toList().apply { shuffle() }
}
fun List.toString() {
"[" + joinToString(",") + "]"
}
fun List.sortBy(predicate) {
sortWith { a, b -> predicate(a) <=> predicate(b) }
}
fun List.sort() {
sortWith { a, b -> a <=> b }
}
class StackTraceEntry(
val sourceName: String,
val line: Int,
val column: Int,
val sourceString: String
) {
fun toString() {
"%s:%d:%d: %s"(sourceName, line, column, sourceString.trim())
}
}
fun Exception.printStackTrace() {
println(this)
for( entry in stackTrace() ) {
println("\tat "+entry)
}
}
fun String.re() { Regex(this) }
""".trimIndent()
This file used to contain an embedded stdlib text literal. It is now generated at build time
from .lyng sources into build/generated/.../root_lyng.generated.kt. The file is intentionally
left without declarations to avoid duplication across targets.
*/
package net.sergeych.lyng.stdlib_included
+174
View File
@@ -0,0 +1,174 @@
package lyng.stdlib
fun cached(builder) {
var calculated = false
var value = null
{
if( !calculated ) {
value = builder()
calculated = true
}
value
}
}
fun Iterable.filter(predicate) {
val list = this
flow {
for( item in list ) {
if( predicate(item) ) {ln
emit(item)
}
}
}
}
fun Iterable.drop(n) {
var cnt = 0
filter { cnt++ >= n }
}
fun Iterable.first() {
val i = iterator()
if( !i.hasNext() ) throw NoSuchElementException()
i.next().also { i.cancelIteration() }
}
fun Iterable.last() {
var found = false
var element = null
for( i in this ) {
element = i
found = true
}
if( !found ) throw NoSuchElementException()
element
}
fun Iterable.dropLast(n) {
val list = this
val buffer = RingBuffer(n)
flow {
for( item in list ) {
if( buffer.size == n )
emit( buffer.first() )
buffer += item
}
}
}
fun Iterable.takeLast(n) {
val buffer = RingBuffer(n)
for( item in this ) buffer += item
buffer
}
fun Iterable.joinToString(prefix=" ", transformer=null) {
var result = null
for( part in this ) {
val transformed = transformer?(part)?.toString() ?: part.toString()
if( result == null ) result = transformed
else result += prefix + transformed
}
result ?: ""
}
fun Iterable.any(predicate): Bool {
for( i in this ) {
if( predicate(i) )
break true
} else false
}
fun Iterable.all(predicate): Bool {
!any { !predicate(it) }
}
fun Iterable.sum() {
val i = iterator()
if( i.hasNext() ) {
var result = i.next()
while( i.hasNext() ) result += i.next()
result
}
else null
}
fun Iterable.sumOf(f) {
val i = iterator()
if( i.hasNext() ) {
var result = f(i.next())
while( i.hasNext() ) result += f(i.next())
result
}
else null
}
fun Iterable.minOf( lambda ) {
val i = iterator()
var minimum = lambda( i.next() )
while( i.hasNext() ) {
val x = lambda(i.next())
if( x < minimum ) minimum = x
}
minimum
}
/*
Return maximum value of the given function applied to elements of the collection.
*/
fun Iterable.maxOf( lambda ) {
val i = iterator()
var maximum = lambda( i.next() )
while( i.hasNext() ) {
val x = lambda(i.next())
if( x > maximum ) maximum = x
}
maximum
}
fun Iterable.sorted() {
sortedWith { a, b -> a <=> b }
}
fun Iterable.sortedBy(predicate) {
sortedWith { a, b -> predicate(a) <=> predicate(b) }
}
fun Iterable.shuffled() {
toList().apply { shuffle() }
}
fun List.toString() {
"[" + joinToString(",") + "]"
}
fun List.sortBy(predicate) {
sortWith { a, b -> predicate(a) <=> predicate(b) }
}
fun List.sort() {
sortWith { a, b -> a <=> b }
}
class StackTraceEntry(
val sourceName: String,
val line: Int,
val column: Int,
val sourceString: String
) {
fun toString() {
"%s:%d:%d: %s"(sourceName, line, column, sourceString.trim())
}
}
fun Exception.printStackTrace() {
println(this)
for( entry in stackTrace() ) {
println("\tat "+entry)
}
}
fun String.re() { Regex(this) }