diff --git a/docs/tutorial.md b/docs/tutorial.md index 00315d0..fa58422 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -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 diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index e6b6a50..a644e30 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -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() - 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() + 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 } diff --git a/library/src/commonTest/kotlin/ScriptTest.kt b/library/src/commonTest/kotlin/ScriptTest.kt index 7893cc3..532f99e 100644 --- a/library/src/commonTest/kotlin/ScriptTest.kt +++ b/library/src/commonTest/kotlin/ScriptTest.kt @@ -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()) + } + } \ No newline at end of file