Compare commits
No commits in common. "311cf6ee44b55ae1b2174ee9e59d354c1da67e14" and "c09746475017773102fd13461f75f839c4e401d7" have entirely different histories.
311cf6ee44
...
c097464750
@ -14,8 +14,6 @@ Sources: `lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt`, `lynglib/s
|
||||
- Assertions/tests: `assert`, `assertEquals`/`assertEqual`, `assertNotEquals`, `assertThrows`.
|
||||
- Preconditions: `require`, `check`.
|
||||
- Async/concurrency: `launch`, `yield`, `flow`, `delay`.
|
||||
- `Deferred.cancel()` cancels an active task.
|
||||
- `Deferred.await()` throws `CancellationException` if that task was cancelled.
|
||||
- Math: `floor`, `ceil`, `round`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`, `exp`, `ln`, `log10`, `log2`, `pow`, `sqrt`, `abs`, `clamp`.
|
||||
- These helpers also accept `lyng.decimal.Decimal`.
|
||||
- Exact Decimal path today: `abs`, `floor`, `ceil`, `round`, and `pow` with integral exponent.
|
||||
@ -28,14 +26,13 @@ Sources: `lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt`, `lynglib/s
|
||||
- Collections/types: `Iterable`, `Iterator`, `Collection`, `Array`, `List`, `ImmutableList`, `Set`, `ImmutableSet`, `Map`, `ImmutableMap`, `MapEntry`, `Range`, `RingBuffer`.
|
||||
- Random: singleton `Random` and class `SeededRandom`.
|
||||
- Async types: `Deferred`, `CompletableDeferred`, `Mutex`, `Flow`, `FlowBuilder`.
|
||||
- Async exception: `CancellationException`.
|
||||
- Delegation types: `Delegate`, `DelegateContext`.
|
||||
- Regex types: `Regex`, `RegexMatch`.
|
||||
- Also present: `Math.PI` namespace constant.
|
||||
|
||||
## 4. `lyng.stdlib` Module Surface (from `root.lyng`)
|
||||
### 4.1 Extern class declarations
|
||||
- Exceptions/delegation base: `Exception`, `CancellationException`, `IllegalArgumentException`, `NotImplementedException`, `Delegate`.
|
||||
- Exceptions/delegation base: `Exception`, `IllegalArgumentException`, `NotImplementedException`, `Delegate`.
|
||||
- Collections and iterables: `Iterable<T>`, `Iterator<T>`, `Collection<T>`, `Array<T>`, `List<T>`, `ImmutableList<T>`, `Set<T>`, `ImmutableSet<T>`, `Map<K,V>`, `ImmutableMap<K,V>`, `MapEntry<K,V>`, `RingBuffer<T>`.
|
||||
- Host iterator bridge: `KotlinIterator<T>`.
|
||||
- Random APIs: `extern object Random`, `extern class SeededRandom`.
|
||||
|
||||
@ -32,25 +32,10 @@ Depending on the platform, these coroutines may be executed on different CPU and
|
||||
assert(xIsCalled)
|
||||
>>> void
|
||||
|
||||
This example shows how to launch a coroutine with `launch` which returns [Deferred] instance, the latter have ways to await for the coroutine completion, cancel it if it is no longer needed, and retrieve possible result.
|
||||
This example shows how to launch a coroutine with `launch` which returns [Deferred] instance, the latter have ways to await for the coroutine completion and retrieve possible result.
|
||||
|
||||
Launch has the only argument which should be a callable (lambda usually) that is run in parallel (or cooperatively in parallel), and return anything as the result.
|
||||
|
||||
If you no longer need the result, cancel the deferred. Awaiting a cancelled deferred throws `CancellationException`:
|
||||
|
||||
var reached = false
|
||||
val work = launch {
|
||||
delay(100)
|
||||
reached = true
|
||||
"ok"
|
||||
}
|
||||
work.cancel()
|
||||
assertThrows(CancellationException) { work.await() }
|
||||
assert(work.isCancelled)
|
||||
assert(!work.isActive)
|
||||
assert(!reached)
|
||||
>>> void
|
||||
|
||||
## Synchronization: Mutex
|
||||
|
||||
Suppose we have a resource, that could be used concurrently, a counter in our case. If we won't protect it, concurrent usage cause RC, Race Condition, providing wrong result:
|
||||
|
||||
@ -84,7 +84,6 @@ fun calculateDepth(
|
||||
|
||||
h = hNew
|
||||
iter++
|
||||
println("iter: $iter: $h")
|
||||
}
|
||||
|
||||
// Не сошлось за maxIter
|
||||
@ -98,7 +97,7 @@ val d = 0.1 // м (10 см)
|
||||
|
||||
val depth = calculateDepth(T, m, d)
|
||||
if (depth != null) {
|
||||
println("Глубина: %.2f м"(depth))
|
||||
println("Глубина: %.2f м".format(depth))
|
||||
} else {
|
||||
println("Расчёт не сошёлся")
|
||||
}
|
||||
|
||||
@ -343,73 +343,6 @@ class Compiler(
|
||||
}
|
||||
return t
|
||||
}
|
||||
fun handleTopLevelKeyword(keyword: Token): Boolean {
|
||||
when (keyword.value) {
|
||||
"fun", "fn" -> {
|
||||
val nameToken = nextNonWs()
|
||||
if (nameToken.type != Token.Type.ID) return true
|
||||
val afterName = cc.peekNextNonWhitespace()
|
||||
if (afterName.type == Token.Type.DOT) {
|
||||
cc.nextNonWhitespace()
|
||||
val actual = cc.nextNonWhitespace()
|
||||
if (actual.type == Token.Type.ID) {
|
||||
extensionNames.add(actual.value)
|
||||
registerExtensionName(nameToken.value, actual.value)
|
||||
declareSlotNameIn(plan, extensionCallableName(nameToken.value, actual.value), isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(extensionCallableName(nameToken.value, actual.value))
|
||||
}
|
||||
return true
|
||||
}
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
return true
|
||||
}
|
||||
"val", "var" -> {
|
||||
val nameToken = nextNonWs()
|
||||
if (nameToken.type != Token.Type.ID) return true
|
||||
val afterName = cc.peekNextNonWhitespace()
|
||||
if (afterName.type == Token.Type.DOT) {
|
||||
cc.nextNonWhitespace()
|
||||
val actual = cc.nextNonWhitespace()
|
||||
if (actual.type == Token.Type.ID) {
|
||||
extensionNames.add(actual.value)
|
||||
registerExtensionName(nameToken.value, actual.value)
|
||||
declareSlotNameIn(plan, extensionPropertyGetterName(nameToken.value, actual.value), isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(extensionPropertyGetterName(nameToken.value, actual.value))
|
||||
if (keyword.value == "var") {
|
||||
declareSlotNameIn(plan, extensionPropertySetterName(nameToken.value, actual.value), isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(extensionPropertySetterName(nameToken.value, actual.value))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = keyword.value == "var", isDelegated = false)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
predeclaredTopLevelValueNames.add(nameToken.value)
|
||||
return true
|
||||
}
|
||||
"class", "object" -> {
|
||||
val nameToken = nextNonWs()
|
||||
if (nameToken.type == Token.Type.ID) {
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false)
|
||||
scopeSeedNames.add(nameToken.value)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
}
|
||||
return true
|
||||
}
|
||||
"enum" -> {
|
||||
val next = nextNonWs()
|
||||
val nameToken = if (next.type == Token.Type.ID && next.value == "class") nextNonWs() else next
|
||||
if (nameToken.type == Token.Type.ID) {
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false)
|
||||
scopeSeedNames.add(nameToken.value)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
try {
|
||||
while (cc.hasNext()) {
|
||||
val t = cc.next()
|
||||
@ -422,11 +355,66 @@ class Compiler(
|
||||
Token.Type.RBRACKET -> if (bracketDepth > 0) bracketDepth--
|
||||
Token.Type.ID -> if (depth == 0) {
|
||||
if (parenDepth > 0 || bracketDepth > 0) continue
|
||||
if (t.value == "extern") {
|
||||
handleTopLevelKeyword(nextNonWs())
|
||||
continue
|
||||
when (t.value) {
|
||||
"fun", "fn" -> {
|
||||
val nameToken = nextNonWs()
|
||||
if (nameToken.type != Token.Type.ID) continue
|
||||
val afterName = cc.peekNextNonWhitespace()
|
||||
if (afterName.type == Token.Type.DOT) {
|
||||
cc.nextNonWhitespace()
|
||||
val actual = cc.nextNonWhitespace()
|
||||
if (actual.type == Token.Type.ID) {
|
||||
extensionNames.add(actual.value)
|
||||
registerExtensionName(nameToken.value, actual.value)
|
||||
declareSlotNameIn(plan, extensionCallableName(nameToken.value, actual.value), isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(extensionCallableName(nameToken.value, actual.value))
|
||||
}
|
||||
continue
|
||||
}
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
}
|
||||
"val", "var" -> {
|
||||
val nameToken = nextNonWs()
|
||||
if (nameToken.type != Token.Type.ID) continue
|
||||
val afterName = cc.peekNextNonWhitespace()
|
||||
if (afterName.type == Token.Type.DOT) {
|
||||
cc.nextNonWhitespace()
|
||||
val actual = cc.nextNonWhitespace()
|
||||
if (actual.type == Token.Type.ID) {
|
||||
extensionNames.add(actual.value)
|
||||
registerExtensionName(nameToken.value, actual.value)
|
||||
declareSlotNameIn(plan, extensionPropertyGetterName(nameToken.value, actual.value), isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(extensionPropertyGetterName(nameToken.value, actual.value))
|
||||
if (t.value == "var") {
|
||||
declareSlotNameIn(plan, extensionPropertySetterName(nameToken.value, actual.value), isMutable = false, isDelegated = false)
|
||||
moduleDeclaredNames.add(extensionPropertySetterName(nameToken.value, actual.value))
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = t.value == "var", isDelegated = false)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
predeclaredTopLevelValueNames.add(nameToken.value)
|
||||
}
|
||||
"class", "object" -> {
|
||||
val nameToken = nextNonWs()
|
||||
if (nameToken.type == Token.Type.ID) {
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false)
|
||||
scopeSeedNames.add(nameToken.value)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
}
|
||||
}
|
||||
"enum" -> {
|
||||
val next = nextNonWs()
|
||||
val nameToken = if (next.type == Token.Type.ID && next.value == "class") nextNonWs() else next
|
||||
if (nameToken.type == Token.Type.ID) {
|
||||
declareSlotNameIn(plan, nameToken.value, isMutable = false, isDelegated = false)
|
||||
scopeSeedNames.add(nameToken.value)
|
||||
moduleDeclaredNames.add(nameToken.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
handleTopLevelKeyword(t)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
@ -1308,11 +1296,23 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
if (seedRecord != null) {
|
||||
seedImportTypeMetadata(name, seedRecord)
|
||||
val value = seedRecord.value
|
||||
if (!nameObjClass.containsKey(name)) {
|
||||
when (value) {
|
||||
is ObjClass -> nameObjClass[name] = value
|
||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
||||
}
|
||||
}
|
||||
return ImportBindingResolution(ImportBinding(name, ImportBindingSource.Seed), seedRecord)
|
||||
}
|
||||
if (rootRecord != null) {
|
||||
seedImportTypeMetadata(name, rootRecord)
|
||||
val value = rootRecord.value
|
||||
if (!nameObjClass.containsKey(name)) {
|
||||
when (value) {
|
||||
is ObjClass -> nameObjClass[name] = value
|
||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
||||
}
|
||||
}
|
||||
return ImportBindingResolution(ImportBinding(name, ImportBindingSource.Root), rootRecord)
|
||||
}
|
||||
if (moduleMatches.isEmpty()) return null
|
||||
@ -1327,7 +1327,13 @@ class Compiler(
|
||||
val candidates = byOrigin[origin] ?: mutableListOf()
|
||||
val preferred = candidates.firstOrNull { it.first.scope.packageName == origin } ?: candidates.first()
|
||||
val binding = ImportBinding(name, ImportBindingSource.Module(origin, preferred.first.pos))
|
||||
seedImportTypeMetadata(name, preferred.second)
|
||||
val value = preferred.second.value
|
||||
if (!nameObjClass.containsKey(name)) {
|
||||
when (value) {
|
||||
is ObjClass -> nameObjClass[name] = value
|
||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
||||
}
|
||||
}
|
||||
return ImportBindingResolution(binding, preferred.second)
|
||||
}
|
||||
val moduleNames = moduleMatches.keys.toList()
|
||||
@ -1335,24 +1341,14 @@ class Compiler(
|
||||
}
|
||||
val (module, record) = moduleMatches.values.first()
|
||||
val binding = ImportBinding(name, ImportBindingSource.Module(module.scope.packageName, module.pos))
|
||||
seedImportTypeMetadata(name, record)
|
||||
return ImportBindingResolution(binding, record)
|
||||
}
|
||||
|
||||
private fun seedImportTypeMetadata(name: String, record: ObjRecord) {
|
||||
if (record.typeDecl != null && nameTypeDecl[name] == null) {
|
||||
nameTypeDecl[name] = record.typeDecl
|
||||
}
|
||||
val value = record.value
|
||||
if (!nameObjClass.containsKey(name)) {
|
||||
record.typeDecl?.let { resolveTypeDeclObjClass(it) }?.let {
|
||||
nameObjClass[name] = it
|
||||
return
|
||||
}
|
||||
when (val value = record.value) {
|
||||
when (value) {
|
||||
is ObjClass -> nameObjClass[name] = value
|
||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
||||
}
|
||||
}
|
||||
return ImportBindingResolution(binding, record)
|
||||
}
|
||||
|
||||
private fun collectModuleRecordMatches(
|
||||
@ -4340,19 +4336,14 @@ class Compiler(
|
||||
is MapLiteralRef -> inferMapLiteralTypeDecl(ref)
|
||||
is ConstRef -> inferTypeDeclFromConst(ref.constValue)
|
||||
is CallRef -> {
|
||||
val targetDecl = resolveReceiverTypeDecl(ref.target)
|
||||
val targetName = when (val target = ref.target) {
|
||||
is LocalVarRef -> target.name
|
||||
is FastLocalVarRef -> target.name
|
||||
is LocalSlotRef -> target.name
|
||||
else -> null
|
||||
}
|
||||
if (targetDecl is TypeDecl.Function) {
|
||||
return targetDecl.returnType
|
||||
}
|
||||
if (targetName != null) {
|
||||
callableReturnTypeDeclByName[targetName]?.let { return it }
|
||||
(seedTypeDeclByName(targetName) as? TypeDecl.Function)?.let { return it.returnType }
|
||||
}
|
||||
inferCallReturnClass(ref)?.let { TypeDecl.Simple(it.className, false) }
|
||||
?: run {
|
||||
@ -4686,17 +4677,6 @@ class Compiler(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun lookupLocalTypeDeclByName(name: String): TypeDecl? {
|
||||
val slotLoc = lookupSlotLocation(name, includeModule = true) ?: return null
|
||||
return slotTypeDeclByScopeId[slotLoc.scopeId]?.get(slotLoc.slot)
|
||||
}
|
||||
|
||||
private fun lookupLocalObjClassByName(name: String): ObjClass? {
|
||||
val slotLoc = lookupSlotLocation(name, includeModule = true) ?: return null
|
||||
return slotTypeByScopeId[slotLoc.scopeId]?.get(slotLoc.slot)
|
||||
?: slotTypeDeclByScopeId[slotLoc.scopeId]?.get(slotLoc.slot)?.let { resolveTypeDeclObjClass(it) }
|
||||
}
|
||||
|
||||
private fun resolveReceiverTypeDecl(ref: ObjRef): TypeDecl? {
|
||||
return when (ref) {
|
||||
is LocalSlotRef -> {
|
||||
@ -4706,12 +4686,8 @@ class Compiler(
|
||||
?: nameTypeDecl[ref.name]
|
||||
?: seedTypeDeclByName(ref.name)
|
||||
}
|
||||
is LocalVarRef -> nameTypeDecl[ref.name]
|
||||
?: lookupLocalTypeDeclByName(ref.name)
|
||||
?: seedTypeDeclByName(ref.name)
|
||||
is FastLocalVarRef -> nameTypeDecl[ref.name]
|
||||
?: lookupLocalTypeDeclByName(ref.name)
|
||||
?: seedTypeDeclByName(ref.name)
|
||||
is LocalVarRef -> nameTypeDecl[ref.name] ?: seedTypeDeclByName(ref.name)
|
||||
is FastLocalVarRef -> nameTypeDecl[ref.name] ?: seedTypeDeclByName(ref.name)
|
||||
is FieldRef -> {
|
||||
val targetDecl = resolveReceiverTypeDecl(ref.target) ?: return null
|
||||
val targetClass = resolveTypeDeclObjClass(targetDecl) ?: resolveReceiverClassForMember(ref.target)
|
||||
@ -4757,13 +4733,11 @@ class Compiler(
|
||||
is LocalVarRef -> nameObjClass[ref.name]
|
||||
?.takeIf { it == ObjDynamic.type }
|
||||
?: nameObjClass[ref.name]
|
||||
?: lookupLocalObjClassByName(ref.name)
|
||||
?: nameTypeDecl[ref.name]?.let { resolveTypeDeclObjClass(it) }
|
||||
?: resolveClassByName(ref.name)
|
||||
is FastLocalVarRef -> nameObjClass[ref.name]
|
||||
?.takeIf { it == ObjDynamic.type }
|
||||
?: nameObjClass[ref.name]
|
||||
?: lookupLocalObjClassByName(ref.name)
|
||||
?: nameTypeDecl[ref.name]?.let { resolveTypeDeclObjClass(it) }
|
||||
?: resolveClassByName(ref.name)
|
||||
is ClassScopeMemberRef -> {
|
||||
@ -9082,10 +9056,7 @@ class Compiler(
|
||||
val effectiveEqToken = if (isProperty) null else eqToken
|
||||
|
||||
// Register the local name at compile time so that subsequent identifiers can be emitted as fast locals
|
||||
val isTopLevelExtern = actualExtern && declaringClassNameCaptured == null && slotPlanStack.size == 1
|
||||
if (!isStatic && declaringClassNameCaptured == null && (!actualExtern || isTopLevelExtern)) {
|
||||
declareLocalName(name, isMutable)
|
||||
}
|
||||
if (!isStatic && declaringClassNameCaptured == null && !actualExtern) declareLocalName(name, isMutable)
|
||||
val declKind = if (codeContexts.lastOrNull() is CodeContext.ClassBody) {
|
||||
SymbolKind.MEMBER
|
||||
} else {
|
||||
|
||||
@ -395,20 +395,9 @@ class Script(
|
||||
requireExactCount(2)
|
||||
decimalAwarePow(args[0], args[1])
|
||||
}
|
||||
addItem(
|
||||
"sqrt",
|
||||
false,
|
||||
ObjExternCallable.fromBridge {
|
||||
decimalAwareUnaryMath(args.firstAndOnly(), fallback = ::sqrt)
|
||||
},
|
||||
recordType = ObjRecord.Type.Fun,
|
||||
typeDecl = TypeDecl.Function(
|
||||
receiver = null,
|
||||
params = listOf(TypeDecl.TypeAny),
|
||||
returnType = TypeDecl.Simple("Real", false),
|
||||
nullable = false
|
||||
)
|
||||
)
|
||||
addFn("sqrt") {
|
||||
decimalAwareUnaryMath(args.firstAndOnly(), fallback = ::sqrt)
|
||||
}
|
||||
addFn("abs") {
|
||||
val x = args.firstAndOnly()
|
||||
if (x is ObjInt) ObjInt(x.value.absoluteValue)
|
||||
|
||||
@ -540,8 +540,7 @@ private fun buildStdlibDocs(): List<MiniDecl> {
|
||||
|
||||
// Concurrency helpers
|
||||
mod.classDoc(name = "Deferred", doc = "Represents a value that will be available in the future.", bases = listOf(type("Obj"))) {
|
||||
method(name = "cancel", doc = "Cancel the deferred if it is still active.")
|
||||
method(name = "await", doc = "Suspend until the value is available and return it. Throws `CancellationException` if cancelled.")
|
||||
method(name = "await", doc = "Suspend until the value is available and return it.")
|
||||
}
|
||||
mod.funDoc(
|
||||
name = "launch",
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlin.coroutines.cancellation.CancellationException as KotlinCancellationException
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
@ -34,27 +33,12 @@ open class ObjDeferred(val deferred: Deferred<Obj>): Obj() {
|
||||
scope.raiseError("Deferred constructor is not directly callable")
|
||||
}
|
||||
}.apply {
|
||||
addFnDoc(
|
||||
name = "cancel",
|
||||
doc = "Cancel this deferred if it is still active. Safe to call multiple times.",
|
||||
returns = type("lyng.Void"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
thisAs<ObjDeferred>().deferred.cancel()
|
||||
ObjVoid
|
||||
}
|
||||
addFnDoc(
|
||||
name = "await",
|
||||
doc = "Suspend until completion and return the result value. Throws `CancellationException` if cancelled.",
|
||||
doc = "Suspend until completion and return the result value (or throw if failed).",
|
||||
returns = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib"
|
||||
) {
|
||||
try {
|
||||
thisAs<ObjDeferred>().deferred.await()
|
||||
} catch (e: KotlinCancellationException) {
|
||||
requireScope().raiseError(ObjCancellationException(requireScope(), e.message ?: "Deferred was cancelled"))
|
||||
}
|
||||
}
|
||||
) { thisAs<ObjDeferred>().deferred.await() }
|
||||
addPropertyDoc(
|
||||
name = "isCompleted",
|
||||
doc = "Whether this deferred has completed (successfully or with an error).",
|
||||
@ -82,3 +66,4 @@ open class ObjDeferred(val deferred: Deferred<Obj>): Obj() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -278,7 +278,6 @@ open class ObjException(
|
||||
"AssertionFailedException",
|
||||
"ClassCastException",
|
||||
"IndexOutOfBoundsException",
|
||||
"CancellationException",
|
||||
"IllegalArgumentException",
|
||||
"IllegalStateException",
|
||||
"NoSuchElementException",
|
||||
@ -312,9 +311,6 @@ class ObjClassCastException(scope: Scope, message: String) : ObjException("Class
|
||||
class ObjIndexOutOfBoundsException(scope: Scope, message: String = "index out of bounds") :
|
||||
ObjException("IndexOutOfBoundsException", scope, message)
|
||||
|
||||
class ObjCancellationException(scope: Scope, message: String = "cancelled") :
|
||||
ObjException("CancellationException", scope, message)
|
||||
|
||||
class ObjIllegalArgumentException(scope: Scope, message: String = "illegal argument") :
|
||||
ObjException("IllegalArgumentException", scope, message)
|
||||
|
||||
|
||||
@ -58,30 +58,6 @@ class TestCoroutines {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeferredCancel() = runTest {
|
||||
eval(
|
||||
"""
|
||||
var reached = false
|
||||
val d = launch {
|
||||
delay(100)
|
||||
reached = true
|
||||
"ok"
|
||||
}
|
||||
|
||||
d.cancel()
|
||||
d.cancel()
|
||||
assertThrows(CancellationException) { d.await() }
|
||||
|
||||
delay(150)
|
||||
|
||||
assert(d.isCancelled)
|
||||
assert(!d.isActive)
|
||||
assert(!reached)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMutex() = runTest {
|
||||
eval(
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.lyng.eval
|
||||
import net.sergeych.lyng.obj.ObjBool
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class LocalRealMemberInferenceRegressionTest {
|
||||
|
||||
@Test
|
||||
fun sqrtInitializedLocalVarKeepsRealReceiverTypeForMembers() = runTest {
|
||||
val result = eval(
|
||||
"""
|
||||
fun probe(T: Real, c: Real, g: Real): Bool {
|
||||
fun passthrough(h: Real): Real = h / c
|
||||
|
||||
val term = 1.0 + g * T / c
|
||||
val sqrtTerm = sqrt(1.0 + 2.0 * g * T / c)
|
||||
assert(sqrtTerm is Real)
|
||||
assert(!sqrtTerm.isNaN())
|
||||
var h = (c * c / g) * (term - sqrtTerm)
|
||||
assert(passthrough(h) >= 0.0)
|
||||
assert(h is Real)
|
||||
!h.isNaN()
|
||||
}
|
||||
|
||||
probe(6.0, 340.0, 9.81)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
assertEquals(ObjBool(true), result)
|
||||
}
|
||||
}
|
||||
@ -5576,7 +5576,7 @@ class ScriptTest {
|
||||
|
||||
val depth = calculateDepth(T, m, d)
|
||||
if (depth != null) {
|
||||
println("Глубина: %.2f м"(depth))
|
||||
println("Глубина: %.2f м".format(depth))
|
||||
} else {
|
||||
println("Расчёт не сошёлся")
|
||||
}
|
||||
|
||||
@ -1,48 +1,11 @@
|
||||
package lyng.stdlib
|
||||
|
||||
/* Launch `code` asynchronously and return its result handle. */
|
||||
extern fun launch(code): Deferred
|
||||
/* Yield execution so other scheduled coroutines can run. */
|
||||
extern fun yield(): void
|
||||
/* Build a lazy asynchronous sequence. */
|
||||
extern fun flow(builder: FlowBuilder.()->void): Flow
|
||||
|
||||
/* Built-in exception type. */
|
||||
extern class Exception
|
||||
extern class IllegalArgumentException
|
||||
extern class NotImplementedException
|
||||
/* Raised when an awaited asynchronous task was cancelled before producing a value. */
|
||||
extern class CancellationException : Exception
|
||||
|
||||
/* A handle to a running asynchronous task. */
|
||||
extern class Deferred {
|
||||
/* Cancel the task if it is still active. Safe to call multiple times. */
|
||||
fun cancel(): void
|
||||
/* Suspend until the task finishes and return its value.
|
||||
Throws `CancellationException` if the task was cancelled. */
|
||||
fun await(): Object
|
||||
/* True when the task has finished, failed, or otherwise reached a terminal state. */
|
||||
val isCompleted: Bool
|
||||
/* True while the task is still running and has not been cancelled. */
|
||||
val isActive: Bool
|
||||
/* True when the task was cancelled. */
|
||||
val isCancelled: Bool
|
||||
}
|
||||
|
||||
/* A deferred result that can be completed manually. */
|
||||
extern class CompletableDeferred : Deferred {
|
||||
fun complete(value: Object): void
|
||||
}
|
||||
|
||||
/* Receiver passed into `flow { ... }` builders. */
|
||||
extern class FlowBuilder {
|
||||
fun emit(value: Object): void
|
||||
}
|
||||
|
||||
/* A cold asynchronous iterable sequence. */
|
||||
extern class Flow<T> : Iterable<T> {
|
||||
}
|
||||
|
||||
extern class Delegate
|
||||
extern class Iterable<T> {
|
||||
fun iterator(): Iterator<T>
|
||||
@ -124,7 +87,7 @@ extern class MapEntry<K,V> : Array<Object> {
|
||||
extern fun abs(x: Object): Object
|
||||
extern fun ln(x: Object): Object
|
||||
extern fun pow(x: Object, y: Object): Object
|
||||
extern fun sqrt(x: Object): Real
|
||||
extern fun sqrt(x: Object): Object
|
||||
extern fun clamp<T>(value: T, range: Range<T>): T
|
||||
|
||||
class SeededRandom {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user