refs #22 @35m 2 shorter forms for catch block, fixed catch class instance type checks

This commit is contained in:
Sergey Chernov 2025-06-13 00:12:21 +04:00
parent 6c71f0a2e6
commit 5ed8b2f123
3 changed files with 106 additions and 32 deletions

View File

@ -778,7 +778,32 @@ Very much like in Kotlin. Try block returns its body block result, if no excepti
assertEquals( "OK", result)
>>> void
It is possible to catch several exceptions in the same block (TBD)
There is shorter form of catch block when you want to catch any exception:
var caught = null
try {
throw IllegalArgumentException()
}
catch(t) { // same as catch(t: Exception), but simpler
caught = t
}
assert( caught is IllegalArgumentException )
>>> void
And even shortest, for the Lying lang tradition, missing var is `it`:
var caught = null
try {
throw IllegalArgumentException()
}
catch { // same as catch(it: Exception), but simpler
caught = it
}
assert( caught is IllegalArgumentException )
>>> void
It is possible to catch several exceptions in the same block too, use
`catch( varName: ExceptionClass1, ExceptionClass2)`, etc.
# Self-assignments in expression

View File

@ -744,33 +744,49 @@ class Compiler(
cc.skipTokens(Token.Type.NEWLINE)
var t = cc.next()
while( t.value == "catch" ) {
ensureLparen(cc)
t = cc.next()
if( t.type != Token.Type.ID ) throw ScriptError(t.pos, "expected catch variable")
val catchVar = t
cc.skipTokenOfType(Token.Type.COLON)
// load list of exception classes
val exClassNames = mutableListOf<String>()
do {
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
t = cc.next()
if( t.type != Token.Type.ID )
throw ScriptError(t.pos, "expected exception class name")
exClassNames += t.value
t = cc.next()
when(t.type) {
Token.Type.COMMA -> {
continue
}
Token.Type.RPAREN -> {
break
}
else -> throw ScriptError(t.pos, "syntax error: expected ',' or ')'")
if (t.type != Token.Type.ID) throw ScriptError(t.pos, "expected catch variable")
val catchVar = t
val exClassNames = mutableListOf<String>()
if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
// load list of exception classes
do {
t = cc.next()
if (t.type != Token.Type.ID)
throw ScriptError(t.pos, "expected exception class name")
exClassNames += t.value
t = cc.next()
when (t.type) {
Token.Type.COMMA -> {
continue
}
Token.Type.RPAREN -> {
break
}
else -> throw ScriptError(t.pos, "syntax error: expected ',' or ')'")
}
} while (true)
} else {
// no type!
exClassNames += "Exception"
cc.skipTokenOfType(Token.Type.RPAREN)
}
} while(true)
val block = parseBlock(cc)
catches += CatchBlockData(catchVar, exClassNames, block)
cc.skipTokens(Token.Type.NEWLINE)
t = cc.next()
val block = parseBlock(cc)
catches += CatchBlockData(catchVar, exClassNames, block)
cc.skipTokens(Token.Type.NEWLINE)
t = cc.next()
} else {
// no (e: Exception) block: should be shortest variant `catch { ... }`
cc.skipTokenOfType(Token.Type.LBRACE, "expected catch(...) or catch { ... } here")
catches += CatchBlockData(Token("it", cc.currentPos(), Token.Type.ID), listOf("Exception"),
parseBlock(cc,true))
t = cc.next()
}
}
if( catches.isEmpty() )
throw ScriptError(cc.currentPos(), "try block must have at least one catch clause")
@ -802,7 +818,7 @@ class Compiler(
?: raiseSymbolNotFound("error clas not exists: $exceptionClassName")
println("exObj: $exObj")
println("objException: ${objException.objClass}")
if( objException.objClass == exObj )
if( objException.isInstanceOf(exObj) )
exceptionObject = objException
break
}

View File

@ -1753,12 +1753,7 @@ class ScriptTest {
fun testThrowExisting()= runTest {
eval("""
val x = IllegalArgumentException("test")
println("instance class",x::class)
println("instance", x)
println("Exception object",Exception)
println("... and it's class",Exception::class)
assert( x is Exception )
println(x)
var t = 0
var finallyCaught = false
@ -1780,4 +1775,42 @@ class ScriptTest {
assert(finallyCaught)
""".trimIndent())
}
@Test
fun testCatchShort1()= runTest {
eval("""
val x = IllegalArgumentException("test")
var t = 0
var finallyCaught = false
try {
t = 1
throw x
t = 2
}
catch(e) {
t = 31
}
finally {
finallyCaught = true
}
assertEquals(31, t)
assert(finallyCaught)
""".trimIndent())
}
@Test
fun testCatchShort2()= runTest {
eval("""
val x = IllegalArgumentException("test")
var caught = null
try {
throw x
}
catch {
caught = it
}
assert( caught is IllegalArgumentException )
""".trimIndent())
}
}