fixed wrong line report on throw statement
This commit is contained in:
parent
a229f227e1
commit
72c6dc2bde
@ -389,7 +389,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
"throw" -> {
|
"throw" -> {
|
||||||
val s = parseThrowStatement()
|
val s = parseThrowStatement(t.pos)
|
||||||
operand = StatementRef(s)
|
operand = StatementRef(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -916,7 +916,7 @@ class Compiler(
|
|||||||
"class" -> parseClassDeclaration()
|
"class" -> parseClassDeclaration()
|
||||||
"enum" -> parseEnumDeclaration()
|
"enum" -> parseEnumDeclaration()
|
||||||
"try" -> parseTryStatement()
|
"try" -> parseTryStatement()
|
||||||
"throw" -> parseThrowStatement()
|
"throw" -> parseThrowStatement(id.pos)
|
||||||
"when" -> parseWhenStatement()
|
"when" -> parseWhenStatement()
|
||||||
else -> {
|
else -> {
|
||||||
// triples
|
// triples
|
||||||
@ -1080,15 +1080,26 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun parseThrowStatement(): Statement {
|
private suspend fun parseThrowStatement(start: Pos): Statement {
|
||||||
val throwStatement = parseStatement() ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
val throwStatement = parseStatement() ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
||||||
return statement {
|
// Important: bind the created statement to the position of the `throw` keyword so that
|
||||||
var errorObject = throwStatement.execute(this)
|
// any raised error reports the correct source location.
|
||||||
if (errorObject is ObjString)
|
return statement(start) { sc ->
|
||||||
errorObject = ObjException(this, errorObject.value)
|
var errorObject = throwStatement.execute(sc)
|
||||||
if (errorObject is ObjException)
|
// Rebind error scope to the throw-site position so ScriptError.pos is accurate
|
||||||
raiseError(errorObject)
|
val throwScope = sc.createChildScope(pos = start)
|
||||||
else raiseError("this is not an exception object: $errorObject")
|
errorObject = when (errorObject) {
|
||||||
|
is ObjString -> ObjException(throwScope, errorObject.value)
|
||||||
|
is ObjException -> ObjException(
|
||||||
|
errorObject.exceptionClass,
|
||||||
|
throwScope,
|
||||||
|
errorObject.message,
|
||||||
|
errorObject.extraData,
|
||||||
|
errorObject.useStackTrace
|
||||||
|
)
|
||||||
|
else -> throwScope.raiseError("this is not an exception object: $errorObject")
|
||||||
|
}
|
||||||
|
throwScope.raiseError(errorObject as ObjException)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3519,4 +3519,21 @@ class ScriptTest {
|
|||||||
""".trimIndent()).toString())
|
""".trimIndent()).toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThrowReportsSource() = runTest {
|
||||||
|
try {
|
||||||
|
eval(
|
||||||
|
"""
|
||||||
|
// line 1
|
||||||
|
// line 2
|
||||||
|
throw "the test"
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
} catch (se: ScriptError) {
|
||||||
|
println(se.message)
|
||||||
|
// Pos.line is zero-based
|
||||||
|
assertEquals(2, se.pos.line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
66
lynglib/src/jvmTest/kotlin/ThrowSourcePosJvmTest.kt
Normal file
66
lynglib/src/jvmTest/kotlin/ThrowSourcePosJvmTest.kt
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Sergey S. Chernov
|
||||||
|
*/
|
||||||
|
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import net.sergeych.lyng.Scope
|
||||||
|
import net.sergeych.lyng.ScriptError
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
class ThrowSourcePosJvmTest {
|
||||||
|
|
||||||
|
private fun assertThrowLine(code: String, expectedLine: Int) {
|
||||||
|
try {
|
||||||
|
runBlocking { Scope().eval(code) }
|
||||||
|
fail("Expected ScriptError to be thrown, but nothing was thrown")
|
||||||
|
} catch (se: ScriptError) {
|
||||||
|
println(se.message)
|
||||||
|
assertEquals(expectedLine, se.pos.line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simpleThrow_afterComments_reportsCorrectLine() {
|
||||||
|
val code = """
|
||||||
|
// line 1
|
||||||
|
// line 2
|
||||||
|
throw "simple"
|
||||||
|
""".trimIndent()
|
||||||
|
// zero-based line index
|
||||||
|
assertThrowLine(code, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun inlineThrow_withLeadingSpaces_reportsCorrectLine() {
|
||||||
|
val code = """
|
||||||
|
val x = 1
|
||||||
|
throw "boom"
|
||||||
|
""".trimIndent()
|
||||||
|
// throw is on the 2nd line (zero-based index 1)
|
||||||
|
assertThrowLine(code, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun throwInsideBlock_reportsCorrectLine() {
|
||||||
|
val code = """
|
||||||
|
if( true ) {
|
||||||
|
// comment
|
||||||
|
throw "boom"
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
// throw is on the 3rd line of the snippet (zero-based index 2)
|
||||||
|
assertThrowLine(code, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun throwAsExpression_reportsCorrectLine() {
|
||||||
|
val code = """
|
||||||
|
val x = null
|
||||||
|
val y = x ?: throw "npe-like"
|
||||||
|
""".trimIndent()
|
||||||
|
// throw is on the 2nd line (zero-based index 1)
|
||||||
|
assertThrowLine(code, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user