Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
23737f9b5c | |||
fb6e2aa49e | |||
95c1da60ed | |||
835333dfad | |||
eefecae7b4 | |||
2ac92a1d09 | |||
464a6dcb99 | |||
eca746b189 | |||
b07452e66e | |||
202e70a99a | |||
f45310f7d9 | |||
48a7f0839c | |||
2adb0ff512 | |||
6735499959 | |||
b5e89c7e78 | |||
84e345b04e | |||
9bd7aa368e | |||
9704f18284 | |||
804087f16d | |||
6d8eed7b8c | |||
e916d9805a | |||
c398496ee0 | |||
299738cffd | |||
62461c09cc | |||
63de82393a | |||
ed0a21cb06 |
42
.run/Tests in 'lyng.lynglib.jvmTest'.run.xml
Normal file
42
.run/Tests in 'lyng.lynglib.jvmTest'.run.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<!--
|
||||
~ Copyright 2025 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tests in 'lyng.lynglib.jvmTest'" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value=":lynglib:cleanJvmTest" />
|
||||
<option value=":lynglib:jvmTest" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>true</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
3
NOTICE
Normal file
3
NOTICE
Normal file
@ -0,0 +1,3 @@
|
||||
The Lyng programming language.
|
||||
Copyright (c) 2024-2025 Sergey Chernov real.sergeych@gmail.com
|
||||
|
49
README.md
49
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
A KMP library and a standalone interpreter
|
||||
|
||||
- simple, compact, intuitive and elegant modern code style:
|
||||
- simple, compact, intuitive and elegant modern code:
|
||||
|
||||
```
|
||||
class Point(x,y) {
|
||||
@ -15,23 +15,31 @@ fun swapEnds(first, args..., last, f) {
|
||||
}
|
||||
```
|
||||
|
||||
- extremely simple Kotlin integration on any platform
|
||||
- extremely simple Kotlin integration on any platform (JVM, JS, WasmJS, Lunux, MacOS, iOS, Windows)
|
||||
- 100% secure: no access to any API you didn't explicitly provide
|
||||
- 100% coroutines! Every function/script is a coroutine, it does not block the thread, no async/await/suspend keyword garbage:
|
||||
- 100% coroutines! Every function/script is a coroutine, it does not block the thread, no async/await/suspend keyword garbage, see [parallelism]
|
||||
|
||||
```
|
||||
val deferred = launch {
|
||||
delay(1.5) // coroutine is delayed for 1.5s, thread is not blocked!
|
||||
"done"
|
||||
}
|
||||
// ...
|
||||
// suspend current coroutine, no thread is blocked again,
|
||||
// and wait for deferred to return something:
|
||||
assertEquals("donw", deferred.await())
|
||||
```
|
||||
and it is multithreaded on platforms supporting it (automatically, no code changes required, just
|
||||
`launch` more coroutines and they will be executed concurrently if possible). See [parallelism]
|
||||
|
||||
- functional style and OOP together, multiple inheritance, implementing interfaces for existing classes, writing extensions.
|
||||
- Any unicode letters can be used as identifiers: `assert( sin(π/2) == 1 )`.
|
||||
- Any Unicode letters can be used as identifiers: `assert( sin(π/2) == 1 )`.
|
||||
|
||||
## Resources:
|
||||
|
||||
- [introduction and tutorial](docs/tutorial.md) - start here please
|
||||
- [Samples directory](docs/samples)
|
||||
- [Books directory](docs)
|
||||
|
||||
## Integration in Kotlin multiplatform
|
||||
|
||||
@ -84,8 +92,8 @@ import com.sun.source.tree.Scope
|
||||
import new.sergeych.lyng.*
|
||||
|
||||
// simple function
|
||||
val scope = Scope().apply {
|
||||
addFn("addArgs") {
|
||||
val scope = Script.newScope().apply {
|
||||
addFn("sumOf") {
|
||||
var sum = 0.0
|
||||
for (a in args) sum += a.toDouble()
|
||||
ObjReal(sum)
|
||||
@ -96,12 +104,14 @@ val scope = Scope().apply {
|
||||
// suspend fun doSomeWork(text: String): Int
|
||||
addFn("doSomeWork") {
|
||||
// this _is_ a suspend lambda, we can call suspend function,
|
||||
// and it won't consume the thread:
|
||||
doSomeWork(args[0].toString()).toObj()
|
||||
// and it won't consume the thread.
|
||||
// note that in kotlin handler, `args` is a list of `Obj` arguments
|
||||
// and return value from this lambda should be Obj too:
|
||||
doSomeWork(args[0]).toObj()
|
||||
}
|
||||
}
|
||||
// adding constant:
|
||||
scope.eval("addArgs(1,2,3)") // <- 6
|
||||
scope.eval("sumOf(1,2,3)") // <- 6
|
||||
```
|
||||
Note that the scope stores all changes in it so you can make calls on a single scope to preserve state between calls.
|
||||
|
||||
@ -119,7 +129,7 @@ Designed to add scripting to kotlin multiplatform application in easy and effici
|
||||
|
||||
- Javascript, WasmJS, native, JVM, android - batteries included.
|
||||
- dynamic types in most elegant and concise way
|
||||
- async, 100% coroutines, supports multiple cores where platofrm supports thread
|
||||
- async, 100% coroutines, supports multiple cores where platform supports thread
|
||||
- good for functional an object-oriented style
|
||||
|
||||
# Language Roadmap
|
||||
@ -139,15 +149,20 @@ Ready features:
|
||||
- [x] exception handling: throw, try-catch-finally, exception classes.
|
||||
- [x] multiplatform maven publication
|
||||
- [x] documentation for the current state
|
||||
|
||||
Under way:
|
||||
|
||||
- [x] maps, sets and sequences (flows?)
|
||||
- [ ] regular exceptions
|
||||
- [x] modules
|
||||
- [x] string formatting and tools
|
||||
- [ ] multiple inheritance for user classes
|
||||
- [x] launch, deferred, CompletableDeferred, Mutex, etc.
|
||||
- [x] multiline strings
|
||||
- [x] typesafe bit-effective serialization
|
||||
- [x] compression/decompression (integrated in serialization)
|
||||
- [x] dynamic fields
|
||||
- [x] function annotations
|
||||
|
||||
### Under way:
|
||||
|
||||
- [ ] regular exceptions
|
||||
- [ ] multiple inheritance for user classes
|
||||
- [ ] site with integrated interpreter to give a try
|
||||
- [ ] kotlin part public API good docs, integration focused
|
||||
- [ ] better stack reporting
|
||||
@ -158,12 +173,12 @@ Planned features.
|
||||
|
||||
- [ ] type specifications
|
||||
- [ ] source docs and maybe lyng.md to a standard
|
||||
- [ ] macro-style kotlin integration or something else to simplify it
|
||||
- [ ] metadata first class access from lyng
|
||||
|
||||
Further
|
||||
|
||||
- [ ] client with GUI support based on compose multiplatform somehow
|
||||
- [ ] notebook - style workbooks with graphs, formulaes, etc.
|
||||
- [ ] notebook - style workbooks with graphs, formulae, etc.
|
||||
- [ ] language server or compose-based lyng-aware editor
|
||||
|
||||
[parallelism]: docs/parallelism.md
|
@ -1,5 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
#
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
root=./lyng/build/install/lyng-jvm/
|
||||
|
@ -1,5 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
#
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
file=./lyng/build/bin/linuxX64/releaseExecutable/lyng.kexe
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.androidLibrary) apply false
|
||||
alias(libs.plugins.kotlinMultiplatform) apply false
|
||||
|
@ -102,20 +102,50 @@ As with [List], it is possible to use ranges as indexes to slice a Buffer:
|
||||
|
||||
>>> void
|
||||
|
||||
## Encoding
|
||||
|
||||
You can encode `String` to buffer using buffer constructor, as was shown. Also, buffer supports out of the box base64 (
|
||||
which is used in `toString`) and hex encoding:
|
||||
|
||||
import lyng.buffer
|
||||
|
||||
// to UTF8 and back:
|
||||
val b = Buffer("hello")
|
||||
assertEquals( "hello", b.decodeUtf8() )
|
||||
|
||||
// to base64 and back:
|
||||
assertEquals( b, Buffer.decodeBase64(b.base64) )
|
||||
assertEquals( b, Buffer.decodeHex(b.hex) )
|
||||
>>> void
|
||||
|
||||
## Members
|
||||
|
||||
| name | meaning | type |
|
||||
|---------------|------------------------------------|---------------|
|
||||
| `size` | size | Int |
|
||||
| `decodeUtf8` | decodee to String using UTF8 rules | Any |
|
||||
| `+` | buffer concatenation | Any |
|
||||
| `toMutable()` | create a mutable copy | MutableBuffer |
|
||||
| name | meaning | type |
|
||||
|----------------------------|-----------------------------------------|---------------|
|
||||
| `size` | size | Int |
|
||||
| `decodeUtf8` | decode to String using UTF8 rules | Any |
|
||||
| `+` | buffer concatenation | Any |
|
||||
| `toMutable()` | create a mutable copy | MutableBuffer |
|
||||
| `hex` | encode to hex strign | String |
|
||||
| `Buffer.decodeHex(hexStr) | decode hex string | Buffer |
|
||||
| `base64` | encode to base64 (url flavor) (2) | String |
|
||||
| `Buffer.decodeBase64(str)` | decode base64 to new Buffer (2) | Buffer |
|
||||
| `toBitInput()` | create bit input from a byte buffer (3) | |
|
||||
|
||||
(1)
|
||||
: optimized implementation that override `Iterable` one
|
||||
|
||||
(2)
|
||||
: base64url alphabet is used without trailing '=', which allows string to be used in URI without escaping. Note that
|
||||
decoding supports both traditional and URL alphabets automatically, and ignores filling `=` characters. Base64URL is
|
||||
well known and mentioned in the internet, for example, [here](https://base64.guru/standards/base64url).
|
||||
|
||||
(3)
|
||||
: `BitInput` is a bit buffer that is used, for example, in [Lynon.decode](serialization.md)
|
||||
|
||||
Also, it inherits methods from [Iterable] and [Array].
|
||||
|
||||
|
||||
[Range]: Range.md
|
||||
|
||||
[Iterable]: Iterable.md
|
@ -26,36 +26,58 @@ Just remember at this stage typed declarations are not yet supported.
|
||||
Having `Iterable` in base classes allows to use it in for loop. Also, each `Iterable` has some utility functions available, for example
|
||||
|
||||
val r = 1..10 // Range is Iterable!
|
||||
assertEquals( [9,10] r.takeLast(2) )
|
||||
assertEquals( [1,2,3] r.take(3) )
|
||||
assertEquals( [9,10] r.drop(8) )
|
||||
assertEquals( [1,2] r.dropLast(8) )
|
||||
assertEquals( [9,10], r.takeLast(2).toList() )
|
||||
assertEquals( [1,2,3], r.take(3).toList() )
|
||||
assertEquals( [9,10], r.drop(8).toList() )
|
||||
assertEquals( [1,2], r.dropLast(8).toList() )
|
||||
>>> void
|
||||
|
||||
## joinToString
|
||||
|
||||
This methods convert any iterable to a string joining string representation of each element, optionally transforming it and joining using specified suffix.
|
||||
|
||||
Iterable.joinToString(suffux=' ', transform=null)
|
||||
|
||||
- if `Iterable` `isEmpty`, the empty string `""` is returned.
|
||||
- `suffix` is inserted between items when there are more than one.
|
||||
- `transform` of specified is applied to each element, otherwise its `toString()` method is used.
|
||||
|
||||
Here is the sample:
|
||||
|
||||
assertEquals( (1..3).joinToString(), "1 2 3")
|
||||
assertEquals( (1..3).joinToString(":"), "1:2:3")
|
||||
assertEquals( (1..3).joinToString { it * 10 }, "10 20 30")
|
||||
>>> void
|
||||
|
||||
## Instance methods:
|
||||
|
||||
| fun/method | description |
|
||||
|-----------------|---------------------------------------------------------------------------------|
|
||||
| toList() | create a list from iterable |
|
||||
| toSet() | create a set from iterable |
|
||||
| contains(i) | check that iterable contains `i` |
|
||||
| `i in iterator` | same as `contains(i)` |
|
||||
| isEmpty() | check iterable is empty |
|
||||
| forEach(f) | call f for each element |
|
||||
| toMap() | create a map from list of key-value pairs (arrays of 2 items or like) |
|
||||
| map(f) | create a list of values returned by `f` called for each element of the iterable |
|
||||
| indexOf(i) | return index if the first encounter of i or a negative value if not found |
|
||||
| associateBy(kf) | create a map where keys are returned by kf that will be called for each element |
|
||||
| first | first element (1) |
|
||||
| last | last element (1) |
|
||||
| take(n) | return [Iterable] of up to n first elements |
|
||||
| taleLast(n) | return [Iterable] of up to n last elements |
|
||||
| drop(n) | return new [Iterable] without first n elements |
|
||||
| dropLast(n) | return new [Iterable] without last n elements |
|
||||
|
||||
| fun/method | description |
|
||||
|-------------------|---------------------------------------------------------------------------|
|
||||
| toList() | create a list from iterable |
|
||||
| toSet() | create a set from iterable |
|
||||
| contains(i) | check that iterable contains `i` |
|
||||
| `i in iterator` | same as `contains(i)` |
|
||||
| isEmpty() | check iterable is empty |
|
||||
| forEach(f) | call f for each element |
|
||||
| toMap() | create a map from list of key-value pairs (arrays of 2 items or like) |
|
||||
| map(f) | create a list of values returned by `f` called for each element of the iterable |
|
||||
| indexOf(i) | return index if the first encounter of i or a negative value if not found |
|
||||
| associateBy(kf) | create a map where keys are returned by kf that will be called for each element |
|
||||
| first | first element (1) |
|
||||
| last | last element (1) |
|
||||
| take(n) | return [Iterable] of up to n first elements |
|
||||
| taleLast(n) | return [Iterable] of up to n last elements |
|
||||
| drop(n) | return new [Iterable] without first n elements |
|
||||
| dropLast(n) | return new [Iterable] without last n elements |
|
||||
| joinToString(s,t) | convert iterable to string, see (2) |
|
||||
|
||||
(1)
|
||||
: throws `NoSuchElementException` if there is no such element
|
||||
|
||||
(2)
|
||||
: `joinToString(suffix=" ",transform=null)`: suffix is inserted between items if there are more than one, trasnfom is optional function applied to each item that must return result string for an item, otherwise `item.toString()` is used.
|
||||
|
||||
fun Iterable.toList(): List
|
||||
fun Iterable.toSet(): Set
|
||||
fun Iterable.indexOf(element): Int
|
||||
|
57
docs/OOP.md
57
docs/OOP.md
@ -235,6 +235,63 @@ as they are modifying the type, not the context.
|
||||
|
||||
Beware of it. We might need to reconsider it later.
|
||||
|
||||
## dynamic symbols
|
||||
|
||||
Sometimes it is convenient to provide methods and variables whose names are not known at compile time. For example, it could be external interfaces not known to library code, user-defined data fields, etc. You can use `dynamic` function to create such:
|
||||
|
||||
// val only dynamic object
|
||||
val accessor = dynamic {
|
||||
// all symbol reads are redirected here:
|
||||
get { name ->
|
||||
// lets provide one dynamic symbol:
|
||||
if( name == "foo" ) "bar" else null
|
||||
// consider also throw SymbolNotDefinedException
|
||||
}
|
||||
}
|
||||
|
||||
// now we can access dynamic "fields" of accessor:
|
||||
assertEquals("bar", accessor.foo)
|
||||
assertEquals(null, accessor.bar)
|
||||
>>> void
|
||||
|
||||
The same we can provide writable dynamic fields (var-type), adding set method:
|
||||
|
||||
// store one dynamic field here
|
||||
var storedValueForBar = null
|
||||
|
||||
// create dynamic object with 2 fields:
|
||||
val accessor = dynamic {
|
||||
get { name ->
|
||||
when(name) {
|
||||
// constant field
|
||||
"foo" -> "bar"
|
||||
// mutable field
|
||||
"bar" -> setValueForBar
|
||||
|
||||
else -> throw SymbolNotFoundException()
|
||||
}
|
||||
}
|
||||
set { name, value ->
|
||||
// only 'bar' is mutable:
|
||||
if( name == "bar" )
|
||||
storedValueForBar = value
|
||||
// the rest is immotable. consider throw also
|
||||
// SymbolNotFoundException when needed.
|
||||
else throw IllegalAssignmentException("Can't assign "+name)
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("bar", accessor.foo)
|
||||
assertEquals(null, accessor.bar)
|
||||
accessor.bar = "buzz"
|
||||
assertEquals("buzz", accessor.bar)
|
||||
|
||||
assertThrows {
|
||||
accessor.bad = "!23"
|
||||
}
|
||||
|
||||
Of course, you can return any object from dynamic fields; returning lambdas let create _dynamic methods_ - the callable method. It is very convenient to implement libraries with dynamic remote interfaces, etc.
|
||||
|
||||
# Theory
|
||||
|
||||
## Basic principles:
|
||||
|
@ -112,6 +112,49 @@ arguments list in almost arbitrary ways. For example:
|
||||
)
|
||||
>>> void
|
||||
|
||||
,
|
||||
# Annotations
|
||||
|
||||
Annotation in Lyng resembles these proposed for Javascript. Annotation is just regular functions that, if used as annotation, are called when defining a function, var, val or class.
|
||||
|
||||
## Function annotation
|
||||
|
||||
When used without params, annotation calls a function with two arguments: actual function name and callable function body. Function annotation __must return callable for the function__, either what it received as a second argument (most often), or something else. Annotation name convention is upper scaled:
|
||||
|
||||
var annotated = false
|
||||
|
||||
// this is annotation function:
|
||||
fun Special(name, body) {
|
||||
assertEquals("foo", name)
|
||||
annotated = true
|
||||
{ body(it) + 100 }
|
||||
}
|
||||
|
||||
@Special
|
||||
fun foo(value) { value + 1 }
|
||||
|
||||
assert(annotated)
|
||||
assertEquals(111, foo( 10 ))
|
||||
>>> void
|
||||
|
||||
Function annotation can have more args specified at call time. There arguments must follow two mandatory ones (name and body). Use default values in order to allow parameterless annotation to be used simultaneously.
|
||||
|
||||
val registered = Map()
|
||||
|
||||
// it is recommended to provide defaults for extra parameters:
|
||||
fun Registered(name, body, overrideName = null) {
|
||||
registered[ overrideName ?: name ] = body
|
||||
body
|
||||
}
|
||||
|
||||
// witout parameters is Ok as we provided default value
|
||||
@Registered
|
||||
fun foo() { "called foo" }
|
||||
|
||||
@Registered("bar")
|
||||
fun foo2() { "called foo2" }
|
||||
|
||||
assertEquals(registered["foo"](), "called foo")
|
||||
assertEquals(registered["bar"](), "called foo2")
|
||||
>>> void
|
||||
|
||||
[parallelism]: parallelism.md
|
||||
|
14
docs/development/scope_resolution.md
Normal file
14
docs/development/scope_resolution.md
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
Provide:
|
||||
|
||||
|
||||
fun outer(a1)
|
||||
// a1 is caller.a1:arg
|
||||
val a1_local = a1 + 1
|
||||
// we return lambda:
|
||||
{ it ->
|
||||
// a1_local
|
||||
a1_lcoal + it
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ $$ \ln(1+x)=x-{\dfrac {x^{2}}{2}}+{\dfrac {x^{3}}{3}}-\cdots =\sum \limits _{n=0
|
||||
}
|
||||
assert( почти_равны( 0.0005, 0.000501 ) )
|
||||
|
||||
Во многих случаях вычисление $n+1$ члена значительно проще cчитается от предыдущего члена, в нашем случае это можно было бы записать через итератор, что мы вскоре добавим.
|
||||
Во многих случаях вычисление $n+1$ члена значительно проще cчитается от предыдущего члена, в нашем случае это можно было бы записать через итератор, см [Iterable] и `flow` в [parallelism].
|
||||
|
||||
(продолжение следует)
|
||||
[Iterable]: ../Iterable.md
|
||||
[parallelism]: ../parallelism.md
|
||||
|
46
docs/serialization.md
Normal file
46
docs/serialization.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Lyng serialization
|
||||
|
||||
Lyng has builting binary bit-effective serialization format, called Lynon for LYng Object Notation. It is typed, binary, implements caching, automatic compression, variable-length ints, one-bit Booleans an many nice features.
|
||||
|
||||
It is as simple as:
|
||||
|
||||
import lyng.serialization
|
||||
|
||||
val text = "
|
||||
We hold these truths to be self-evident, that all men are created equal,
|
||||
that they are endowed by their Creator with certain unalienable Rights,
|
||||
that among these are Life, Liberty and the pursuit of Happiness.
|
||||
"
|
||||
val encodedBits = Lynon.encode(text)
|
||||
|
||||
// decode bits source:
|
||||
assertEquals( text, Lynon.decode(encodedBits) )
|
||||
|
||||
// compression was used automatically
|
||||
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:
|
||||
|
||||
import lyng.serialization
|
||||
|
||||
class Point(x,y)
|
||||
|
||||
val p = Lynon.decode( Lynon.encode( Point(5,6) ) )
|
||||
|
||||
assertEquals( 5, p.x )
|
||||
assertEquals( 6, p.y )
|
||||
>>> void
|
||||
|
||||
|
||||
just as expected.
|
||||
|
||||
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:
|
||||
|
||||
buffer.toBitInput()
|
||||
|
||||
this possibly creates extra zero bits at the end, as bit content could be shorter than byte-grained but for the Lynon format it does not make sense. Note that when you serialize [BitBuffer], exact number of bits is written. To convert bit buffer to bytes:
|
||||
|
||||
Lynon.encode("hello").toBuffer()
|
||||
|
||||
(topic is incomplete and under construction)
|
@ -225,6 +225,19 @@ It works much like `also`, but is executed in the context of the source object:
|
||||
assertEquals(p, Point(2,3))
|
||||
>>> void
|
||||
|
||||
## run
|
||||
|
||||
Executes a block after it returning the value passed by the block. for example, can be used with elvis operator:
|
||||
|
||||
var someVar = null
|
||||
val result = someVar ?: run {
|
||||
someVar = 121
|
||||
"reset"
|
||||
}
|
||||
assertEquals("reset", result)
|
||||
assertEquals(121, someVar)
|
||||
>>> void
|
||||
|
||||
## Math
|
||||
|
||||
It is rather simple, like everywhere else:
|
||||
@ -475,7 +488,7 @@ Lyng has built-in mutable array class `List` with simple literals:
|
||||
[1, "two", 3.33].size
|
||||
>>> 3
|
||||
|
||||
[List] is an implementation of the type `Array`, and through it `Collection` and [Iterable].
|
||||
[List] is an implementation of the type `Array`, and through it `Collection` and [Iterable]. Please read [Iterable], many collection based methods are implemented there.
|
||||
|
||||
Lists can contain any type of objects, lists too:
|
||||
|
||||
@ -747,7 +760,7 @@ You can thest that _when expression_ is _contained_, or not contained, in some o
|
||||
`!in container`. The container is any object that provides `contains` method, otherwise the runtime exception will be
|
||||
thrown.
|
||||
|
||||
Typical builtin types that are containers (e.g. support `conain`):
|
||||
Typical builtin types that are containers (e.g. support `contains`):
|
||||
|
||||
| class | notes |
|
||||
|------------|------------------------------------------------|
|
||||
@ -756,6 +769,8 @@ Typical builtin types that are containers (e.g. support `conain`):
|
||||
| List | faster than Array's |
|
||||
| String | character in string or substring in string (3) |
|
||||
| Range | object is included in the range (2) |
|
||||
| Buffer | byte is in buffer |
|
||||
| RingBuffer | object is in buffer |
|
||||
|
||||
(1)
|
||||
: Iterable is not the container as it can be infinite
|
||||
@ -1120,6 +1135,25 @@ These should be imported from [lyng.time](time.md). For example:
|
||||
|
||||
See [more docs on time manipulation](time.md)
|
||||
|
||||
# Enums
|
||||
|
||||
For the moment, only simple enums are implemented. Enum is a list of constants, represented also by their _ordinal_ - [Int] value.
|
||||
|
||||
enum Color {
|
||||
RED, GREEN, BLUE
|
||||
}
|
||||
|
||||
assert( Color.RED is Color )
|
||||
|
||||
assertEquals( 2, Color.BLUE.ordinal )
|
||||
assertEquals( "BLUE", Color.BLUE.name )
|
||||
|
||||
assertEquals( [Color.RED,Color.GREEN,Color.BLUE], Color.entries)
|
||||
assertEquals( Color.valueOf("GREEN"), Color.GREEN )
|
||||
>>> void
|
||||
|
||||
Enums are serialized as ordinals. Please note that due to caching, serialized string arrays could be even more compact than enum arrays, until `Lynon.encodeTyped` will be implemented.
|
||||
|
||||
# Comments
|
||||
|
||||
// single line comment
|
||||
@ -1259,24 +1293,39 @@ String literal could be multiline:
|
||||
"Hello
|
||||
World"
|
||||
|
||||
though multiline literals is yet work in progress.
|
||||
In this case, it will be passed literally ot "hello\n World". But, if there are
|
||||
several lines with common left indent, it will be removed, also, forst and last lines,
|
||||
if blank, will be removed too, for example:
|
||||
|
||||
println("
|
||||
This is a multiline text.
|
||||
This is a second line.
|
||||
")
|
||||
>>> This is a multiline text.
|
||||
>>> This is a second line.
|
||||
>>> void
|
||||
|
||||
- as expected, empty lines and common indent were removed. It is much like kotlin's `""" ... """.trimIndent()` technique, but simpler ;)
|
||||
|
||||
# Built-in functions
|
||||
|
||||
See [math functions](math.md). Other general purpose functions are:
|
||||
|
||||
| name | description |
|
||||
|--------------------------------------------|-----------------------------------------------------------|
|
||||
| assert(condition,message="assertion failed") | runtime code check. There will be an option to skip them |
|
||||
| assertEquals(a,b) | |
|
||||
| assertNotEquals(a,b) | |
|
||||
| assertTrows { /* block */ } | |
|
||||
| check(condition, message=<default>) | throws IllegalStateException" of condition isn't met |
|
||||
| require(condition, message=<default>) | throws IllegalArgumentException" of condition isn't met |
|
||||
| println(args...) | Open for overriding, it prints to stdout with newline. |
|
||||
| print(args...) | Open for overriding, it prints to stdout without newline. |
|
||||
| flow {} | create flow sequence, see [parallelism] |
|
||||
| delay, launch, yield | see [parallelism] |
|
||||
| name | description |
|
||||
|----------------------------------------------|------------------------------------------------------------|
|
||||
| assert(condition,message="assertion failed") | runtime code check. There will be an option to skip them |
|
||||
| assertEquals(a,b) | |
|
||||
| assertNotEquals(a,b) | |
|
||||
| assertTrows { /* block */ } | |
|
||||
| check(condition, message=<default>) | throws IllegalStateException" of condition isn't met |
|
||||
| require(condition, message=<default>) | throws IllegalArgumentException" of condition isn't met |
|
||||
| println(args...) | Open for overriding, it prints to stdout with newline. |
|
||||
| print(args...) | Open for overriding, it prints to stdout without newline. |
|
||||
| flow {} | create flow sequence, see [parallelism] |
|
||||
| delay, launch, yield | see [parallelism] |
|
||||
| cached(builder) | remembers builder() on first invocation and return it then |
|
||||
| let, also, apply, run | see above, flow controls |
|
||||
|
||||
|
||||
# Built-in constants
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
#
|
||||
#
|
||||
|
||||
#Gradle
|
||||
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
|
||||
org.gradle.caching=true
|
||||
|
17
gradle/wrapper/gradle-wrapper.properties
vendored
17
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,3 +1,20 @@
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
#
|
||||
#
|
||||
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
|
5
gradlew
vendored
5
gradlew
vendored
@ -1,13 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright 2025 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
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
# 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,
|
||||
@ -15,6 +15,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "2.1.21"
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
import kotlin.system.exitProcess
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
|
||||
|
||||
package net.sergeych
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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_cli
|
||||
|
||||
import net.sergeych.runMain
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.runMain
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
@ -1,4 +1,23 @@
|
||||
@file:OptIn(ExperimentalForeignApi::class, ExperimentalForeignApi::class, ExperimentalForeignApi::class)
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalForeignApi::class, ExperimentalForeignApi::class, ExperimentalForeignApi::class,
|
||||
ExperimentalForeignApi::class
|
||||
)
|
||||
|
||||
package net.sergeych
|
||||
|
||||
|
@ -1,10 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 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 com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.8.4-SNAPSHOT"
|
||||
version = "0.8.14-SNAPSHOT"
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
enum class AccessType(val isMutable: Boolean) {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.Obj
|
||||
@ -31,13 +48,12 @@ data class ArgsDeclaration(val params: List<Item>, val endTokenType: Token.Type)
|
||||
arguments: Arguments = scope.args,
|
||||
defaultAccessType: AccessType = AccessType.Var,
|
||||
defaultVisibility: Visibility = Visibility.Public,
|
||||
defaultRecordType: ObjRecord.Type = ObjRecord.Type.ConstructorField
|
||||
) {
|
||||
fun assign(a: Item, value: Obj) {
|
||||
scope.addItem(a.name, (a.accessType ?: defaultAccessType).isMutable,
|
||||
value.byValueCopy(),
|
||||
a.visibility ?: defaultVisibility,
|
||||
recordType = defaultRecordType)
|
||||
recordType = ObjRecord.Type.Argument)
|
||||
}
|
||||
|
||||
// will be used with last lambda arg fix
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.Obj
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
//fun buildDoubleFromParts(
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.ObjRecord
|
||||
@ -7,10 +24,33 @@ import net.sergeych.lyng.obj.ObjRecord
|
||||
* Inherits [Scope.args] and [Scope.thisObj] from [callScope] and adds lookup for symbols
|
||||
* from [closureScope] with proper precedence
|
||||
*/
|
||||
class ClosureScope(val callScope: Scope,val closureScope: Scope) : Scope(callScope, callScope.args, thisObj = callScope.thisObj) {
|
||||
class ClosureScope(val callScope: Scope, val closureScope: Scope) :
|
||||
Scope(callScope, callScope.args, thisObj = callScope.thisObj) {
|
||||
|
||||
override fun get(name: String): ObjRecord? {
|
||||
// closure should be treated below callScope
|
||||
return super.get(name) ?: closureScope.get(name)
|
||||
// we take arguments from the callerScope, the rest
|
||||
// from the closure.
|
||||
|
||||
// note using super, not callScope, as arguments are assigned by the constructor
|
||||
// and are not assigned yet to vars in callScope self:
|
||||
super.objects[name]?.let {
|
||||
// if( name == "predicate" ) {
|
||||
// println("predicate: ${it.type.isArgument}: ${it.value}")
|
||||
// }
|
||||
if( it.type.isArgument ) return it
|
||||
}
|
||||
return closureScope.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
class ApplyScope(_parent: Scope,val applied: Scope) : Scope(_parent, thisObj = applied.thisObj) {
|
||||
|
||||
override fun get(name: String): ObjRecord? {
|
||||
return applied.get(name) ?: super.get(name)
|
||||
}
|
||||
|
||||
override fun applyClosure(closure: Scope): Scope {
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
sealed class CodeContext {
|
||||
class Module(@Suppress("unused") val packageName: String?): CodeContext()
|
||||
class Function(val name: String): CodeContext()
|
||||
class ClassBody(val name: String): CodeContext()
|
||||
}
|
@ -1,5 +1,23 @@
|
||||
/*
|
||||
* Copyright 2025 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 ObjEnumClass
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportProvider
|
||||
|
||||
@ -27,6 +45,17 @@ class Compiler(
|
||||
|
||||
private fun popInitScope(): MutableList<Statement> = initStack.removeLast()
|
||||
|
||||
private val codeContexts = mutableListOf<CodeContext>(CodeContext.Module(null))
|
||||
|
||||
private suspend fun <T> inCodeContext(context: CodeContext, f: suspend () -> T): T {
|
||||
return try {
|
||||
codeContexts.add(context)
|
||||
f()
|
||||
} finally {
|
||||
codeContexts.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun parseScript(): Script {
|
||||
val statements = mutableListOf<Statement>()
|
||||
val start = cc.currentPos()
|
||||
@ -65,9 +94,17 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
}
|
||||
parseStatement(braceMeansLambda = true)?.also {
|
||||
val s = parseStatement(braceMeansLambda = true)?.also {
|
||||
statements += it
|
||||
} ?: break
|
||||
}
|
||||
if (s == null) {
|
||||
when (t.type) {
|
||||
Token.Type.RBRACE, Token.Type.EOF, Token.Type.SEMICOLON -> {}
|
||||
else ->
|
||||
throw ScriptError(t.pos, "unexpeced `${t.value}` here")
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
} while (true)
|
||||
return Script(start, statements)//returnScope.needCatch)
|
||||
@ -88,7 +125,10 @@ class Compiler(
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
private var lastAnnotation: (suspend (Scope, ObjString, Statement) -> Statement)? = null
|
||||
|
||||
private suspend fun parseStatement(braceMeansLambda: Boolean = false): Statement? {
|
||||
lastAnnotation = null
|
||||
while (true) {
|
||||
val t = cc.next()
|
||||
return when (t.type) {
|
||||
@ -105,6 +145,11 @@ class Compiler(
|
||||
parseExpression()
|
||||
}
|
||||
|
||||
Token.Type.ATLABEL -> {
|
||||
lastAnnotation = parseAnnotation(t)
|
||||
continue
|
||||
}
|
||||
|
||||
Token.Type.LABEL -> continue
|
||||
Token.Type.SINLGE_LINE_COMMENT, Token.Type.MULTILINE_COMMENT -> continue
|
||||
|
||||
@ -331,6 +376,13 @@ class Compiler(
|
||||
|
||||
}
|
||||
|
||||
"throw" -> {
|
||||
val s = parseThrowStatement()
|
||||
operand = Accessor {
|
||||
s.execute(it).asReadonly
|
||||
}
|
||||
}
|
||||
|
||||
else -> operand?.let { left ->
|
||||
// selector: <lvalue>, '.' , <id>
|
||||
// we replace operand with selector code, that
|
||||
@ -470,7 +522,7 @@ class Compiler(
|
||||
|
||||
val callStatement = statement {
|
||||
// and the source closure of the lambda which might have other thisObj.
|
||||
val context = ClosureScope(this, closure!!) //AppliedScope(closure!!, args, this)
|
||||
val context = this.applyClosure(closure!!)
|
||||
if (argsDeclaration == null) {
|
||||
// no args: automatic var 'it'
|
||||
val l = args.list
|
||||
@ -482,7 +534,7 @@ class Compiler(
|
||||
// more args: it is a list of args
|
||||
else -> ObjList(l.toMutableList())
|
||||
}
|
||||
context.addItem("it", false, itValue)
|
||||
context.addItem("it", false, itValue, recordType = ObjRecord.Type.Argument)
|
||||
} else {
|
||||
// assign vars as declared the standard way
|
||||
argsDeclaration.assignToContext(context, defaultAccessType = AccessType.Val)
|
||||
@ -491,7 +543,7 @@ class Compiler(
|
||||
}
|
||||
|
||||
return Accessor { x ->
|
||||
if (closure == null) closure = x
|
||||
closure = x
|
||||
callStatement.asReadonly
|
||||
}
|
||||
}
|
||||
@ -810,6 +862,26 @@ class Compiler(
|
||||
return parseNumberOrNull(isPlus) ?: throw ScriptError(cc.currentPos(), "Expecting number")
|
||||
}
|
||||
|
||||
suspend fun parseAnnotation(t: Token): (suspend (Scope, ObjString, Statement) -> Statement) {
|
||||
val extraArgs = parseArgsOrNull()
|
||||
println("annotation ${t.value}: args: $extraArgs")
|
||||
return { scope, name, body ->
|
||||
val extras = extraArgs?.first?.toArguments(scope, extraArgs.second)?.list
|
||||
val required = listOf(name, body)
|
||||
val args = extras?.let { required + it } ?: required
|
||||
val fn = scope.get(t.value)?.value ?: scope.raiseSymbolNotFound("annotation not found: ${t.value}")
|
||||
if (fn !is Statement) scope.raiseIllegalArgument("annotation must be callable, got ${fn.objClass}")
|
||||
(fn.execute(scope.copy(Arguments(args))) as? Statement)
|
||||
?: scope.raiseClassCastError("function annotation must return callable")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun parseArgsOrNull(): Pair<List<ParsedArgument>, Boolean>? =
|
||||
if (cc.skipNextIf(Token.Type.LPAREN))
|
||||
parseArgs()
|
||||
else
|
||||
null
|
||||
|
||||
/**
|
||||
* Parse keyword-starting statement.
|
||||
* @return parsed statement or null if, for example. [id] is not among keywords
|
||||
@ -823,7 +895,8 @@ class Compiler(
|
||||
"break" -> parseBreakStatement(id.pos)
|
||||
"continue" -> parseContinueStatement(id.pos)
|
||||
"if" -> parseIfStatement()
|
||||
"class" -> parseClassDeclaration(false)
|
||||
"class" -> parseClassDeclaration()
|
||||
"enum" -> parseEnumDeclaration()
|
||||
"try" -> parseTryStatement()
|
||||
"throw" -> parseThrowStatement()
|
||||
"when" -> parseWhenStatement()
|
||||
@ -833,8 +906,18 @@ class Compiler(
|
||||
val isExtern = cc.skipId("extern")
|
||||
when {
|
||||
cc.matchQualifiers("fun", "private") -> parseFunctionDeclaration(Visibility.Private, isExtern)
|
||||
cc.matchQualifiers("fun", "private", "static") -> parseFunctionDeclaration(Visibility.Private, isExtern, isStatic = true)
|
||||
cc.matchQualifiers("fun", "static") -> parseFunctionDeclaration(Visibility.Public, isExtern, isStatic = true)
|
||||
cc.matchQualifiers("fun", "private", "static") -> parseFunctionDeclaration(
|
||||
Visibility.Private,
|
||||
isExtern,
|
||||
isStatic = true
|
||||
)
|
||||
|
||||
cc.matchQualifiers("fun", "static") -> parseFunctionDeclaration(
|
||||
Visibility.Public,
|
||||
isExtern,
|
||||
isStatic = true
|
||||
)
|
||||
|
||||
cc.matchQualifiers("fn", "private") -> parseFunctionDeclaration(Visibility.Private, isExtern)
|
||||
cc.matchQualifiers("fun", "open") -> parseFunctionDeclaration(isOpen = true, isExtern = isExtern)
|
||||
cc.matchQualifiers("fn", "open") -> parseFunctionDeclaration(isOpen = true, isExtern = isExtern)
|
||||
@ -1100,78 +1183,115 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun parseClassDeclaration(isStruct: Boolean): Statement {
|
||||
private fun parseEnumDeclaration(): Statement {
|
||||
val nameToken = cc.requireToken(Token.Type.ID)
|
||||
val constructorArgsDeclaration =
|
||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
||||
parseArgsDeclaration(isClassDeclaration = true)
|
||||
else null
|
||||
// so far only simplest enums:
|
||||
val names = mutableListOf<String>()
|
||||
// skip '{'
|
||||
cc.skipTokenOfType(Token.Type.LBRACE)
|
||||
|
||||
if (constructorArgsDeclaration != null && constructorArgsDeclaration.endTokenType != Token.Type.RPAREN)
|
||||
throw ScriptError(
|
||||
nameToken.pos,
|
||||
"Bad class declaration: expected ')' at the end of the primary constructor"
|
||||
)
|
||||
do {
|
||||
val t = cc.skipWsTokens()
|
||||
when (t.type) {
|
||||
Token.Type.ID -> {
|
||||
names += t.value
|
||||
val t1 = cc.skipWsTokens()
|
||||
when (t1.type) {
|
||||
Token.Type.COMMA ->
|
||||
continue
|
||||
|
||||
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||
val t = cc.next()
|
||||
Token.Type.RBRACE -> break
|
||||
else -> {
|
||||
t1.raiseSyntax("unexpected token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pushInitScope()
|
||||
|
||||
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
||||
// parse body
|
||||
parseScript().also {
|
||||
cc.skipTokens(Token.Type.RBRACE)
|
||||
else -> t.raiseSyntax("expected enum entry name")
|
||||
}
|
||||
} else {
|
||||
cc.previous()
|
||||
null
|
||||
}
|
||||
|
||||
val initScope = popInitScope()
|
||||
|
||||
// create class
|
||||
val className = nameToken.value
|
||||
|
||||
@Suppress("UNUSED_VARIABLE") val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
|
||||
@Suppress("UNUSED_VARIABLE") val defaultVisibility = Visibility.Public
|
||||
|
||||
// create instance constructor
|
||||
// create custom objClass with all fields and instance constructor
|
||||
|
||||
val constructorCode = statement {
|
||||
// constructor code is registered with class instance and is called over
|
||||
// new `thisObj` already set by class to ObjInstance.instanceContext
|
||||
thisObj as ObjInstance
|
||||
|
||||
// the context now is a "class creation context", we must use its args to initialize
|
||||
// fields. Note that 'this' is already set by class
|
||||
constructorArgsDeclaration?.assignToContext(this)
|
||||
bodyInit?.execute(this)
|
||||
|
||||
thisObj
|
||||
}
|
||||
// inheritance must alter this code:
|
||||
val newClass = ObjInstanceClass(className).apply {
|
||||
instanceConstructor = constructorCode
|
||||
constructorMeta = constructorArgsDeclaration
|
||||
}
|
||||
} while (true)
|
||||
|
||||
return statement {
|
||||
// the main statement should create custom ObjClass instance with field
|
||||
// accessors, constructor registration, etc.
|
||||
addItem(className, false, newClass)
|
||||
if (initScope.isNotEmpty()) {
|
||||
val classScope = copy(newThisObj = newClass)
|
||||
newClass.classScope = classScope
|
||||
for (s in initScope)
|
||||
s.execute(classScope)
|
||||
.also { println("executed, ${classScope.objects}") }
|
||||
ObjEnumClass.createSimpleEnum(nameToken.value, names).also {
|
||||
addItem(nameToken.value, false, it, recordType = ObjRecord.Type.Enum)
|
||||
}
|
||||
newClass
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun parseClassDeclaration(): Statement {
|
||||
val nameToken = cc.requireToken(Token.Type.ID)
|
||||
return inCodeContext(CodeContext.ClassBody(nameToken.value)) {
|
||||
val constructorArgsDeclaration =
|
||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
||||
parseArgsDeclaration(isClassDeclaration = true)
|
||||
else null
|
||||
|
||||
if (constructorArgsDeclaration != null && constructorArgsDeclaration.endTokenType != Token.Type.RPAREN)
|
||||
throw ScriptError(
|
||||
nameToken.pos,
|
||||
"Bad class declaration: expected ')' at the end of the primary constructor"
|
||||
)
|
||||
|
||||
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
|
||||
val t = cc.next()
|
||||
|
||||
pushInitScope()
|
||||
|
||||
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
|
||||
// parse body
|
||||
parseScript().also {
|
||||
cc.skipTokens(Token.Type.RBRACE)
|
||||
}
|
||||
} else {
|
||||
cc.previous()
|
||||
null
|
||||
}
|
||||
|
||||
val initScope = popInitScope()
|
||||
|
||||
// create class
|
||||
val className = nameToken.value
|
||||
|
||||
// @Suppress("UNUSED_VARIABLE") val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
|
||||
// @Suppress("UNUSED_VARIABLE") val defaultVisibility = Visibility.Public
|
||||
|
||||
// create instance constructor
|
||||
// create custom objClass with all fields and instance constructor
|
||||
|
||||
val constructorCode = statement {
|
||||
// constructor code is registered with class instance and is called over
|
||||
// new `thisObj` already set by class to ObjInstance.instanceContext
|
||||
thisObj as ObjInstance
|
||||
|
||||
// the context now is a "class creation context", we must use its args to initialize
|
||||
// fields. Note that 'this' is already set by class
|
||||
constructorArgsDeclaration?.assignToContext(this)
|
||||
bodyInit?.execute(this)
|
||||
|
||||
thisObj
|
||||
}
|
||||
// inheritance must alter this code:
|
||||
val newClass = ObjInstanceClass(className).apply {
|
||||
instanceConstructor = constructorCode
|
||||
constructorMeta = constructorArgsDeclaration
|
||||
}
|
||||
|
||||
statement {
|
||||
// the main statement should create custom ObjClass instance with field
|
||||
// accessors, constructor registration, etc.
|
||||
addItem(className, false, newClass)
|
||||
if (initScope.isNotEmpty()) {
|
||||
val classScope = copy(newThisObj = newClass)
|
||||
newClass.classScope = classScope
|
||||
for (s in initScope)
|
||||
s.execute(classScope)
|
||||
}
|
||||
newClass
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun getLabel(maxDepth: Int = 2): String? {
|
||||
var cnt = 0
|
||||
@ -1540,8 +1660,7 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun
|
||||
parseFunctionDeclaration(
|
||||
private suspend fun parseFunctionDeclaration(
|
||||
visibility: Visibility = Visibility.Public,
|
||||
@Suppress("UNUSED_PARAMETER") isOpen: Boolean = false,
|
||||
isExtern: Boolean = false,
|
||||
@ -1554,6 +1673,9 @@ class Compiler(
|
||||
throw ScriptError(t.pos, "Expected identifier after 'fun'")
|
||||
else t.value
|
||||
|
||||
val annotation = lastAnnotation
|
||||
val parentContext = codeContexts.last()
|
||||
|
||||
t = cc.next()
|
||||
// Is extension?
|
||||
if (t.type == Token.Type.DOT) {
|
||||
@ -1577,57 +1699,66 @@ class Compiler(
|
||||
|
||||
if (cc.current().type == Token.Type.COLON) parseTypeDeclaration()
|
||||
|
||||
// Here we should be at open body
|
||||
val fnStatements = if (isExtern)
|
||||
statement { raiseError("extern function not provided: $name") }
|
||||
else
|
||||
parseBlock()
|
||||
return inCodeContext(CodeContext.Function(name)) {
|
||||
|
||||
var closure: Scope? = null
|
||||
// Here we should be at open body
|
||||
val fnStatements = if (isExtern)
|
||||
statement { raiseError("extern function not provided: $name") }
|
||||
else
|
||||
parseBlock()
|
||||
|
||||
val fnBody = statement(t.pos) { callerContext ->
|
||||
callerContext.pos = start
|
||||
var closure: Scope? = null
|
||||
|
||||
// restore closure where the function was defined, and making a copy of it
|
||||
// for local space (otherwise it will write local stuff to closure!)
|
||||
val context = closure?.let { ClosureScope(callerContext, it) }
|
||||
?: callerContext.raiseError("bug: closure not set")
|
||||
val fnBody = statement(t.pos) { callerContext ->
|
||||
callerContext.pos = start
|
||||
|
||||
// load params from caller context
|
||||
argsDeclaration.assignToContext(context, callerContext.args, defaultAccessType = AccessType.Val)
|
||||
if (extTypeName != null) {
|
||||
context.thisObj = callerContext.thisObj
|
||||
}
|
||||
fnStatements.execute(context)
|
||||
}
|
||||
val fnCreateStatement = statement(start) { context ->
|
||||
// we added fn in the context. now we must save closure
|
||||
// for the function
|
||||
closure = context
|
||||
extTypeName?.let { typeName ->
|
||||
// class extension method
|
||||
val type = context[typeName]?.value ?: context.raiseSymbolNotFound("class $typeName not found")
|
||||
if (type !is ObjClass) context.raiseClassCastError("$typeName is not the class instance")
|
||||
type.addFn(name, isOpen = true) {
|
||||
// ObjInstance has a fixed instance scope, so we need to build a closure
|
||||
(thisObj as? ObjInstance)?.let { i ->
|
||||
fnBody.execute(ClosureScope(this, i.instanceScope))
|
||||
}
|
||||
// other classes can create one-time scope for this rare case:
|
||||
?: fnBody.execute(thisObj.autoInstanceScope(this))
|
||||
// restore closure where the function was defined, and making a copy of it
|
||||
// for local space. If there is no closure, we are in, say, class context where
|
||||
// the closure is in the class initialization and we needn't more:
|
||||
val context = closure?.let { ClosureScope(callerContext, it) }
|
||||
?: callerContext
|
||||
|
||||
// load params from caller context
|
||||
argsDeclaration.assignToContext(context, callerContext.args, defaultAccessType = AccessType.Val)
|
||||
if (extTypeName != null) {
|
||||
context.thisObj = callerContext.thisObj
|
||||
}
|
||||
fnStatements.execute(context)
|
||||
}
|
||||
// regular function/method
|
||||
?: context.addItem(name, false, fnBody, visibility)
|
||||
// as the function can be called from anywhere, we have
|
||||
// saved the proper context in the closure
|
||||
fnBody
|
||||
val fnCreateStatement = statement(start) { context ->
|
||||
// we added fn in the context. now we must save closure
|
||||
// for the function, unless we're in the class scope:
|
||||
if (isStatic || parentContext !is CodeContext.ClassBody)
|
||||
closure = context
|
||||
|
||||
val annotatedFnBody = annotation?.invoke(context, ObjString(name), fnBody)
|
||||
?: fnBody
|
||||
|
||||
extTypeName?.let { typeName ->
|
||||
// class extension method
|
||||
val type = context[typeName]?.value ?: context.raiseSymbolNotFound("class $typeName not found")
|
||||
if (type !is ObjClass) context.raiseClassCastError("$typeName is not the class instance")
|
||||
type.addFn(name, isOpen = true) {
|
||||
// ObjInstance has a fixed instance scope, so we need to build a closure
|
||||
(thisObj as? ObjInstance)?.let { i ->
|
||||
annotatedFnBody.execute(ClosureScope(this, i.instanceScope))
|
||||
}
|
||||
// other classes can create one-time scope for this rare case:
|
||||
?: annotatedFnBody.execute(thisObj.autoInstanceScope(this))
|
||||
}
|
||||
}
|
||||
// regular function/method
|
||||
?: context.addItem(name, false, annotatedFnBody, visibility)
|
||||
// as the function can be called from anywhere, we have
|
||||
// saved the proper context in the closure
|
||||
annotatedFnBody
|
||||
}
|
||||
if (isStatic) {
|
||||
currentInitScope += fnCreateStatement
|
||||
NopStatement
|
||||
} else
|
||||
fnCreateStatement
|
||||
}
|
||||
return if (isStatic) {
|
||||
currentInitScope += fnCreateStatement
|
||||
NopStatement
|
||||
} else
|
||||
fnCreateStatement
|
||||
}
|
||||
|
||||
private suspend fun parseBlock(skipLeadingBrace: Boolean = false): Statement {
|
||||
@ -1662,24 +1793,31 @@ class Compiler(
|
||||
|
||||
val eqToken = cc.next()
|
||||
var setNull = false
|
||||
if (eqToken.type != Token.Type.ASSIGN) {
|
||||
if (!isMutable)
|
||||
throw ScriptError(start, "val must be initialized")
|
||||
else {
|
||||
cc.previous()
|
||||
setNull = true
|
||||
|
||||
val isDelegate = if (eqToken.isId("by")) {
|
||||
true
|
||||
} else {
|
||||
if (eqToken.type != Token.Type.ASSIGN) {
|
||||
if (!isMutable)
|
||||
throw ScriptError(start, "val must be initialized")
|
||||
else {
|
||||
cc.previous()
|
||||
setNull = true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
val initialExpression = if (setNull) null else parseStatement(true)
|
||||
val initialExpression = if (setNull) null
|
||||
else parseStatement(true)
|
||||
?: throw ScriptError(eqToken.pos, "Expected initializer expression")
|
||||
|
||||
if (isStatic) {
|
||||
// find objclass instance: this is tricky: this code executes in object initializer,
|
||||
// when creating instance, but we need to execute it in the class initializer which
|
||||
// is missing as for now. Add it to the compiler context?
|
||||
// add there
|
||||
// return
|
||||
|
||||
// if (isDelegate) throw ScriptError(start, "static delegates are not yet implemented")
|
||||
currentInitScope += statement {
|
||||
val initValue = initialExpression?.execute(this)?.byValueCopy() ?: ObjNull
|
||||
(thisObj as ObjClass).createClassField(name, initValue, isMutable, visibility, pos)
|
||||
@ -1693,12 +1831,32 @@ class Compiler(
|
||||
if (context.containsLocal(name))
|
||||
throw ScriptError(nameToken.pos, "Variable $name is already defined")
|
||||
|
||||
// init value could be a val; when we initialize by-value type var with it, we need to
|
||||
// create a separate copy:
|
||||
val initValue = initialExpression?.execute(context)?.byValueCopy() ?: ObjNull
|
||||
|
||||
context.addItem(name, isMutable, initValue, visibility, recordType = ObjRecord.Type.Field)
|
||||
initValue
|
||||
if (isDelegate) {
|
||||
TODO()
|
||||
// println("initial expr = $initialExpression")
|
||||
// val initValue =
|
||||
// (initialExpression?.execute(context.copy(Arguments(ObjString(name)))) as? Statement)
|
||||
// ?.execute(context.copy(Arguments(ObjString(name))))
|
||||
// ?: context.raiseError("delegate initialization required")
|
||||
// println("delegate init: $initValue")
|
||||
// if (!initValue.isInstanceOf(ObjArray))
|
||||
// context.raiseIllegalArgument("delegate initialized must be an array")
|
||||
// val s = initValue.getAt(context, 1)
|
||||
// val setter = if (s == ObjNull) statement { raiseNotImplemented("setter is not provided") }
|
||||
// else (s as? Statement) ?: context.raiseClassCastError("setter must be a callable")
|
||||
// ObjDelegate(
|
||||
// (initValue.getAt(context, 0) as? Statement)
|
||||
// ?: context.raiseClassCastError("getter must be a callable"), setter
|
||||
// ).also {
|
||||
// context.addItem(name, isMutable, it, visibility, recordType = ObjRecord.Type.Field)
|
||||
// }
|
||||
} else {
|
||||
// init value could be a val; when we initialize by-value type var with it, we need to
|
||||
// create a separate copy:
|
||||
val initValue = initialExpression?.execute(context)?.byValueCopy() ?: ObjNull
|
||||
context.addItem(name, isMutable, initValue, visibility, recordType = ObjRecord.Type.Field)
|
||||
initValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1817,7 +1975,15 @@ class Compiler(
|
||||
Operator.simple(Token.Type.IS, lastPriority) { _, a, b -> ObjBool(a.isInstanceOf(b)) },
|
||||
Operator.simple(Token.Type.NOTIS, lastPriority) { _, a, b -> ObjBool(!a.isInstanceOf(b)) },
|
||||
|
||||
Operator.simple(Token.Type.ELVIS, ++lastPriority) { _, a, b -> if (a == ObjNull) b else a },
|
||||
Operator(Token.Type.ELVIS, ++lastPriority, 2) { _: Pos, a: Accessor, b: Accessor ->
|
||||
Accessor {
|
||||
val aa = a.getter(it).value
|
||||
(
|
||||
if (aa != ObjNull) aa
|
||||
else b.getter(it).value
|
||||
).asReadonly
|
||||
}
|
||||
},
|
||||
|
||||
// shuttle <=> 6
|
||||
Operator.simple(Token.Type.SHUTTLE, ++lastPriority) { c, a, b ->
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
class CompilerContext(val tokens: List<Token>) {
|
||||
@ -20,7 +37,7 @@ class CompilerContext(val tokens: List<Token>) {
|
||||
fun hasNext() = currentIndex < tokens.size
|
||||
fun hasPrevious() = currentIndex > 0
|
||||
fun next() =
|
||||
if( currentIndex < tokens.size ) tokens[currentIndex++]
|
||||
if (currentIndex < tokens.size) tokens[currentIndex++]
|
||||
else Token("", tokens.last().pos, Token.Type.EOF)
|
||||
// throw IllegalStateException("No more tokens")
|
||||
|
||||
@ -61,7 +78,7 @@ class CompilerContext(val tokens: List<Token>) {
|
||||
*/
|
||||
fun skipId(name: String): Boolean {
|
||||
current().let { t ->
|
||||
if( t.type == Token.Type.ID && t.value == name ) {
|
||||
if (t.type == Token.Type.ID && t.value == name) {
|
||||
next()
|
||||
return true
|
||||
}
|
||||
@ -93,6 +110,20 @@ class CompilerContext(val tokens: List<Token>) {
|
||||
} else true
|
||||
}
|
||||
|
||||
/**
|
||||
* If next token is one of these types, skip it.
|
||||
* @return true if token was found and skipped
|
||||
*/
|
||||
fun skipNextIf(vararg types: Token.Type): Boolean {
|
||||
val t = next()
|
||||
return if (t.type in types)
|
||||
true
|
||||
else {
|
||||
previous()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun skipTokens(vararg tokenTypes: Token.Type) {
|
||||
while (next().type in tokenTypes) { /**/
|
||||
@ -143,19 +174,24 @@ class CompilerContext(val tokens: List<Token>) {
|
||||
fun matchQualifiers(keyword: String, vararg qualifiers: String): Boolean {
|
||||
val pos = savePos()
|
||||
var count = 0
|
||||
while( count < qualifiers.size) {
|
||||
while (count < qualifiers.size) {
|
||||
val t = next()
|
||||
when(t.type) {
|
||||
when (t.type) {
|
||||
Token.Type.ID -> {
|
||||
if( t.value in qualifiers ) count++
|
||||
else { restorePos(pos); return false }
|
||||
if (t.value in qualifiers) count++
|
||||
else {
|
||||
restorePos(pos); return false
|
||||
}
|
||||
}
|
||||
|
||||
Token.Type.MULTILINE_COMMENT, Token.Type.SINLGE_LINE_COMMENT, Token.Type.NEWLINE -> {}
|
||||
else -> { restorePos(pos); return false }
|
||||
else -> {
|
||||
restorePos(pos); return false
|
||||
}
|
||||
}
|
||||
}
|
||||
val t = next()
|
||||
if( t.type == Token.Type.ID && t.value == keyword ) {
|
||||
if (t.type == Token.Type.ID && t.value == keyword) {
|
||||
return true
|
||||
} else {
|
||||
restorePos(pos)
|
||||
@ -168,7 +204,7 @@ class CompilerContext(val tokens: List<Token>) {
|
||||
* Note that [Token.Type.EOF] is not considered a whitespace token.
|
||||
*/
|
||||
fun skipWsTokens(): Token {
|
||||
while( current().type in wstokens ) {
|
||||
while (current().type in wstokens) {
|
||||
next()
|
||||
}
|
||||
return next()
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.Accessor
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.Obj
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.ObjRecord
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
val digitsSet = ('0'..'9').toSet()
|
||||
@ -375,6 +392,32 @@ private class Parser(fromPos: Pos) {
|
||||
|
||||
private val currentChar: Char get() = pos.currentChar
|
||||
|
||||
private fun fixMultilineStringLiteral(source: String): String {
|
||||
val sizes = mutableListOf<Int>()
|
||||
val lines = source.lines().toMutableList()
|
||||
if( lines.size == 0 ) return ""
|
||||
if( lines[0].isBlank() ) lines.removeFirst()
|
||||
if( lines.isEmpty()) return ""
|
||||
if( lines.last().isBlank() ) lines.removeLast()
|
||||
|
||||
val normalized = lines.map { l ->
|
||||
if( l.isBlank() ) {
|
||||
sizes.add(-1)
|
||||
""
|
||||
}
|
||||
else {
|
||||
val margin = leftMargin(l)
|
||||
sizes += margin
|
||||
" ".repeat(margin) + l.trim()
|
||||
}
|
||||
}
|
||||
val commonMargin = sizes.filter { it >= 0 }.min()
|
||||
val fixed = if( commonMargin < 1 ) lines else normalized.map {
|
||||
if( it.isBlank() ) "" else it.drop(commonMargin)
|
||||
}
|
||||
return fixed.joinToString("\n")
|
||||
}
|
||||
|
||||
private fun loadStringToken(): Token {
|
||||
val start = currentPos
|
||||
|
||||
@ -383,6 +426,7 @@ private class Parser(fromPos: Pos) {
|
||||
// start = start.back()
|
||||
|
||||
val sb = StringBuilder()
|
||||
var newlineDetected = false
|
||||
while (currentChar != '"') {
|
||||
if (pos.end) throw ScriptError(start, "unterminated string started there")
|
||||
when (currentChar) {
|
||||
@ -397,6 +441,12 @@ private class Parser(fromPos: Pos) {
|
||||
}
|
||||
}
|
||||
|
||||
'\n', '\r'-> {
|
||||
newlineDetected = true
|
||||
sb.append(currentChar)
|
||||
pos.advance()
|
||||
}
|
||||
|
||||
else -> {
|
||||
sb.append(currentChar)
|
||||
pos.advance()
|
||||
@ -404,7 +454,10 @@ private class Parser(fromPos: Pos) {
|
||||
}
|
||||
}
|
||||
pos.advance()
|
||||
return Token(sb.toString(), start, Token.Type.STRING)
|
||||
|
||||
val result = sb.toString().let { if( newlineDetected ) fixMultilineStringLiteral(it) else it }
|
||||
|
||||
return Token(result, start, Token.Type.STRING)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
data class Pos(val source: Source, val line: Int, val column: Int) {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.*
|
||||
@ -71,6 +88,11 @@ open class Scope(
|
||||
throw ExecutionError(obj)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun raiseNotFound(message: String="not found"): Nothing {
|
||||
throw ExecutionError(ObjNotFoundException(this,message))
|
||||
}
|
||||
|
||||
inline fun <reified T : Obj> requiredArg(index: Int): T {
|
||||
if (args.list.size <= index) raiseError("Expected at least ${index + 1} argument, got ${args.list.size}")
|
||||
return (args.list[index].byValueCopy() as? T)
|
||||
@ -109,9 +131,16 @@ open class Scope(
|
||||
open operator fun get(name: String): ObjRecord? =
|
||||
if (name == "this") thisObj.asReadonly
|
||||
else {
|
||||
objects[name]
|
||||
(objects[name]
|
||||
?: parent?.get(name)
|
||||
?: thisObj.objClass.getInstanceMemberOrNull(name)
|
||||
?: thisObj.objClass
|
||||
.getInstanceMemberOrNull(name)
|
||||
)
|
||||
// ?.also {
|
||||
// if( name == "predicate") {
|
||||
// println("got predicate $it")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fun copy(pos: Pos, args: Arguments = Arguments.EMPTY, newThisObj: Obj? = null): Scope =
|
||||
@ -220,6 +249,8 @@ open class Scope(
|
||||
|
||||
}
|
||||
|
||||
open fun applyClosure(closure: Scope): Scope = ClosureScope(this, closure)
|
||||
|
||||
companion object {
|
||||
|
||||
fun new(): Scope =
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.delay
|
||||
@ -29,6 +46,11 @@ class Script(
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Create new scope using standard safe set of modules, using [defaultImportManager]. It is
|
||||
* suspended as first time calls requires compilation of standard library or other
|
||||
* asynchronous initialization.
|
||||
*/
|
||||
suspend fun newScope(pos: Pos = Pos.builtIn) = defaultImportManager.newStdScope(pos)
|
||||
|
||||
internal val rootScope: Scope = Scope(null).apply {
|
||||
@ -165,6 +187,11 @@ class Script(
|
||||
}
|
||||
result ?: raiseError(ObjAssertionFailedException(this,"Expected exception but nothing was thrown"))
|
||||
}
|
||||
|
||||
addFn("dynamic") {
|
||||
ObjDynamic.create(this, requireOnlyArg())
|
||||
}
|
||||
|
||||
addFn("require") {
|
||||
val condition = requiredArg<ObjBool>(0)
|
||||
if( !condition.value ) {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@file:Suppress("CanBeParameter")
|
||||
|
||||
package net.sergeych.lyng
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
interface SecurityManager {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
class Source(val fileName: String, text: String) {
|
||||
|
@ -1,8 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
data class Token(val value: String, val pos: Pos, val type: Type) {
|
||||
fun raiseSyntax(text: String): Nothing {
|
||||
throw ScriptError(pos, text)
|
||||
}
|
||||
|
||||
val isComment: Boolean by lazy { type == Type.SINLGE_LINE_COMMENT || type == Type.MULTILINE_COMMENT }
|
||||
|
||||
fun isId(text: String) =
|
||||
type == Type.ID && value == text
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
enum class Type {
|
||||
ID, INT, REAL, HEX, STRING, CHAR,
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.sergeych.lyng
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
enum class Visibility {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.sync.Mutex
|
||||
@ -68,13 +85,15 @@ open class Obj {
|
||||
name: String,
|
||||
args: Arguments = Arguments.EMPTY,
|
||||
onNotFoundResult: Obj?=null
|
||||
): Obj =
|
||||
objClass.getInstanceMemberOrNull(name)?.value?.invoke(
|
||||
): Obj {
|
||||
return objClass.getInstanceMemberOrNull(name)?.value?.invoke(
|
||||
scope,
|
||||
this,
|
||||
args)
|
||||
args
|
||||
)
|
||||
?: onNotFoundResult
|
||||
?: scope.raiseSymbolNotFound(name)
|
||||
}
|
||||
|
||||
open suspend fun getInstanceMethod(
|
||||
scope: Scope,
|
||||
@ -144,6 +163,8 @@ open class Obj {
|
||||
|
||||
open suspend fun assign(scope: Scope, other: Obj): Obj? = null
|
||||
|
||||
open fun getValue(scope: Scope) = this
|
||||
|
||||
/**
|
||||
* a += b
|
||||
* if( the operation is not defined, it returns null and the compiler would try
|
||||
@ -269,6 +290,9 @@ open class Obj {
|
||||
addFn("toString") {
|
||||
thisObj.asStr
|
||||
}
|
||||
addFn("inspect", true) {
|
||||
thisObj.inspect().toObj()
|
||||
}
|
||||
addFn("contains") {
|
||||
ObjBool(thisObj.contains(this, args.firstAndOnly()))
|
||||
}
|
||||
@ -277,15 +301,23 @@ open class Obj {
|
||||
args.firstAndOnly().callOn(copy(Arguments(thisObj)))
|
||||
}
|
||||
addFn("apply") {
|
||||
val newContext = (thisObj as? ObjInstance)?.instanceScope ?: this
|
||||
args.firstAndOnly()
|
||||
.callOn(newContext)
|
||||
val body = args.firstAndOnly()
|
||||
(thisObj as? ObjInstance)?.let {
|
||||
println("apply in ${thisObj is ObjInstance}, ${it.instanceScope}")
|
||||
body.callOn(ApplyScope(this, it.instanceScope))
|
||||
} ?: run {
|
||||
println("apply on non-instance $thisObj")
|
||||
body.callOn(this)
|
||||
}
|
||||
thisObj
|
||||
}
|
||||
addFn("also") {
|
||||
args.firstAndOnly().callOn(copy(Arguments(thisObj)))
|
||||
thisObj
|
||||
}
|
||||
addFn("run") {
|
||||
args.firstAndOnly().callOn(this)
|
||||
}
|
||||
addFn("getAt") {
|
||||
requireExactCount(1)
|
||||
thisObj.getAt(this, requiredArg<Obj>(0))
|
||||
@ -513,6 +545,7 @@ open class ObjException(exceptionClass: ExceptionClass, val scope: Scope, val me
|
||||
"IterationEndException",
|
||||
"AccessException",
|
||||
"UnknownException",
|
||||
"NotFoundException"
|
||||
)) {
|
||||
scope.addConst(name, getOrCreateExceptionClass(name))
|
||||
}
|
||||
@ -556,3 +589,6 @@ class ObjUnknownException(scope: Scope, message: String = "access not allowed er
|
||||
|
||||
class ObjIllegalOperationException(scope: Scope, message: String = "Operation is illegal") :
|
||||
ObjException("IllegalOperationException", scope, message)
|
||||
|
||||
class ObjNotFoundException(scope: Scope, message: String = "not found") :
|
||||
ObjException("NotFoundException", scope, message)
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
val ObjArray by lazy {
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.bintools.toDump
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,20 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import net.sergeych.bintools.decodeHex
|
||||
import net.sergeych.bintools.encodeToHex
|
||||
import net.sergeych.bintools.toDump
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.statement
|
||||
import net.sergeych.lynon.BitArray
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
import net.sergeych.mp_tools.decodeBase64Url
|
||||
import net.sergeych.mp_tools.encodeToBase64Url
|
||||
import kotlin.math.min
|
||||
|
||||
open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
|
||||
override val objClass: ObjClass = type
|
||||
|
||||
val hex by lazy { byteArray.encodeToHex("")}
|
||||
val base64 by lazy { byteArray.toByteArray().encodeToBase64Url()}
|
||||
|
||||
fun checkIndex(scope: Scope, index: Obj): Int {
|
||||
if (index !is ObjInt)
|
||||
scope.raiseIllegalArgument("index must be Int")
|
||||
@ -66,9 +90,7 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
} else scope.raiseIllegalArgument("can't concatenate buffer with ${other.inspect()}")
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Buffer(${byteArray.encodeToHex()})"
|
||||
}
|
||||
override fun toString(): String = base64
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@ -85,6 +107,8 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
encoder.encodeCachedBytes(byteArray.asByteArray())
|
||||
}
|
||||
|
||||
override fun inspect(): String = "Buf($base64)"
|
||||
|
||||
companion object {
|
||||
private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
|
||||
when (obj) {
|
||||
@ -141,11 +165,27 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
})
|
||||
|
||||
}.apply {
|
||||
addClassFn("decodeBase64") {
|
||||
ObjBuffer(requireOnlyArg<Obj>().toString().decodeBase64Url().asUByteArray())
|
||||
}
|
||||
addClassFn("decodeHex") {
|
||||
ObjBuffer(requireOnlyArg<Obj>().toString().decodeHex().asUByteArray())
|
||||
}
|
||||
createField("size",
|
||||
statement {
|
||||
(thisObj as ObjBuffer).byteArray.size.toObj()
|
||||
}
|
||||
)
|
||||
createField("hex",
|
||||
statement {
|
||||
thisAs<ObjBuffer>().hex.toObj()
|
||||
}
|
||||
)
|
||||
createField("base64",
|
||||
statement {
|
||||
thisAs<ObjBuffer>().base64.toObj()
|
||||
}
|
||||
)
|
||||
addFn("decodeUtf8") {
|
||||
ObjString(
|
||||
thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString()
|
||||
@ -161,6 +201,9 @@ open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
thisAs<ObjBuffer>().byteArray.toByteArray().toDump()
|
||||
)
|
||||
}
|
||||
addFn("toBitInput") {
|
||||
ObjBitBuffer(BitArray(thisAs<ObjBuffer>().byteArray, 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.*
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.CompletableDeferred
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.Deferred
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
//class ObjDelegateContext()
|
||||
//
|
||||
//class ObjDelegate(
|
||||
// val getter: Statement,
|
||||
// val setter: Statement = statement { raiseNotImplemented("setter is not implemented") }
|
||||
//): Obj() {
|
||||
//
|
||||
// override suspend fun assign(scope: Scope, other: Obj): Obj? {
|
||||
// setter.execute(scope.copy(Arguments(other)))
|
||||
// return other
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// val type = object: ObjClass("Delegate") {
|
||||
// override suspend fun callOn(scope: Scope): Obj {
|
||||
// scope.raiseError("Delegate should not be constructed directly")
|
||||
// }
|
||||
// }.apply {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Arguments
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Statement
|
||||
|
||||
class ObjDynamicContext(val delegate: ObjDynamic) : Obj() {
|
||||
override val objClass: ObjClass = type
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("DelegateContext").apply {
|
||||
addFn("get") {
|
||||
val d = thisAs<ObjDynamicContext>().delegate
|
||||
if (d.readCallback != null)
|
||||
raiseIllegalState("get already defined")
|
||||
d.readCallback = requireOnlyArg()
|
||||
ObjVoid
|
||||
}
|
||||
|
||||
addFn("set") {
|
||||
val d = thisAs<ObjDynamicContext>().delegate
|
||||
if (d.writeCallback != null)
|
||||
raiseIllegalState("set already defined")
|
||||
d.writeCallback = requireOnlyArg()
|
||||
ObjVoid
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class ObjDynamic : Obj() {
|
||||
|
||||
internal var readCallback: Statement? = null
|
||||
internal var writeCallback: Statement? = null
|
||||
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
return readCallback?.execute(scope.copy(Arguments(ObjString(name))))?.let {
|
||||
if (writeCallback != null)
|
||||
it.asMutable
|
||||
else
|
||||
it.asReadonly
|
||||
}
|
||||
?: super.readField(scope, name)
|
||||
}
|
||||
|
||||
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
||||
writeCallback?.execute(scope.copy(Arguments(ObjString(name), newValue)))
|
||||
?: super.writeField(scope, name, newValue)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
suspend fun create(scope: Scope, builder: Statement): ObjDynamic {
|
||||
val delegate = ObjDynamic()
|
||||
val context = ObjDynamicContext(delegate)
|
||||
builder.execute(scope.copy(newThisObj = context))
|
||||
return delegate
|
||||
}
|
||||
|
||||
val type = object : ObjClass("Delegate") {}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
import net.sergeych.lynon.LynonType
|
||||
|
||||
open class ObjEnumEntry(enumClass: ObjEnumClass, val name: ObjString, val ordinal: ObjInt) : Obj() {
|
||||
override val objClass = enumClass
|
||||
|
||||
override fun toString(): String {
|
||||
return "$objClass.$name"
|
||||
}
|
||||
|
||||
override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) {
|
||||
encoder.encodeUnsigned(ordinal.value.toULong())
|
||||
}
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if( other !is ObjEnumEntry) return -2
|
||||
if( other.objClass != objClass ) return -2
|
||||
return ordinal.compareTo(scope, other.ordinal)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object EnumBase : ObjClass("Enum") {
|
||||
|
||||
}
|
||||
|
||||
class ObjEnumClass(val name: String) : ObjClass(name, EnumBase) {
|
||||
val objEntries = ObjList()
|
||||
val byName by lazy { objEntries.list.associateBy { (it as ObjEnumEntry).name } }
|
||||
|
||||
init {
|
||||
addClassConst("entries", objEntries )
|
||||
addClassFn("valueOf") {
|
||||
val name = requireOnlyArg<ObjString>()
|
||||
byName[name] ?: raiseSymbolNotFound("does not exists: enum ${className}.$name")
|
||||
}
|
||||
addFn("name") { thisAs<ObjEnumEntry>().name }
|
||||
addFn("ordinal") { thisAs<ObjEnumEntry>().ordinal }
|
||||
|
||||
}
|
||||
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
val index = decoder.unpackUnsigned().toInt()
|
||||
return objEntries.list[index]
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createSimpleEnum(enumName: String, names: List<String>): ObjEnumClass {
|
||||
val klass = ObjEnumClass(enumName)
|
||||
names.forEachIndexed { index, name ->
|
||||
val entry = ObjEnumEntry(klass, ObjString(name), ObjInt(index.toLong(), isConst = true))
|
||||
klass.objEntries.list += entry
|
||||
klass.addClassConst(name, entry)
|
||||
}
|
||||
return klass
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.DelicateCoroutinesApi
|
||||
@ -23,12 +40,12 @@ class ObjFlowBuilder(val output: SendChannel<Obj>) : Obj() {
|
||||
val data = requireOnlyArg<Obj>()
|
||||
try {
|
||||
val channel = thisAs<ObjFlowBuilder>().output
|
||||
if( !channel.isClosedForSend )
|
||||
if (!channel.isClosedForSend)
|
||||
channel.send(data)
|
||||
else
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
} catch (x: Exception) {
|
||||
if( x !is CancellationException )
|
||||
if (x !is CancellationException)
|
||||
x.printStackTrace()
|
||||
throw ScriptFlowIsNoMoreCollected()
|
||||
}
|
||||
@ -45,12 +62,10 @@ private fun createLyngFlowInput(scope: Scope, producer: Statement): ReceiveChann
|
||||
globalLaunch {
|
||||
try {
|
||||
producer.execute(builderScope)
|
||||
}
|
||||
catch(x: ScriptFlowIsNoMoreCollected) {
|
||||
} catch (x: ScriptFlowIsNoMoreCollected) {
|
||||
x.printStackTrace()
|
||||
// premature flow closing, OK
|
||||
}
|
||||
catch(x: Exception) {
|
||||
} catch (x: Exception) {
|
||||
x.printStackTrace()
|
||||
}
|
||||
channel.close()
|
||||
@ -70,7 +85,11 @@ class ObjFlow(val producer: Statement, val scope: Scope) : Obj() {
|
||||
}.apply {
|
||||
addFn("iterator") {
|
||||
val objFlow = thisAs<ObjFlow>()
|
||||
ObjFlowIterator( statement { objFlow.producer.execute(ClosureScope(this,objFlow.scope)) } )
|
||||
ObjFlowIterator(statement {
|
||||
objFlow.producer.execute(
|
||||
ClosureScope(this, objFlow.scope)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,9 +107,10 @@ class ObjFlowIterator(val producer: Statement) : Obj() {
|
||||
private var isCancelled = false
|
||||
|
||||
private fun checkNotCancelled(scope: Scope) {
|
||||
if( isCancelled )
|
||||
if (isCancelled)
|
||||
scope.raiseIllegalState("iteration is cancelled")
|
||||
}
|
||||
|
||||
suspend fun hasNext(scope: Scope): ObjBool {
|
||||
checkNotCancelled(scope)
|
||||
// cold start:
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Arguments
|
||||
@ -71,18 +88,15 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
val vars = instanceVars.values.map { it.value }
|
||||
if( vars.isNotEmpty()) {
|
||||
encoder.encodeAnyList(scope, vars)
|
||||
println("serialized state vars $vars")
|
||||
}
|
||||
}
|
||||
|
||||
internal suspend fun deserializeStateVars(scope: Scope, decoder: LynonDecoder) {
|
||||
val localVars = instanceVars.values.toList()
|
||||
if( localVars.isNotEmpty() ) {
|
||||
println("gonna read vars")
|
||||
val vars = decoder.decodeAnyList(scope)
|
||||
if (vars.size > instanceVars.size)
|
||||
scope.raiseIllegalArgument("serialized vars has bigger size than instance vars")
|
||||
println("deser state vars $vars")
|
||||
for ((i, v) in vars.withIndex()) {
|
||||
localVars[i].value = v
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Arguments
|
||||
@ -12,7 +29,6 @@ class ObjInstanceClass(val name: String) : ObjClass(name) {
|
||||
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
val args = decoder.decodeAnyList(scope)
|
||||
println("deserializing constructor $name, $args params")
|
||||
val actualSize = constructorMeta?.params?.size ?: 0
|
||||
if( args.size > actualSize )
|
||||
scope.raiseIllegalArgument("constructor $name has only $actualSize but serialized version has ${args.size}")
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.Clock
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
@ -45,7 +62,7 @@ class ObjInt(var value: Long, override val isConst: Boolean = false) : Obj(), Nu
|
||||
|
||||
override fun toString(): String = value.toString()
|
||||
|
||||
override val objClass: ObjClass = type
|
||||
override val objClass: ObjClass by lazy { type }
|
||||
|
||||
override suspend fun plus(scope: Scope, other: Obj): Obj =
|
||||
if (other is ObjInt)
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Arguments
|
||||
@ -42,12 +59,16 @@ val ObjIterable by lazy {
|
||||
}
|
||||
|
||||
addFn("toSet") {
|
||||
val result = mutableSetOf<Obj>()
|
||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
result += it.invokeInstanceMethod(this, "next")
|
||||
if( thisObj.isInstanceOf(ObjSet.type) )
|
||||
thisObj
|
||||
else {
|
||||
val result = mutableSetOf<Obj>()
|
||||
val it = thisObj.invokeInstanceMethod(this, "iterator")
|
||||
while (it.invokeInstanceMethod(this, "hasNext").toBool()) {
|
||||
result += it.invokeInstanceMethod(this, "next")
|
||||
}
|
||||
ObjSet(result)
|
||||
}
|
||||
ObjSet(result)
|
||||
}
|
||||
|
||||
addFn("toMap") {
|
||||
|
@ -1,4 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
val ObjIterator by lazy { ObjClass("Iterator") }
|
||||
/**
|
||||
* Iterator should provide lyng-level iterator functions:
|
||||
*
|
||||
* - hasNext()
|
||||
* - next()
|
||||
* - optional cancelIteration() that _may_ be called when iteration is performed
|
||||
* only on the part of the iterable entity. Implement it when there are resources
|
||||
* to be reclaimed on iteration interruption.
|
||||
*/
|
||||
val ObjIterator by lazy {
|
||||
ObjClass("Iterator").apply {
|
||||
addFn("cancelIteration", true) {
|
||||
ObjVoid
|
||||
}
|
||||
addFn("hasNext", true) {
|
||||
raiseNotImplemented("hasNext() is not implemented")
|
||||
}
|
||||
addFn("next", true) {
|
||||
raiseNotImplemented("next() is not implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.sergeych.lyng.obj
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.flow.map
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.coroutines.sync.Mutex
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
@ -39,7 +56,7 @@ class ObjRangeIterator(val self: ObjRange) : Obj() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("RangeIterator", ObjIterable).apply {
|
||||
val type = ObjClass("RangeIterator", ObjIterator).apply {
|
||||
addFn("hasNext") {
|
||||
thisAs<ObjRangeIterator>().hasNext().toObj()
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Pos
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
@ -18,8 +35,15 @@ data class ObjRecord(
|
||||
Field(true, true),
|
||||
@Suppress("unused")
|
||||
Fun,
|
||||
@Suppress("unused")
|
||||
ConstructorField(true, true),
|
||||
Other
|
||||
Argument(true, true),
|
||||
@Suppress("unused")
|
||||
Class,
|
||||
Enum,
|
||||
Other;
|
||||
|
||||
val isArgument get() = this == Argument
|
||||
}
|
||||
@Suppress("unused")
|
||||
fun qualifiedName(name: String): String =
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.Scope
|
||||
@ -92,7 +109,7 @@ class ObjSet(val set: MutableSet<Obj> = mutableSetOf()) : Obj() {
|
||||
companion object {
|
||||
|
||||
|
||||
val type = object : ObjClass("Set", ObjCollection) {
|
||||
val type: ObjClass = object : ObjClass("Set", ObjCollection) {
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
return ObjSet(scope.args.list.toMutableSet())
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.serialization.SerialName
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.pacman
|
||||
|
||||
import net.sergeych.lyng.*
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.pacman
|
||||
|
||||
import net.sergeych.lyng.*
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.pacman
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
|
@ -1,7 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 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 net.sergeych.lyng.obj.Obj
|
||||
import net.sergeych.lyng.obj.ObjClass
|
||||
import net.sergeych.lyng.obj.ObjNull
|
||||
import net.sergeych.lyng.obj.ObjVoid
|
||||
|
||||
fun String.toSource(name: String = "eval"): Source = Source(name, this)
|
||||
@ -28,6 +46,7 @@ abstract class Statement(
|
||||
abstract suspend fun execute(scope: Scope): Obj
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if( other == ObjNull || other == ObjVoid ) return 1
|
||||
throw UnsupportedOperationException("not comparable")
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,41 @@
|
||||
/*
|
||||
* Copyright 2025 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.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) ) {
|
||||
if( predicate(item) ) {ln
|
||||
emit(item)
|
||||
}
|
||||
}
|
||||
@ -21,7 +50,7 @@ fun Iterable.drop(n) {
|
||||
fun Iterable.first() {
|
||||
val i = iterator()
|
||||
if( !i.hasNext() ) throw NoSuchElementException()
|
||||
i.next()
|
||||
i.next().also { i.cancelIteration() }
|
||||
}
|
||||
|
||||
fun Iterable.last() {
|
||||
@ -54,5 +83,26 @@ fun Iterable.takeLast(n) {
|
||||
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) }
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2025 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
|
||||
|
||||
fun leftMargin(s: String): Int {
|
||||
var cnt = 0
|
||||
for (c in s) {
|
||||
when (c) {
|
||||
' ' -> cnt++
|
||||
'\t' -> cnt = (cnt / 4.0 + 0.9).toInt() * 4
|
||||
else -> break
|
||||
}
|
||||
}
|
||||
return cnt
|
||||
}
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
interface BitInput {
|
||||
@ -82,6 +99,8 @@ interface BitInput {
|
||||
fun decompressStringOrNull(): String? = decompressOrNull()?.decodeToString()
|
||||
|
||||
fun decompressString(): String = decompress().decodeToString()
|
||||
|
||||
@Suppress("unused")
|
||||
fun unpackDouble(): Double {
|
||||
val bits = getBits(64)
|
||||
return Double.fromBits(bits.toLong())
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
@Suppress("unused")
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
interface BitOutput {
|
||||
@ -84,7 +101,6 @@ interface BitOutput {
|
||||
val compressed = LZW.compress(source.asUByteArray())
|
||||
// check that compression is effective including header bits size:
|
||||
if( compressed.size + 2 < source.size * 8L) {
|
||||
println("write compressed")
|
||||
putBit(1)
|
||||
// LZW algorithm
|
||||
putBits(0, 2)
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
class DecompressionException(message: String) : IllegalArgumentException(message) {}
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
@ -48,7 +65,6 @@ 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
|
||||
println("expected class name $className")
|
||||
return scope.get(className.value)?.value?.let {
|
||||
if (it !is ObjClass)
|
||||
scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}")
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
import net.sergeych.bintools.ByteChunk
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
import net.sergeych.lyng.obj.ObjBool
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
import kotlin.math.min
|
||||
@ -85,7 +102,7 @@ class BitArray(val bytes: UByteArray, val lastByteBits: Int) : BitList {
|
||||
* in the bit 0x02 of the first byte, etc.
|
||||
*
|
||||
* This allows automatic fill of the last byte with zeros. This is important when
|
||||
* using bytes stored from [asByteArray] or [asUbyteArray]. When converting to
|
||||
* using bytes stored from [asByteArray] or `asUbyteArray`. When converting to
|
||||
* bytes, automatic padding to byte size is applied. With such bit order, constructing
|
||||
* [BitInput] to read from [ByteArray.toUByteArray] result only provides 0 to 7 extra zeroes bits
|
||||
* at teh end which is often acceptable. To avoid this, use [toBitArray]; the [BitArray]
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.lynon
|
||||
|
||||
import net.sergeych.collections.SortedList
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user