fixed samples test

This commit is contained in:
Sergey Chernov 2026-02-18 09:17:12 +03:00
parent a0ecbfd334
commit dc9885c218
4 changed files with 134 additions and 14 deletions

View File

@ -1,23 +1,23 @@
// Sample: Operator Overloading in Lyng // Sample: Operator Overloading in Lyng
class Vector(val x, val y) { class Vector<T>(val x: T, val y: T) {
// Overload + // Overload +
fun plus(other) = Vector(x + other.x, y + other.y) fun plus(other: Vector<U>) = Vector(x + other.x, y + other.y)
// Overload - // Overload -
fun minus(other) = Vector(x - other.x, y - other.y) fun minus(other: Vector<U>) = Vector(x - other.x, y - other.y)
// Overload unary - // Overload unary -
fun negate() = Vector(-x, -y) fun negate() = Vector(-x, -y)
// Overload == // Overload ==
fun equals(other) { fun equals(other) {
if (other is Vector) x == other.x && y == other.y if (other is Vector<U>) x == other.x && y == other.y
else false else false
} }
// Overload * (scalar multiplication) // Overload * (scalar multiplication)
fun mul(scalar) = Vector(x * scalar, y * scalar) fun mul(scalar: Int | Real) = Vector(x * scalar, y * scalar)
override fun toString() = "Vector(${x}, ${y})" override fun toString() = "Vector(${x}, ${y})"
} }

View File

@ -13,7 +13,6 @@ fun findSumLimit(f) {
println("limit reached after "+n+" rounds") println("limit reached after "+n+" rounds")
break sum break sum
} }
n++
} }
else { else {
println("limit not reached") println("limit not reached")

View File

@ -6797,6 +6797,118 @@ class Compiler(
return t.pos return t.pos
} }
private data class SmartCastTarget(
val name: String? = null,
val scopeId: Int? = null,
val slot: Int? = null,
val typeDecl: TypeDecl,
)
private data class SmartCastRestore(
val name: String?,
val nameHad: Boolean,
val namePrev: TypeDecl?,
val scopeId: Int?,
val slot: Int?,
val slotHad: Boolean,
val slotPrev: TypeDecl?,
val slotMapCreated: Boolean,
)
private fun smartCastTargetFromRef(ref: ObjRef, typeDecl: TypeDecl): SmartCastTarget? = when (ref) {
is LocalSlotRef -> {
val ownerScopeId = ref.captureOwnerScopeId ?: ref.scopeId
val ownerSlot = ref.captureOwnerSlot ?: ref.slot
SmartCastTarget(scopeId = ownerScopeId, slot = ownerSlot, typeDecl = typeDecl)
}
is LocalVarRef -> SmartCastTarget(name = ref.name, typeDecl = typeDecl)
is FastLocalVarRef -> SmartCastTarget(name = ref.name, typeDecl = typeDecl)
else -> null
}
private fun extractSmartCasts(condition: Statement): Pair<List<SmartCastTarget>, List<SmartCastTarget>> {
val ref = unwrapDirectRef(condition) ?: return emptyList<SmartCastTarget>() to emptyList()
if (ref !is BinaryOpRef) return emptyList<SmartCastTarget>() to emptyList()
if (ref.op != BinOp.IS && ref.op != BinOp.NOTIS) return emptyList<SmartCastTarget>() to emptyList()
val typeRef = ref.right as? net.sergeych.lyng.obj.TypeDeclRef ?: return emptyList<SmartCastTarget>() to emptyList()
val typeDecl = expandTypeAliases(typeRef.decl(), typeRef.pos())
val target = smartCastTargetFromRef(ref.left, typeDecl) ?: return emptyList<SmartCastTarget>() to emptyList()
return if (ref.op == BinOp.IS) {
listOf(target) to emptyList()
} else {
emptyList<SmartCastTarget>() to listOf(target)
}
}
private fun applySmartCasts(overrides: List<SmartCastTarget>): List<SmartCastRestore> {
if (overrides.isEmpty()) return emptyList()
val restores = ArrayList<SmartCastRestore>(overrides.size)
for (override in overrides) {
if (override.name != null) {
val had = nameTypeDecl.containsKey(override.name)
val prev = nameTypeDecl[override.name]
nameTypeDecl[override.name] = override.typeDecl
restores.add(
SmartCastRestore(
name = override.name,
nameHad = had,
namePrev = prev,
scopeId = null,
slot = null,
slotHad = false,
slotPrev = null,
slotMapCreated = false,
)
)
} else if (override.scopeId != null && override.slot != null) {
val map = slotTypeDeclByScopeId[override.scopeId]
val mapCreated = map == null
val targetMap = map ?: mutableMapOf<Int, TypeDecl>().also { slotTypeDeclByScopeId[override.scopeId] = it }
val had = targetMap.containsKey(override.slot)
val prev = targetMap[override.slot]
targetMap[override.slot] = override.typeDecl
restores.add(
SmartCastRestore(
name = null,
nameHad = false,
namePrev = null,
scopeId = override.scopeId,
slot = override.slot,
slotHad = had,
slotPrev = prev,
slotMapCreated = mapCreated,
)
)
}
}
return restores
}
private fun restoreSmartCasts(restores: List<SmartCastRestore>) {
if (restores.isEmpty()) return
for (restore in restores.asReversed()) {
if (restore.name != null) {
if (restore.nameHad) {
nameTypeDecl[restore.name] = restore.namePrev!!
} else {
nameTypeDecl.remove(restore.name)
}
} else if (restore.scopeId != null && restore.slot != null) {
val map = slotTypeDeclByScopeId[restore.scopeId]
if (map != null) {
if (restore.slotHad) {
map[restore.slot] = restore.slotPrev!!
} else {
map.remove(restore.slot)
}
if (restore.slotMapCreated && map.isEmpty()) {
slotTypeDeclByScopeId.remove(restore.scopeId)
}
}
}
}
}
private suspend fun parseIfStatement(): Statement { private suspend fun parseIfStatement(): Statement {
val start = ensureLparen() val start = ensureLparen()
@ -6805,7 +6917,13 @@ class Compiler(
val pos = ensureRparen() val pos = ensureRparen()
val ifBody = parseStatement() ?: throw ScriptError(pos, "Bad if statement: expected statement") val (trueCasts, falseCasts) = extractSmartCasts(condition)
val ifRestores = applySmartCasts(trueCasts)
val ifBody = try {
parseStatement() ?: throw ScriptError(pos, "Bad if statement: expected statement")
} finally {
restoreSmartCasts(ifRestores)
}
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true) cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
// could be else block: // could be else block:
@ -6813,8 +6931,12 @@ class Compiler(
// we generate different statements: optimization // we generate different statements: optimization
val stmt = if (t2.type == Token.Type.ID && t2.value == "else") { val stmt = if (t2.type == Token.Type.ID && t2.value == "else") {
val elseBody = val elseRestores = applySmartCasts(falseCasts)
val elseBody = try {
parseStatement() ?: throw ScriptError(pos, "Bad else statement: expected statement") parseStatement() ?: throw ScriptError(pos, "Bad else statement: expected statement")
} finally {
restoreSmartCasts(elseRestores)
}
IfStatement(condition, ifBody, elseBody, start) IfStatement(condition, ifBody, elseBody, start)
} else { } else {
cc.previous() cc.previous()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com * Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,11 +18,11 @@
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.sergeych.lyng.Scope import net.sergeych.lyng.Script
import net.sergeych.lyng.toSource
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Paths import java.nio.file.Paths
import kotlin.io.path.extension import kotlin.io.path.extension
import kotlin.test.Ignore
import kotlin.test.Test import kotlin.test.Test
import kotlin.time.Clock import kotlin.time.Clock
@ -31,9 +31,9 @@ suspend fun executeSampleTests(fileName: String) {
Files.readString(Paths.get(fileName)) Files.readString(Paths.get(fileName))
} }
runBlocking { runBlocking {
val c = Scope() val c = Script.newScope()
val start = Clock.System.now() val start = Clock.System.now()
c.eval(sample) c.eval(sample.toSource(fileName))
val time = Clock.System.now() - start val time = Clock.System.now() - start
println("$time: $fileName") println("$time: $fileName")
// delay(100) // delay(100)
@ -41,7 +41,6 @@ suspend fun executeSampleTests(fileName: String) {
} }
} }
@Ignore("TODO(compile-time-res): legacy tests disabled")
class SamplesTest { class SamplesTest {
@Test @Test