[plt-scheme] Code for catching exceptions in embedding applications

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Mon Nov 3 09:39:33 EST 2008

At Mon, 3 Nov 2008 11:14:07 +0300, "Sergey Khorev" wrote:
> 
>     environment = scheme_basic_env();
>     declare_modules(environment);

At this point, `environment' is set up ok.

>     env = (Scheme_Env *)scheme_make_namespace(0, NULL);
>     declare_modules(env);

But then you create another namespace...


Solution 1:

If you don't actually need a second namespace, just set `env' to
`environment'.

The other solutions below assume that you do need a second namespace.


Solution 2 (incomplete):

It turns out that declare_modules() doesn't use its `env' argument.
Instead, it declares modules in the current environment, which is
`environment'. I'll adjust the docs to clarify this.

Even if you reverse the order of the declare and parameter assignment,
like this:

    env = (Scheme_Env *)scheme_make_namespace(0, NULL);
    scheme_set_param(scheme_current_config(), MZCONFIG_ENV, env);
    declare_modules(env);

then it doesn't work, because the empty namespace doesn't have some
built-in modules that are needed for the `scheme/base' declarations.

You could attach the built-in declarations from `environment' to `env',
but it's best just to attach `scheme/base' itself, as in Solution 3.


Solution 3 (works with latest in SVN):

To create a separate `env', it's best to call `make-base-namespace'
from `scheme/base' instead of scheme_make_namespace(). That operation
attaches the declared modules from the original namespace, instead of
redeclaring them.

The C code looks like this:

    a[0] = scheme_intern_symbol("scheme/base");
    a[1] = scheme_intern_symbol("make-base-namespace");
    p = scheme_dynamic_require(2, a);
    env = scheme_apply(p, 0, NULL);

However, this didn't work previously, because the namespace-attaching
operation didn't transfer module-name mappings. That is, in the new
namespace, the module resolver didn't track that `scheme/base' was
pre-declared.

In SVN, I've adjusted the module renamer created by `mzc --c-mods' to
correctly track attaches, so that this approach works. The code below
works with the latest in SVN.

----------------------------------------

#define MZ_PRECISE_GC 1

#include <scheme.h>

#include "base.c"

static Scheme_Env *environment = NULL;

    static int
scheme_main(void *data)
{
    char *e =
	"(lambda (thunk) "
	"(with-handlers ([void (lambda (exn) (cons #f exn))]) "
	"(cons #t (thunk))))";

    Scheme_Env *env = NULL;
    Scheme_Object *exn_catching_apply = NULL;
    Scheme_Object *p = NULL, *a[2] = { NULL, NULL };

    MZ_GC_DECL_REG(6);
    MZ_GC_VAR_IN_REG(0, env);
    MZ_GC_VAR_IN_REG(1, exn_catching_apply);
    MZ_GC_VAR_IN_REG(2, p);
    MZ_GC_ARRAY_VAR_IN_REG(3, a, 2);
    MZ_GC_REG();

    MZ_REGISTER_STATIC(environment);

    environment = scheme_basic_env();
    declare_modules(environment);

    a[0] = scheme_intern_symbol("scheme/base");
    a[1] = scheme_intern_symbol("make-base-namespace");
    p = scheme_dynamic_require(2, a);
    env = scheme_apply(p, 0, NULL);

    scheme_set_param(scheme_current_config(), MZCONFIG_ENV, 
                     (Scheme_Object *)env);
    scheme_namespace_require(a[0]);
    exn_catching_apply = scheme_eval_string(e, env);

    MZ_GC_UNREG();

    a[1] = scheme_intern_symbol("read-eval-print-loop");
    p = scheme_dynamic_require(2, a);
    p = scheme_dynamic_require(2, a);
    env = scheme_apply(p, 0, NULL);

    return 1;
}

int main()
{
    return scheme_main_stack_setup(1, scheme_main, NULL);
}



Posted on the users mailing list.