Started work on binding functions. Not yet complete.
This commit is contained in:
parent
f4303247b9
commit
efa6a3246d
17 changed files with 321 additions and 41 deletions
175
src/c/environment/function_bindings.c
Normal file
175
src/c/environment/function_bindings.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
* environment/function_bindings.c
|
||||
*
|
||||
* Post Scarcity Software Environment:
|
||||
*
|
||||
* Provide bindings for substrate functions. At least in theory, these
|
||||
* bindings only need to be initialised on node zero.
|
||||
* todo: they really ought to be in a namespace ::system:bootstrap, once I
|
||||
* have namespaces and paths working.
|
||||
*
|
||||
* (c) 2026 Simon Brooke <simon@journeyman.cc>
|
||||
* Licensed under GPL version 2.0, or, at your option, any later version.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "environment/privileged_keywords.h"
|
||||
#include "memory/node.h"
|
||||
#include "memory/pointer.h"
|
||||
#include "memory/tags.h"
|
||||
|
||||
#include "ops/assoc.h"
|
||||
#include "ops/bind.h"
|
||||
#include "ops/cond.h"
|
||||
#include "ops/eval_apply.h"
|
||||
#include "ops/eq.h"
|
||||
#include "ops/inspect.h"
|
||||
#include "ops/stack_ops.h"
|
||||
#include "ops/string_ops.h"
|
||||
|
||||
#include "payloads/cons.h"
|
||||
#include "payloads/function.h"
|
||||
#include "payloads/special.h"
|
||||
|
||||
/**
|
||||
* Bind this compiled `executable` function, as a Lisp function, to
|
||||
* this name in the `oblist`.
|
||||
* \todo where a function is not compiled from source, we could cache
|
||||
* the name on the source pointer. Would make stack frames potentially
|
||||
* more readable and aid debugging generally.
|
||||
*/
|
||||
|
||||
struct pso_pointer
|
||||
bind_function(struct pso_pointer frame_pointer, wchar_t *name, wchar_t *doc,
|
||||
struct pso_pointer (*executable)(struct pso_pointer)) {
|
||||
struct pso_pointer result = fetch_env(frame_pointer);
|
||||
struct pso_pointer n = c_string_to_lisp_symbol(frame_pointer, name);
|
||||
struct pso_pointer d = c_string_to_lisp_string(frame_pointer, doc);
|
||||
|
||||
struct pso_pointer meta =
|
||||
make_cons( frame_pointer, make_cons( frame_pointer, privileged_keyword_bootstrap, nil),
|
||||
make_cons( frame_pointer, make_cons( frame_pointer, privileged_keyword_name, n),
|
||||
make_cons( frame_pointer, make_cons( frame_pointer, privileged_keyword_documentation, d), nil)));
|
||||
|
||||
struct pso_pointer r = make_function(frame_pointer, meta, executable);
|
||||
|
||||
if (!exceptionp(r)) {
|
||||
result = make_cons( frame_pointer, make_cons( frame_pointer, n, r), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind this compiled `executable` function, as a Lisp special form, to
|
||||
* this `name` in the `oblist`.
|
||||
*/
|
||||
struct pso_pointer
|
||||
bind_special(struct pso_pointer frame_pointer, wchar_t *name, wchar_t *doc,
|
||||
struct pso_pointer (*executable)(struct pso_pointer)) {
|
||||
struct pso_pointer result = fetch_env(frame_pointer);
|
||||
struct pso_pointer n = c_string_to_lisp_symbol(frame_pointer, name);
|
||||
struct pso_pointer d = c_string_to_lisp_string(frame_pointer, doc);
|
||||
|
||||
struct pso_pointer meta =
|
||||
make_cons( frame_pointer, make_cons( frame_pointer, privileged_keyword_bootstrap, nil),
|
||||
make_cons( frame_pointer, make_cons( frame_pointer, privileged_keyword_name, n),
|
||||
make_cons( frame_pointer, make_cons( frame_pointer, privileged_keyword_documentation, d), nil)));
|
||||
|
||||
struct pso_pointer r = make_special(frame_pointer, meta, executable);
|
||||
|
||||
if (!exceptionp(r)) {
|
||||
result = make_cons( frame_pointer, make_cons( frame_pointer, n, r), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct function_data {
|
||||
char32_t *name;
|
||||
char32_t *documentation;
|
||||
void* executable;
|
||||
};
|
||||
|
||||
/* right, the problem with all those pretty '#ifdefs' which might allow us to
|
||||
* simply switch functions on and off just by including or not including .h
|
||||
* files is that the C compiler is too primitive to know how many items there
|
||||
* are in an array. So this number must be edited manually, and must be right.
|
||||
*/
|
||||
#define N_FUNCTION_INITIALISERS 4
|
||||
|
||||
/** initialisers for functions */
|
||||
struct function_data function_initialisers[] = {
|
||||
#ifdef __psse_ops_assoc_h
|
||||
{U"assoc",
|
||||
U"(assoc key store): search `store` for the value associated with "
|
||||
U"`key`.",
|
||||
&assoc},
|
||||
#endif
|
||||
#ifdef __psse_ops_bind_h
|
||||
{U"bind!",
|
||||
U"(bind! key value store): bind `key` to `value` in this store, modifying "
|
||||
U"the store if it is writable to the user, otherwise returning a new "
|
||||
U"store",
|
||||
&bind},
|
||||
#endif
|
||||
#ifdef __psse_ops_eq_h
|
||||
{U"eq",
|
||||
U"(eq args...): shallow, cheap equality; returns `t` if all `args...` "
|
||||
U"are the same object, else `nil`.",
|
||||
&eq},
|
||||
{U"equal",
|
||||
U"(equal a b): expensive, deep equality: returns `t` if objects `a` "
|
||||
U"and `b` have recursively equal value.",
|
||||
&equal},
|
||||
#endif
|
||||
#ifdef __psse_ops_eval_apply_h
|
||||
// TODO: there's a lot of other stuff in eval_apply.c, which ought to be in
|
||||
// other files but at present isn't.
|
||||
{U"apply",
|
||||
U"(apply fn args...): apply this `fn` to these `args...` and return "
|
||||
U"their value.",
|
||||
&lisp_apply},
|
||||
{U"eval",
|
||||
U"(eval expression): evaluate this `expression` and return its value",
|
||||
&lisp_eval},
|
||||
#endif
|
||||
#ifdef __psse_ops_inspect_h
|
||||
{
|
||||
U"inspect",
|
||||
U"(inspect expr), (inspect expr write-stream): inspect one complete "
|
||||
U"lisp expression and return `nil`. If `write-stream` is specified and "
|
||||
U"is a write stream, then print to that stream, else to the stream "
|
||||
U"which is the value of `*out*` in the environment.",
|
||||
&lisp_inspect
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* right, the problem with all those pretty '#ifdefs' which might allow us to
|
||||
* simply switch functions on and off just by including or not including .h
|
||||
* files is that the C compiler is too primitive to know how many items there
|
||||
* are in an array */
|
||||
#define N_SPECIAL_INITIALISERS 1
|
||||
|
||||
/** initialisers for special forms */
|
||||
struct function_data special_initialisers[] = {
|
||||
#ifdef __psse_ops_cond_h
|
||||
{U"cond",
|
||||
U"(cond clauses...): conditional. Each `clause` is expected to be a "
|
||||
U"list; if the first item in such a list evaluates to non-nil, the "
|
||||
U"remaining items in that list are evaluated in turn and the value of "
|
||||
U"the last returned. If no arg `clause` has a first element which "
|
||||
U"evaluates to non nil, then nil is returned",
|
||||
&lisp_cond},
|
||||
#endif
|
||||
};
|
||||
|
||||
struct pso_pointer
|
||||
initialise_function_bindings(struct pso_pointer frame_pointer) {
|
||||
struct pso_pointer result = fetch_env(frame_pointer);
|
||||
|
||||
return result;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue