WiseIndian / Coroutines-for-Scala-3

3 stars 2 forks source link

Support exception throwing within coroutines #13

Open WiseIndian opened 4 years ago

WiseIndian commented 4 years ago

It seems I found some sort of solution. The main challenge for the try catch was for me to keep the c out of the try catch.

My first iterations on the problem (which didnt work):

At first I thought I could do something like this:

[try {
    Z0 Z*
} catch {
    e2
}] c

which would become

'{
    try {
        [Z0] {
            () => 
                [try {
                    Z*
                } catch {
                    e2
                }]c
        }
    } catch {
        e2
    }
}

But as one can see c might end within the try catch which goes against the initial semantic of the program.

A solution that seems to work

Then I read again your solution for the while Fengyun and it inspired me :) We assume the catch doesnt contain any yieldval for now. And I omitted the finally block too, but since I assume it doesnt contain yieldval for the moment it can just be added after the catch with no problems.

        [[try {
          Z1*
        } catch {
          e2
        }]] c

would become

        '{
          val co = coroutine(Z1*)

          def f() = {

            var tryRet = None

            try {
              tryRet = co.continue()
            } catch  {
              e2
            }

            if (tryRet.isDefined) { 

              [[yieldval(tryRet.get)]] {() => '{ f() } }  //this could be simplified to the actual code returned by the transformation of yieldval to avoid one more call.
            } else ${  c() }

          }
          f()
        }

If the execution lands in if (tryRet.isDefined): This means the try actually yielded something. In this case we can yield the value yielded by the try. After the yield we can come back to f to execute what is left of the coroutine containing the try body.

There are two possibility for landing in the else: 1) the subcoroutine actually is done 2) an exception was thrown by the body of the try and caught. In both cases we continue by calling c()

I think the drawback from my solution is that I end up creating a new coroutine which could be a bit heavy to do within a function. So it might be nice to lift the created coroutine in the containing Coroutine class.