Implement first try of a module system
Very much inspired by lua, as so often: The module system maintains a list of searchers that will be called with the requested module name. They can then return a loader function, which will then be called again with the module name. That loader then returns the actual module, which is then cached. We also add a goofy "foo" module in main.c to test this.
This commit is contained in:
parent
c07caa9aa2
commit
4d01f20d6e
4 changed files with 148 additions and 0 deletions
|
|
@ -835,6 +835,8 @@ void apfl_registry_set(apfl_ctx, void *key_major, size_t key_minor, apfl_stackid
|
|||
void apfl_registry_delete(apfl_ctx, void *key_major, size_t key_minor);
|
||||
bool apfl_registry_try_get(apfl_ctx, void *key_major, size_t key_minor);
|
||||
|
||||
void apfl_modules_register(apfl_ctx ctx, const char *name, apfl_stackidx modloader);
|
||||
|
||||
enum apfl_call_stack_entry_type {
|
||||
APFL_CSE_FUNCTION,
|
||||
APFL_CSE_CFUNCTION,
|
||||
|
|
|
|||
|
|
@ -700,6 +700,41 @@ add_builtin(apfl_ctx ctx, const char *name, apfl_cfunc func)
|
|||
apfl_dict_set(ctx, -3, -2, -1);
|
||||
}
|
||||
|
||||
static int cmod_searcher_registry_key;
|
||||
|
||||
static void
|
||||
cmod_searcher(apfl_ctx ctx)
|
||||
{
|
||||
ONE_ARG(ctx, "cmod-searcher");
|
||||
if (!apfl_registry_try_get(ctx, &cmod_searcher_registry_key, 0)) {
|
||||
apfl_drop(ctx, -1);
|
||||
apfl_push_nil(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (apfl_get_member_if_exists(ctx, -1, -2)) {
|
||||
apfl_sym_some(ctx);
|
||||
apfl_push_pair(ctx, -1, -2);
|
||||
} else {
|
||||
apfl_push_nil(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
apfl_modules_register(apfl_ctx ctx, const char *name, apfl_stackidx modloader)
|
||||
{
|
||||
apfl_move_to_top_of_stack(ctx, modloader);
|
||||
|
||||
if (!apfl_registry_try_get(ctx, &cmod_searcher_registry_key, 0)) {
|
||||
apfl_dict_create(ctx);
|
||||
}
|
||||
|
||||
apfl_push_const_string(ctx, name);
|
||||
apfl_dict_set(ctx, -2, -1, -3);
|
||||
|
||||
apfl_registry_set(ctx, &cmod_searcher_registry_key, 0, -1);
|
||||
}
|
||||
|
||||
void
|
||||
apfl_builtins(apfl_ctx ctx)
|
||||
{
|
||||
|
|
@ -744,4 +779,5 @@ apfl_builtins(apfl_ctx ctx)
|
|||
add_builtin(ctx, "raise", impl_raise);
|
||||
add_builtin(ctx, "getsym-Some", apfl_sym_some);
|
||||
add_builtin(ctx, "get-argv", get_argv);
|
||||
add_builtin(ctx, "cmod-searcher", cmod_searcher);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,6 +188,45 @@
|
|||
}
|
||||
}
|
||||
|
||||
andalso := {
|
||||
f ->
|
||||
(f)
|
||||
f ~fs ->
|
||||
result := (f)
|
||||
if result { andalso ~fs } { result }
|
||||
}
|
||||
|
||||
orelse := {
|
||||
f ->
|
||||
(f)
|
||||
f ~fs ->
|
||||
result := (f)
|
||||
if result { result } { orelse ~fs }
|
||||
}
|
||||
|
||||
find-first := { l f ->
|
||||
out := nil
|
||||
i := 0
|
||||
n := len l
|
||||
while {andalso {== out nil} {< i n}} {
|
||||
{
|
||||
Some:x ->
|
||||
out = Some::x
|
||||
nil ->
|
||||
} (f l@i)
|
||||
|
||||
i = ++ i
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
unwrap-some := {
|
||||
Some:x then _ -> then x
|
||||
x _ else -> else x
|
||||
x then -> unwrap-some x then identity
|
||||
}
|
||||
|
||||
has-key := { k container ->
|
||||
{
|
||||
Some: _ -> true
|
||||
|
|
@ -199,6 +238,60 @@
|
|||
((load-file f))
|
||||
}
|
||||
|
||||
modules := ({
|
||||
loaded-modules := [->]
|
||||
searchers := []
|
||||
|
||||
ImportError := symbol 'ImportError
|
||||
|
||||
add-searcher := { s ->
|
||||
searchers = [~searchers s]
|
||||
}
|
||||
|
||||
add-searcher { m ->
|
||||
unwrap-some (get-optional m loaded-modules) { mod ->
|
||||
{ Some::mod }
|
||||
}
|
||||
}
|
||||
|
||||
add-searcher { m ->
|
||||
unwrap-some (builtins.cmod-searcher m) { loader ->
|
||||
Some::(loader)
|
||||
}
|
||||
}
|
||||
|
||||
import := { name ->
|
||||
maybe-mod := find-first searchers { s ->
|
||||
unwrap-some (s name) { loader ->
|
||||
loader name
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Some:mod ->
|
||||
loaded-modules@name = mod
|
||||
mod
|
||||
nil ->
|
||||
raise ImportError::(& "Module " name " not found")
|
||||
} maybe-mod
|
||||
}
|
||||
|
||||
add-preloaded-module := { name mod ->
|
||||
loaded-modules@name = mod
|
||||
}
|
||||
|
||||
modules := [
|
||||
'import -> import
|
||||
'add-searcher -> add-searcher
|
||||
'add-preloaded-module -> add-preloaded-module
|
||||
'ImportError -> ImportError
|
||||
]
|
||||
|
||||
add-preloaded-module 'modules modules
|
||||
|
||||
modules
|
||||
})
|
||||
|
||||
# Dictionary of exported functions
|
||||
[
|
||||
'if -> if
|
||||
|
|
@ -257,5 +350,10 @@
|
|||
'symbol -> symbol
|
||||
'Some -> Some
|
||||
'get-argv -> builtins.get-argv
|
||||
'andalso -> andalso
|
||||
'orelse -> orelse
|
||||
'find-first -> find-first
|
||||
'unwrap-some -> unwrap-some
|
||||
'import -> modules.import
|
||||
]
|
||||
}
|
||||
|
|
|
|||
12
src/main.c
12
src/main.c
|
|
@ -166,6 +166,15 @@ eval_whole_file(apfl_ctx ctx, void *opaque)
|
|||
|
||||
#define FMT_TRY(x) if (!(x)) { rv = 1; goto err; }
|
||||
|
||||
static void
|
||||
foomod(apfl_ctx ctx)
|
||||
{
|
||||
apfl_dict_create(ctx);
|
||||
apfl_push_const_string(ctx, "bar");
|
||||
apfl_push_const_string(ctx, "baz");
|
||||
apfl_dict_set(ctx, -3, -2, -1);
|
||||
}
|
||||
|
||||
static int
|
||||
eval(
|
||||
struct apfl_source_reader source_reader,
|
||||
|
|
@ -193,6 +202,9 @@ eval(
|
|||
}
|
||||
apfl_argv_set(ctx, -1);
|
||||
|
||||
apfl_push_cfunc(ctx, foomod, 0);
|
||||
apfl_modules_register(ctx, "foo", -1);
|
||||
|
||||
int rv = 0;
|
||||
if (run_as_repl) {
|
||||
apfl_iterative_runner runner = apfl_iterative_runner_new(ctx, source_reader);
|
||||
|
|
|
|||
Loading…
Reference in a new issue