171 lines
5.2 KiB
Kotlin
171 lines
5.2 KiB
Kotlin
/*
|
|
* Copyright 2026 Sergey S. Chernov
|
|
*
|
|
* 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.Compiler
|
|
import net.sergeych.lyng.Arguments
|
|
import net.sergeych.lyng.Pos
|
|
import net.sergeych.lyng.Scope
|
|
import net.sergeych.lyng.Script
|
|
import net.sergeych.lyng.ScriptError
|
|
import net.sergeych.lyng.Source
|
|
import net.sergeych.lyng.Statement
|
|
import net.sergeych.lyng.asFacade
|
|
import net.sergeych.lyng.obj.ObjInt
|
|
import net.sergeych.lyng.obj.ObjString
|
|
import net.sergeych.lyng.obj.toInt
|
|
import net.sergeych.lyng.pacman.ImportManager
|
|
import kotlin.test.Test
|
|
import kotlin.test.assertContains
|
|
import kotlin.test.assertEquals
|
|
import kotlin.test.assertFailsWith
|
|
|
|
class CompilerVmReviewRegressionTest {
|
|
|
|
@Test
|
|
fun missingModuleCaptureFailsFastInsteadOfBecomingUnset() = runTest {
|
|
val manager = ImportManager()
|
|
manager.addTextPackages(
|
|
"""
|
|
package foo
|
|
|
|
val answer = 42
|
|
""".trimIndent()
|
|
)
|
|
val script = Compiler.compile(
|
|
Source(
|
|
"<missing-module-capture>",
|
|
"""
|
|
import foo
|
|
fun make() = { answer }
|
|
make()
|
|
""".trimIndent()
|
|
),
|
|
manager
|
|
)
|
|
|
|
val prepared = manager.newModule()
|
|
script.importInto(prepared)
|
|
val preparedLambda = script.execute(prepared)
|
|
assertEquals(42, prepared.asFacade().call(preparedLambda).toInt())
|
|
|
|
val rawModule = manager.newModule()
|
|
val hostScope = Scope(parent = rawModule, thisObj = ObjString("receiver"))
|
|
|
|
val lambda = script.execute(hostScope)
|
|
val ex = assertFailsWith<ScriptError> {
|
|
hostScope.asFacade().call(lambda)
|
|
}
|
|
assertContains(ex.errorMessage, "module binding 'answer'")
|
|
}
|
|
|
|
@Test
|
|
fun facadeCallUsesPreparedLambdaWithArgs() = runTest {
|
|
val lambda = Compiler.compile(
|
|
Source(
|
|
"<facade-call-lambda>",
|
|
"""
|
|
val base = 2
|
|
{ x -> x + base }
|
|
""".trimIndent()
|
|
),
|
|
Script.defaultImportManager
|
|
)
|
|
|
|
val scope = Script.newScope()
|
|
val callable = lambda.execute(scope)
|
|
assertEquals(42, scope.asFacade().call(callable, Arguments(ObjInt.of(40))).toInt())
|
|
}
|
|
|
|
@Test
|
|
fun genericInvokeHelpersUsePreparedLambdaEntryPoints() = runTest {
|
|
val unaryLambda = Compiler.compile(
|
|
Source(
|
|
"<generic-invoke-unary>",
|
|
"""
|
|
val delta = 2
|
|
{ x -> x + delta }
|
|
""".trimIndent()
|
|
),
|
|
Script.defaultImportManager
|
|
)
|
|
val nullaryLambda = Compiler.compile(
|
|
Source(
|
|
"<generic-invoke-nullary>",
|
|
"""
|
|
val base = 7
|
|
{ base }
|
|
""".trimIndent()
|
|
),
|
|
Script.defaultImportManager
|
|
)
|
|
|
|
val unaryScope = Script.newScope()
|
|
val nullaryScope = Script.newScope()
|
|
val unaryCallable = unaryLambda.execute(unaryScope)
|
|
val nullaryCallable = nullaryLambda.execute(nullaryScope)
|
|
|
|
assertEquals(42, unaryCallable.invoke(unaryScope, ObjString("receiver"), ObjInt.of(40)).toInt())
|
|
assertEquals(7, nullaryCallable.invoke(nullaryScope, ObjString("receiver")).toInt())
|
|
assertEquals(
|
|
42,
|
|
unaryCallable.invoke(
|
|
unaryScope,
|
|
Pos(Source("<generic-invoke-pos>", ""), 0, 0),
|
|
ObjString("receiver"),
|
|
Arguments(ObjInt.of(40))
|
|
).toInt()
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun statementCallUsesPreparedLambdaFastPath() = runTest {
|
|
val unaryLambda = Compiler.compile(
|
|
Source(
|
|
"<statement-call-unary>",
|
|
"""
|
|
val delta = 2
|
|
{ x -> x + delta }
|
|
""".trimIndent()
|
|
),
|
|
Script.defaultImportManager
|
|
)
|
|
|
|
val scope = Script.newScope()
|
|
val callable = unaryLambda.execute(scope) as Statement
|
|
|
|
assertEquals(42, callable.call(scope, ObjInt.of(40)).toInt())
|
|
}
|
|
|
|
@Test
|
|
fun subjectlessWhenReportsScriptError() = runTest {
|
|
val ex = assertFailsWith<ScriptError> {
|
|
Compiler.compile(
|
|
Source(
|
|
"<when-without-subject>",
|
|
"""
|
|
when {
|
|
true -> 1
|
|
}
|
|
""".trimIndent()
|
|
),
|
|
Script.defaultImportManager
|
|
)
|
|
}
|
|
assertContains(ex.errorMessage, "when without subject")
|
|
}
|
|
}
|