parent
5ed8b2f123
commit
c3bf536bab
129
docs/exceptions_handling.md
Normal file
129
docs/exceptions_handling.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# Exceptions handling
|
||||||
|
|
||||||
|
Exceptions are widely used in modern programming languages, so
|
||||||
|
they are implemented also in Lyng and in the most complete way.
|
||||||
|
|
||||||
|
# Exception classes
|
||||||
|
|
||||||
|
Exceptions are throwing instances of some class that inherits `Exception`
|
||||||
|
across the code. Below is the list of built-in exceptions. Note that
|
||||||
|
only objects that inherit `Exception` can be thrown. For example:
|
||||||
|
|
||||||
|
assert( IllegalArgumentException() is Exception)
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
# Try statement: catching exceptions
|
||||||
|
|
||||||
|
There general pattern is:
|
||||||
|
|
||||||
|
```
|
||||||
|
try_statement = try_clause, [catch_clause, ...], [finally_clause]
|
||||||
|
|
||||||
|
try_clause = "try", "{", statements, "}"
|
||||||
|
|
||||||
|
catch_clause = "catch", [(full_catch | shorter_catch)], "{", statements "}"
|
||||||
|
|
||||||
|
full_catch = "(", catch_var, ":", exception_class [, excetpion_class...], ")
|
||||||
|
|
||||||
|
shorter_catch = "(", catch_var, ")"
|
||||||
|
|
||||||
|
finally_clause = "{", statements, "}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's in details.
|
||||||
|
|
||||||
|
## Full catch block:
|
||||||
|
|
||||||
|
val result = try {
|
||||||
|
throw IllegalArgumentException("the test")
|
||||||
|
}
|
||||||
|
catch( x: IndexOutOfBoundsException, IllegalArgumentException) {
|
||||||
|
x.message
|
||||||
|
}
|
||||||
|
catch(x: Exception) {
|
||||||
|
"bad"
|
||||||
|
}
|
||||||
|
assertEquals(result, "the test")
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
Because our exception is listed in a first catch block, it is processed there.
|
||||||
|
|
||||||
|
The full form allow a single catch block to process exceptions with specified classes and bind actual caught object to
|
||||||
|
the given variable. This is most common and well known form, implemented like this or similar in many other languages,
|
||||||
|
like Kotlin, Java or C++.
|
||||||
|
|
||||||
|
## Shorter form
|
||||||
|
|
||||||
|
When you want to catch _all_ the exceptions, you should write `catch(e: Exception)`,
|
||||||
|
but it is somewhat redundant, so there is simpler variant:
|
||||||
|
|
||||||
|
val sample2 = try {
|
||||||
|
throw IllegalArgumentException("sample 2")
|
||||||
|
}
|
||||||
|
catch(x) {
|
||||||
|
x.message
|
||||||
|
}
|
||||||
|
assertEquals( sample2, "sample 2" )
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
But well most likely you will find default variable `it`, like in Kotlin, more than enough
|
||||||
|
to catch all exceptions to, then you can write it even shorter:
|
||||||
|
|
||||||
|
val sample2 = try {
|
||||||
|
throw IllegalArgumentException("sample 3")
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
it.message
|
||||||
|
}
|
||||||
|
assertEquals( sample2, "sample 3" )
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
You can even check the type of the `it` and create more convenient and sophisticated processing logic. Such approach is
|
||||||
|
used, for example, in Scala.
|
||||||
|
|
||||||
|
# Conveying data with exceptions
|
||||||
|
|
||||||
|
The simplest way is to provide exception string and `Exception` class:
|
||||||
|
|
||||||
|
try {
|
||||||
|
throw Exception("this is my exception")
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
it.message
|
||||||
|
}
|
||||||
|
>>> "this is my exception"
|
||||||
|
|
||||||
|
This way, in turn, can also be shortened, as it is overly popular:
|
||||||
|
|
||||||
|
try {
|
||||||
|
throw "this is my exception"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
it.message
|
||||||
|
}
|
||||||
|
>>> "this is my exception"
|
||||||
|
|
||||||
|
The trick, though, works with strings only, and always provide `Exception` instances, which is good for debugging but
|
||||||
|
most often not enough.
|
||||||
|
|
||||||
|
# Custom error classes
|
||||||
|
|
||||||
|
_this functionality is not yet released_
|
||||||
|
|
||||||
|
# Standard exception classes
|
||||||
|
|
||||||
|
| class | notes |
|
||||||
|
|----------------------------|-------------------------------------------------------|
|
||||||
|
| Exception | root of al throwable objects |
|
||||||
|
| NullPointerException | |
|
||||||
|
| AssertionFailedException | |
|
||||||
|
| ClassCastException | |
|
||||||
|
| IndexOutOfBoundsException | |
|
||||||
|
| IllegalArgumentException | |
|
||||||
|
| IllegalAssignmentException | assigning to val, etc. |
|
||||||
|
| SymbolNotDefinedException | |
|
||||||
|
| IterationEndException | attempt to read iterator past end, `hasNext == false` |
|
||||||
|
| AccessException | attempt to access private members or like |
|
||||||
|
| UnknownException | unexpected kotlin exception caught |
|
||||||
|
| | |
|
||||||
|
|
@ -12,7 +12,7 @@ In other word, the code usually works as expected when you see it. So, nothing u
|
|||||||
__Other documents to read__ maybe after this one:
|
__Other documents to read__ maybe after this one:
|
||||||
|
|
||||||
- [Advanced topics](advanced_topics.md), [declaring arguments](declaring_arguments.md)
|
- [Advanced topics](advanced_topics.md), [declaring arguments](declaring_arguments.md)
|
||||||
- [OOP notes](OOP.md)
|
- [OOP notes](OOP.md), [exception handling](exceptions_handling.md)
|
||||||
- [math in Lyng](math.md)
|
- [math in Lyng](math.md)
|
||||||
- Some class references: [List], [Real], [Range], [Iterable], [Iterator]
|
- Some class references: [List], [Real], [Range], [Iterable], [Iterator]
|
||||||
- Some samples: [combinatorics](samples/combinatorics.lyng.md), national vars and loops: [сумма ряда](samples/сумма_ряда.lyng.md). More at [samples folder](samples)
|
- Some samples: [combinatorics](samples/combinatorics.lyng.md), national vars and loops: [сумма ряда](samples/сумма_ряда.lyng.md). More at [samples folder](samples)
|
||||||
|
@ -725,7 +725,9 @@ class Compiler(
|
|||||||
private fun parseThrowStatement(cc: CompilerContext): Statement {
|
private fun parseThrowStatement(cc: CompilerContext): Statement {
|
||||||
val throwStatement = parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
val throwStatement = parseStatement(cc) ?: throw ScriptError(cc.currentPos(), "throw object expected")
|
||||||
return statement {
|
return statement {
|
||||||
val errorObject = throwStatement.execute(this)
|
var errorObject = throwStatement.execute(this)
|
||||||
|
if( errorObject is ObjString )
|
||||||
|
errorObject = ObjException(this, errorObject.value)
|
||||||
if( errorObject is ObjException )
|
if( errorObject is ObjException )
|
||||||
raiseError(errorObject)
|
raiseError(errorObject)
|
||||||
else raiseError("this is not an exception object: $errorObject")
|
else raiseError("this is not an exception object: $errorObject")
|
||||||
@ -816,12 +818,11 @@ class Compiler(
|
|||||||
for (exceptionClassName in cdata.classNames) {
|
for (exceptionClassName in cdata.classNames) {
|
||||||
val exObj = ObjException.getErrorClass(exceptionClassName)
|
val exObj = ObjException.getErrorClass(exceptionClassName)
|
||||||
?: raiseSymbolNotFound("error clas not exists: $exceptionClassName")
|
?: raiseSymbolNotFound("error clas not exists: $exceptionClassName")
|
||||||
println("exObj: $exObj")
|
if( objException.isInstanceOf(exObj) ) {
|
||||||
println("objException: ${objException.objClass}")
|
|
||||||
if( objException.isInstanceOf(exObj) )
|
|
||||||
exceptionObject = objException
|
exceptionObject = objException
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if( exceptionObject != null ) {
|
if( exceptionObject != null ) {
|
||||||
val catchContext = this.copy(pos = cdata.catchVar.pos)
|
val catchContext = this.copy(pos = cdata.catchVar.pos)
|
||||||
catchContext.addItem(cdata.catchVar.value, false, objException)
|
catchContext.addItem(cdata.catchVar.value, false, objException)
|
||||||
|
@ -347,13 +347,16 @@ open class ObjException(exceptionClass: ExceptionClass, val context: Context, va
|
|||||||
|
|
||||||
class ExceptionClass(val name: String,vararg parents: ObjClass) : ObjClass(name, *parents) {
|
class ExceptionClass(val name: String,vararg parents: ObjClass) : ObjClass(name, *parents) {
|
||||||
override suspend fun callOn(context: Context): Obj {
|
override suspend fun callOn(context: Context): Obj {
|
||||||
return ObjException(this, context, name).apply {
|
val message = context.args.getOrNull(0)?.toString() ?: name
|
||||||
println(">>>> "+this)
|
return ObjException(this, context, message)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
override fun toString(): String = "ExceptionClass[$name]@${hashCode().encodeToHex()}"
|
override fun toString(): String = "ExceptionClass[$name]@${hashCode().encodeToHex()}"
|
||||||
}
|
}
|
||||||
val Root = ExceptionClass("Throwable")
|
val Root = ExceptionClass("Throwable").apply {
|
||||||
|
addConst("message", statement {
|
||||||
|
(thisObj as ObjException).message.toObj()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private val op = ProtectedOp()
|
private val op = ProtectedOp()
|
||||||
private val existingErrorClasses = mutableMapOf<String, ExceptionClass>()
|
private val existingErrorClasses = mutableMapOf<String, ExceptionClass>()
|
||||||
|
@ -1813,4 +1813,24 @@ class ScriptTest {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAccessEHData() = runTest {
|
||||||
|
eval("""
|
||||||
|
val x = IllegalArgumentException("test")
|
||||||
|
val m = try {
|
||||||
|
throw x
|
||||||
|
null
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
println(e)
|
||||||
|
println(e::class)
|
||||||
|
println(e.message)
|
||||||
|
println("--------------")
|
||||||
|
e.message
|
||||||
|
}
|
||||||
|
println(m)
|
||||||
|
assert( m == "test" )
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -268,4 +268,9 @@ class BookTest {
|
|||||||
fun testArgumentBooks() = runTest {
|
fun testArgumentBooks() = runTest {
|
||||||
runDocTests("../docs/declaring_arguments.md")
|
runDocTests("../docs/declaring_arguments.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testExceptionsBooks() = runTest {
|
||||||
|
runDocTests("../docs/exceptions_handling.md")
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user