Move native functions into the context

This commit is contained in:
Přemysl Eric Janouch 2017-05-21 09:47:24 +02:00
parent 0f4ece8867
commit c7b06a490f
Signed by: p
GPG Key ID: B715679E3A361BE6

127
ell.c
View File

@ -622,44 +622,9 @@ parser_run (struct parser *self, const char **e) {
// --- Runtime -----------------------------------------------------------------
struct context;
typedef bool (*handler_fn) (struct context *, struct item *, struct item **);
struct native_fn {
struct native_fn *next; ///< The next link in the chain
handler_fn handler; ///< Internal C handler, or NULL
char name[]; ///< The name of the function
};
struct native_fn *g_native; ///< Maps words to functions
static struct native_fn *
native_find (const char *name) {
for (struct native_fn *fn = g_native; fn; fn = fn->next)
if (!strcmp (fn->name, name))
return fn;
return NULL;
}
static bool
native_register (const char *name, handler_fn handler) {
struct native_fn *fn = native_find (name);
if (!fn) {
if (!(fn = calloc (1, sizeof *fn + strlen (name) + 1)))
return false;
strcpy (fn->name, name);
fn->next = g_native;
g_native = fn;
}
fn->handler = handler;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct context {
struct item *variables; ///< List of variables
struct native_fn *native; ///< Maps strings to C functions
char *error; ///< Error information
bool error_is_fatal; ///< Whether the error can be catched
@ -668,6 +633,14 @@ struct context {
void *user_data; ///< User data
};
typedef bool (*handler_fn) (struct context *, struct item *, struct item **);
struct native_fn {
struct native_fn *next; ///< The next link in the chain
handler_fn handler; ///< Internal C handler, or NULL
char name[]; ///< The name of the function
};
static void
context_init (struct context *ctx) {
memset (ctx, 0, sizeof *ctx);
@ -675,6 +648,11 @@ context_init (struct context *ctx) {
static void
context_free (struct context *ctx) {
struct native_fn *next, *iter;
for (iter = ctx->native; iter; iter = next) {
next = iter->next;
free (iter);
}
item_free_list (ctx->variables);
free (ctx->error);
}
@ -719,6 +697,30 @@ set (struct context *ctx, const char *name, struct item *value) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static struct native_fn *
native_find (struct context *ctx, const char *name) {
for (struct native_fn *fn = ctx->native; fn; fn = fn->next)
if (!strcmp (fn->name, name))
return fn;
return NULL;
}
static bool
native_register (struct context *ctx, const char *name, handler_fn handler) {
struct native_fn *fn = native_find (ctx, name);
if (!fn) {
if (!(fn = calloc (1, sizeof *fn + strlen (name) + 1)))
return false;
strcpy (fn->name, name);
fn->next = ctx->native;
ctx->native = fn;
}
fn->handler = handler;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static bool
set_error (struct context *ctx, const char *format, ...) {
va_list ap;
@ -795,10 +797,10 @@ execute_and_set_args (struct context *ctx, struct item *following) {
static bool
execute_native (struct context *ctx,
struct native_fn *fn, struct item *next, struct item **res) {
struct native_fn *fn, struct item *following, struct item **result) {
struct item *args = NULL;
bool ok = execute_args (ctx, next, &args)
&& fn->handler (ctx, args, res);
bool ok = execute_args (ctx, following, &args)
&& fn->handler (ctx, args, result);
item_free_list (args);
return ok;
}
@ -839,7 +841,7 @@ execute_statement
// Maybe something like (choose [@f1 @f2 @f3]) arg1 arg2 arg3
if (!body) {
struct native_fn *fn = native_find (name);
struct native_fn *fn = native_find (ctx, name);
if (!fn)
return set_error (ctx, "unknown function: %s", name);
if (execute_native (ctx, fn, following, result))
@ -1067,35 +1069,8 @@ defn (fn_concatenate) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static bool
init_native_library (void)
{
return native_register ("set", fn_set)
&& native_register ("list", fn_list)
&& native_register ("if", fn_if)
&& native_register ("for", fn_for)
&& native_register ("break", fn_break)
&& native_register ("map", fn_map)
&& native_register ("filter", fn_filter)
&& native_register ("print", fn_print)
&& native_register ("..", fn_concatenate);
}
static void
free_native_library (void) {
struct native_fn *next, *iter;
for (iter = g_native; iter; iter = next) {
next = iter->next;
free (iter);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static bool
init_runtime_library (struct context *ctx) {
bool ok = true;
struct {
const char *name; ///< Name of the function
const char *definition; ///< The defining script
@ -1105,6 +1080,7 @@ init_runtime_library (struct context *ctx) {
{ "unless", "arg cond body; if (not (eval @cond)) @body" },
};
bool ok = true;
for (size_t i = 0; i < N_ELEMENTS (functions); i++) {
struct parser parser;
parser_init (&parser,
@ -1123,7 +1099,17 @@ init_runtime_library (struct context *ctx) {
item_free_list (body);
parser_free (&parser);
}
return ok;
return ok
&& native_register (ctx, "set", fn_set)
&& native_register (ctx, "list", fn_list)
&& native_register (ctx, "if", fn_if)
&& native_register (ctx, "for", fn_for)
&& native_register (ctx, "break", fn_break)
&& native_register (ctx, "map", fn_map)
&& native_register (ctx, "filter", fn_filter)
&& native_register (ctx, "print", fn_print)
&& native_register (ctx, "..", fn_concatenate);
}
// --- Main --------------------------------------------------------------------
@ -1161,8 +1147,7 @@ main (int argc, char *argv[]) {
struct context ctx;
context_init (&ctx);
if (!init_native_library ()
|| !init_runtime_library (&ctx))
if (!init_runtime_library (&ctx))
printf ("%s\n", "runtime library initialization failed");
struct item *result = NULL;
@ -1176,8 +1161,6 @@ main (int argc, char *argv[]) {
if (failure)
printf ("%s: %s\n", "runtime error", failure);
context_free (&ctx);
free_native_library ();
return 0;
}