ref: 244cb2a15ce8e48cde9bd7080526840d296c5b5c
parent: 66e9533beb55468e14d91738780d15c70c509f8a
author: Matthew Flatt <mflatt@racket-lang.org>
date: Sat Nov 12 05:01:17 CST 2022
Zuo: add 'dynamic-require to `zuo` module hash tables The 'dynamic-require key at the Zuo primitive module layer provides a way into the `zuo` module layer. Also, fix `zuo_ext_apply` for embedding applications.
--- a/lib/zuo/private/base-common/entry.zuo
+++ b/lib/zuo/private/base-common/entry.zuo
@@ -19,7 +19,9 @@
(kernel-eval (cons 'begin (cons '(void) body)))
(hash 'macromod-provides outs
'submodules submods
- merge-bindings-export-key (make-export-merge-binds ctx (state-binds state))))))
+ merge-bindings-export-key (make-export-merge-binds ctx (state-binds state))
+ ;; for getting into this module world from the `zuo/kernel` module world:
+ 'dynamic-require dynamic-require))))
(hash
;; makes `#lang zuo/private/base[-hygienic] work:
@@ -26,7 +28,7 @@
'read-and-eval (make-read-and-eval (lambda (ctx)
(make-state (binds-create top-provides ctx)
(initial-nominals language-mod-path top-provides))))
- ;; makes `(require zuo/private/base[hygienic])` work:
+ ;; makes `(require zuo/private/base[-hygienic])` work:
'macromod-provides top-provides
;; for making a new `#lang` with initial imports from `mod-path`:
'make-language
@@ -42,4 +44,5 @@
(merge-binds (make-state (binds-create provides ctx)
(initial-nominals mod-path provides))
m-binds)))
- 'macromod-provides (hash-ref (module->hash mod-path) 'macromod-provides #f)))))
+ 'macromod-provides (hash-ref (module->hash mod-path) 'macromod-provides #f)
+ 'dynamic-require dynamic-require))))
--- a/zuo-doc/fake-zuo.rkt
+++ b/zuo-doc/fake-zuo.rkt
@@ -192,6 +192,7 @@
build-module-path
kernel-env
kernel-eval
+ dynamic-require
runtime-env
dump-image-and-exit
--- a/zuo-doc/lang-zuo.scrbl
+++ b/zuo-doc/lang-zuo.scrbl
@@ -21,6 +21,17 @@
@racketmodname[zuo/build], @racketmodname[zuo/shell], @racketmodname[zuo/thread],
@racketmodname[zuo/glob], or @racketmodname[zuo/config].
+When using @racket[module->hash] on @racketmodname[zuo/base],
+@racketmodname[zuo], or a module implemented with one of those
+languages, the resulting hash table includes @racket['dynamic-require]
+mapped to the @racket[dynamic-require] function. Getting
+@racket[dynamic-require] that way provides a path from the primitive
+@seclink["module-protocol"]{Zuo kernel module protocol} to
+@racketmodname[zuo/base] module exports.
+
+@history[#:changed "1.2" @elem{Added the @racket['dynamic-require] key
+ for @racketmodname[zuo] and related languages.}]
+
@section{Syntax and Evaluation Model}
A @racketmodname[zuo] module consists of a sequence of definitions
--- a/zuo-doc/overview.scrbl
+++ b/zuo-doc/overview.scrbl
@@ -271,6 +271,15 @@
looks for a @racket['main] submodule and runs it (i.e., calls the
thunk) if present.
+The @racketmodname[zuo], @racketmodname[zuo/base], and
+@racketmodname[zuo/hygienic] languages do not specify how their
+provided-variable information is represented in a module hash table,
+but they do specify that @racket['dynamic-require] is mapped to the
+@racket[dynamic-require] function, and then @racket[dynamic-require]
+can be used to access provided values.
+
+@history[#:changed "1.2" @elem{Added the @racket['dynamic-require] key
+ for @racketmodname[zuo] and related languages.}]
@section[#:tag "paths"]{Path Handling}
--- a/zuo.c
+++ b/zuo.c
@@ -3,7 +3,7 @@
declarations. */
#define ZUO_VERSION 1
-#define ZUO_MINOR_VERSION 1
+#define ZUO_MINOR_VERSION 2
#if defined(_MSC_VER) || defined(__MINGW32__)
# define ZUO_WINDOWS
@@ -7464,13 +7464,18 @@
zuo_ext_t *zuo_ext_kernel_env() { return z.o_top_env; }
zuo_ext_t *zuo_ext_apply(zuo_ext_t *proc, zuo_ext_t *args) {
- /* special-case primtives, so this cna be used to perform primitive
+ /* special-case primtives, so this can be used to perform primitive
operations without triggering a GC */
if (proc->tag == zuo_primitive_tag) {
zuo_primitive_t *f = (zuo_primitive_t *)proc;
return f->dispatcher(f->proc, args);
- } else
- return zuo_kernel_eval(zuo_cons(proc, args));
+ } else {
+ /* quote arguments */
+ zuo_t *l, *quoted = z.o_null, *quote = zuo_symbol("quote");
+ for (l = zuo_cons(proc, args); l != z.o_null; l = _zuo_cdr(l))
+ quoted = zuo_cons(zuo_cons(quote, zuo_cons(_zuo_car(l), z.o_null)), quoted);
+ return zuo_kernel_eval(zuo_reverse(quoted));
+ }
}
void zuo_ext_runtime_init(zuo_ext_t *lib_path, zuo_ext_t *runtime_env) { zuo_runtime_init(lib_path, runtime_env); }
--- a/zuo.h
+++ b/zuo.h
@@ -78,6 +78,11 @@
procedure. Arguments are in a list created with `zuo_ext_cons` and
`zuo_ext_null`: */
ZUO_EXPORT zuo_ext_t *zuo_ext_apply(zuo_ext_t *proc, zuo_ext_t *args);
+/* Note: Prior to version 1.2, this function was broken and evaluated
+ the procedure and arguments as expressions instead of using them as
+ values when `proc` is not a promitive. The following `#define`
+ reflects the repair: */
+#define ZUO_EXT_APPLY_ALWAYS_EXPECTS_VALUES 1
/* ======================================================================== */
/*
@@ -93,9 +98,15 @@
/* After `zuo_ext_runtime_init`, all functionality is available. You
can load a module from a file by extracting `module->hash` from the
kernel env. Or you can declare and run a module directly from
- source text, giveing it a module path that is eiter a symbolic
- library path or a file path. */
+ source text, giving it a module path that is eiter a symbolic
+ library path or a file path.
+ Note that the result of the kernel's `module->hash` function or the
+ `zuo_ext_eval_module` is just a hash table. If the module is
+ implemented in `zuo` or a related language, you can use the symbol
+ `'dynamic-require` to get the `dynamic-require` function, and then
+ you can use that function to access provided values. */
+
ZUO_EXPORT zuo_ext_t *zuo_ext_eval_module(zuo_ext_t *as_module_path, const char *content, long long len);
/* For saving and retriving a value across an evaluation, which is
@@ -105,7 +116,9 @@
#endif
-/* Here's a simple example embedding application: */
+/* ======================================================================== */
+/* Here's a simple example embedding application that makes an extra
+ primitive `random-five` available: */
#if 0
#include <stdio.h>
@@ -143,6 +156,57 @@
printf("The answer was %d\n", (int)zuo_ext_integer_value(v));
else
printf("Something went wrong!\n");
+
+ return 0;
+}
+
+#endif
+
+/* ======================================================================== */
+/* Here's a example embedding application that doesn't need a new
+ primitive, but where the module is implemented with `#lang zuo`, so
+ we need to go through `dynamic-require` to get provided values: */
+#if 0
+
+#include <stdio.h>
+#include <string.h>
+#include "zuo.h"
+
+/* Link with a copy of "zuo.c" created by `zuo local/image.zuo` so
+ that the `zuo` module is available. */
+
+int main() {
+ const char *prog = "#lang zuo (provide main) (define (main) (+ 1 2))";
+ zuo_ext_t *ht, *dynamic_require, *main, *v;
+
+ /* Step 1 */
+ zuo_ext_primitive_init();
+
+ /* Step 2 */
+ zuo_ext_image_init(NULL);
+
+ /* Step 3 */
+ zuo_ext_runtime_init(zuo_ext_false(), zuo_ext_empty_hash());
+
+ /* Run `prog`: */
+ ht = zuo_ext_eval_module(zuo_ext_symbol("main-app"), prog, strlen(prog));
+
+ dynamic_require = zuo_ext_hash_ref(ht,
+ zuo_ext_symbol("dynamic-require"),
+ zuo_ext_false());
+
+ main = zuo_ext_apply(dynamic_require,
+ zuo_ext_cons(zuo_ext_symbol("main-app"),
+ zuo_ext_cons(zuo_ext_symbol("main"),
+ zuo_ext_null())));
+
+ v = zuo_ext_apply(main, zuo_ext_null());
+
+ printf("%s\n",
+ zuo_ext_string_ptr(zuo_ext_apply(zuo_ext_hash_ref(zuo_ext_kernel_env(),
+ zuo_ext_symbol("~s"),
+ zuo_ext_false()),
+ zuo_ext_cons(v, zuo_ext_null()))));
return 0;
}