// Copyright (c) 1996-2002 Brian D. Carlstrom

package bdc.scheme.procedure;

import bdc.scheme.Scheme;
import bdc.scheme.SchemeException;
import bdc.scheme.Stack;
import bdc.scheme.exception.PrimitiveException;
import bdc.scheme.expression.Procedure3;
import bdc.scheme.expression.Procedure;
import bdc.util.ClassUtil;

/**
    (catch x y z)
*/
public class Catch extends Procedure3
{
    public Object apply3 (Stack stack) throws SchemeException
    {
        Object o1 = stack.array[stack.inUse-1];
        Object o2 = stack.array[stack.inUse-2];
        Object o3 = stack.array[stack.inUse-3];
        Procedure body      = Scheme.procedure(o1, this);
        String    throwable = Scheme.string(o2, this);
        Procedure handler   = Scheme.procedure(o3, this);

        try {
            return body.apply0(stack);
        }
        catch (PrimitiveException primitiveException) {
            Throwable t = primitiveException.throwable;
            if (!ClassUtil.instanceOf(t, throwable)) {
                throw primitiveException;
            }
            try {
                stack.addElement(t);
                return handler.apply1(stack);
            }
            finally {
                stack.inUse -= 1;
            }
        }
    }
}
