forum-msg-id-125915-edit

Original date:2014-12-30 23:23:43 Edited by: dcuny Subject: Try/Catch

I'm wondering how try/catch/finally might be implemented in Euphoria.

I've only looked briefly at the interpreter, and not much at all at the C code generator, so I apologize if some of this is nonsense.

First, instead exiting on an error, RTFatal() would have to have set some sort of flag.

Because the implementation would have to work with the C version of Euphoria as well as the interpreter, the most straight-forward thing to do would be to implement new opcodes.

So let's assume there were a new opcode, ON_ERROR address that would jump to address if the error flag was set. This opcode would need to be inserted after any call that could potentially call RTFatal. This means opcodes as mundane as ATOM_CHECK and as complex as SWITCH_RT, but certainly not every opcode.

It would also have to be inserted after the return from any non-trivial user routine, since something as simple as an atom declaration could generate a runtime error.

While the implementation in Euphoria would be fairly straight-forward, along the lines of:

procedure opON_ERROR() 
    -- jump to address following opcode if fatal_error_flag is set 
    if fatal_error_flag then 
        pc = Code[pc+1] 
    else 
        pc += 2 
    end if 
end procedure 

For the sake of speed, I'll assume that ON_ERROR would be implemented as "real" code and not a subroutine, along the lines of:

    if (fatal_error_flag) goto L_CATCH_22; 

so to make things a bit more efficient, the code to clear the error flag should probably be another opcode called CLEAR_ERROR, implemented at the top of the catch block. I'd imagine would be as simple as

    _rt_fatal_flag = 0; 

Of course, there's always the possibility that an error might happen outside of a try/catch block. There are a couple ways this could be handled. One option would be to add a new opcode, along the lines of RETURNF, but only returning if the error flag was set.

Another option would be to have ON_ERROR jump to an actual RETURNF automatically placed at the end of the routine. On returning to the calling routine, the error would be detected by an ON_ERROR opcode that would automatically be generated.

In the case of a forward reference, Euphoria wouldn't know if the routine could potentially throw an error. By default, it could insert an ON_ERROR after any forward references.

At the finally portion of the try/catch/finally block, things get a bit more dicey. That's because finally is guaranteed to be executed, even if there is no error.

There are a number of different ways that finally can be triggered:

  • Exiting the try block without error.
  • An error in the try or catch block.
  • An error in the catch block.
  • Exiting the try or catch block with a return.
  • Exiting the try or catch block with a goto.

For example, if a return is encountered deep inside a bunch of nested try/catch/finally blocks, all the finally blocks need to be called before exiting the routine. The catch is that the finally can't be called via a standard jump, because it has to return to the next instruction. That means implementing an equivalent to BASIC's GOSUB.

In the interpreter, this could be done via a stack. In standard C setjmp and longjmp() look like they'll do the trick.

So from a very cursory look, it seems feasible that try/catch/finally could be coded in Euphoria - both the interpreter and the C version - fairly efficiently, without too many changes to the code. I'd also guess that it could be an option - a with try-catch would generate code that would throw errors, and without try-catch would generate "classic" Euphoria code.

Thoughts?

Not Categorized, Please Help

Search



Quick Links

User menu

Not signed in.

Misc Menu