mirror of
https://github.com/janet-lang/janet
synced 2025-01-11 08:00:27 +00:00
Add lookups for marshalling and unmarshalling.
Allow generating lookup tables from the current environment.
This commit is contained in:
parent
c3ba613959
commit
98f2c6feab
@ -332,7 +332,6 @@ static void janet_quick_asm(
|
||||
}
|
||||
memcpy(def->bytecode, bytecode, bytecode_size);
|
||||
janet_def(env, name, janet_wrap_function(janet_thunk(def)));
|
||||
janet_register(name, janet_wrap_function(janet_thunk(def)));
|
||||
}
|
||||
|
||||
/* Macros for easier inline janet assembly */
|
||||
|
@ -376,26 +376,21 @@ static const JanetReg cfuns[] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static void addf(JanetTable *env, const char *name, Janet val) {
|
||||
janet_def(env, name, val);
|
||||
janet_register(name, val);
|
||||
}
|
||||
|
||||
/* Module entry point */
|
||||
int janet_lib_io(JanetArgs args) {
|
||||
JanetTable *env = janet_env(args);
|
||||
janet_cfuns(env, NULL, cfuns);
|
||||
|
||||
/* stdout */
|
||||
addf(env, "stdout",
|
||||
janet_def(env, "stdout",
|
||||
makef(stdout, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE));
|
||||
|
||||
/* stderr */
|
||||
addf(env, "stderr",
|
||||
janet_def(env, "stderr",
|
||||
makef(stderr, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE));
|
||||
|
||||
/* stdin */
|
||||
addf(env, "stdin",
|
||||
janet_def(env, "stdin",
|
||||
makef(stdin, IO_READ | IO_NOT_CLOSEABLE | IO_SERIALIZABLE));
|
||||
|
||||
return 0;
|
||||
|
132
src/core/marsh.c
132
src/core/marsh.c
@ -31,6 +31,7 @@ typedef struct {
|
||||
jmp_buf err;
|
||||
JanetBuffer *buf;
|
||||
JanetTable seen;
|
||||
JanetTable *rreg;
|
||||
JanetFuncEnv **seen_envs;
|
||||
JanetFuncDef **seen_defs;
|
||||
int32_t nextid;
|
||||
@ -78,6 +79,59 @@ enum {
|
||||
LB_FUNCDEF_REF
|
||||
} LeadBytes;
|
||||
|
||||
/* Helper to look inside an entry in an environment */
|
||||
static Janet entry_getval(Janet env_entry) {
|
||||
if (janet_checktype(env_entry, JANET_TABLE)) {
|
||||
JanetTable *entry = janet_unwrap_table(env_entry);
|
||||
Janet checkval = janet_table_get(entry, janet_csymbolv(":value"));
|
||||
if (janet_checktype(checkval, JANET_NIL)) {
|
||||
checkval = janet_table_get(entry, janet_csymbolv(":ref"));
|
||||
}
|
||||
return checkval;
|
||||
} else if (janet_checktype(env_entry, JANET_STRUCT)) {
|
||||
const JanetKV *entry = janet_unwrap_struct(env_entry);
|
||||
Janet checkval = janet_struct_get(entry, janet_csymbolv(":value"));
|
||||
if (janet_checktype(checkval, JANET_NIL)) {
|
||||
checkval = janet_struct_get(entry, janet_csymbolv(":ref"));
|
||||
}
|
||||
return checkval;
|
||||
} else {
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a reverse lookup table for an environment (for marshaling) */
|
||||
JanetTable *janet_env_rreg(JanetTable *env) {
|
||||
JanetTable *renv = janet_table(env->count);
|
||||
while (env) {
|
||||
for (int32_t i = 0; i < env->capacity; i++) {
|
||||
if (janet_checktype(env->data[i].key, JANET_SYMBOL)) {
|
||||
janet_table_put(renv,
|
||||
entry_getval(env->data[i].value),
|
||||
env->data[i].key);
|
||||
}
|
||||
}
|
||||
env = env->proto;
|
||||
}
|
||||
return renv;
|
||||
}
|
||||
|
||||
/* Make a forward lookup table from an environment (for unmarshaling) */
|
||||
JanetTable *janet_env_reg(JanetTable *env) {
|
||||
JanetTable *renv = janet_table(env->count);
|
||||
while (env) {
|
||||
for (int32_t i = 0; i < env->capacity; i++) {
|
||||
if (janet_checktype(env->data[i].key, JANET_SYMBOL)) {
|
||||
janet_table_put(renv,
|
||||
env->data[i].key,
|
||||
entry_getval(env->data[i].value));
|
||||
}
|
||||
}
|
||||
env = env->proto;
|
||||
}
|
||||
return renv;
|
||||
}
|
||||
|
||||
/* Marshal an integer onto the buffer */
|
||||
static void pushint(MarshalState *st, int32_t x) {
|
||||
if (x >= 0 && x < 200) {
|
||||
@ -258,7 +312,10 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check reference */
|
||||
#define MARK_SEEN() \
|
||||
janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++))
|
||||
|
||||
/* Check reference and registry value */
|
||||
{
|
||||
Janet check = janet_table_get(&st->seen, x);
|
||||
if (janet_checktype(check, JANET_INTEGER)) {
|
||||
@ -266,10 +323,18 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
||||
pushint(st, janet_unwrap_integer(check));
|
||||
return;
|
||||
}
|
||||
if (st->rreg) {
|
||||
check = janet_table_get(st->rreg, x);
|
||||
if (janet_checktype(check, JANET_SYMBOL)) {
|
||||
MARK_SEEN();
|
||||
const uint8_t *regname = janet_unwrap_symbol(check);
|
||||
pushbyte(st, LB_REGISTRY);
|
||||
pushint(st, janet_string_length(regname));
|
||||
pushbytes(st, regname, janet_string_length(regname));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MARK_SEEN() \
|
||||
janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++))
|
||||
|
||||
/* Reference types */
|
||||
switch (type) {
|
||||
@ -373,17 +438,7 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
||||
return;
|
||||
case JANET_ABSTRACT:
|
||||
case JANET_CFUNCTION:
|
||||
{
|
||||
MARK_SEEN();
|
||||
Janet regval = janet_table_get(janet_vm_registry, x);
|
||||
if (!janet_checktype(regval, JANET_SYMBOL))
|
||||
goto noregval;
|
||||
const uint8_t *regname = janet_unwrap_symbol(regval);
|
||||
pushbyte(st, LB_REGISTRY);
|
||||
pushint(st, janet_string_length(regname));
|
||||
pushbytes(st, regname, janet_string_length(regname));
|
||||
}
|
||||
return;
|
||||
case JANET_FUNCTION:
|
||||
{
|
||||
pushbyte(st, LB_FUNCTION);
|
||||
@ -416,13 +471,14 @@ noregval:
|
||||
longjmp(st->err, MR_NRV);
|
||||
}
|
||||
|
||||
int janet_marshal(JanetBuffer *buf, Janet x, int flags) {
|
||||
int janet_marshal(JanetBuffer *buf, Janet x, JanetTable *rreg, int flags) {
|
||||
int status;
|
||||
MarshalState st;
|
||||
st.buf = buf;
|
||||
st.nextid = 0;
|
||||
st.seen_defs = NULL;
|
||||
st.seen_envs = NULL;
|
||||
st.rreg = rreg;
|
||||
janet_table_init(&st.seen, 0);
|
||||
if (!(status = setjmp(st.err)))
|
||||
marshal_one(&st, x, flags);
|
||||
@ -435,6 +491,7 @@ int janet_marshal(JanetBuffer *buf, Janet x, int flags) {
|
||||
typedef struct {
|
||||
jmp_buf err;
|
||||
JanetArray lookup;
|
||||
JanetTable *reg;
|
||||
JanetFuncEnv **lookup_envs;
|
||||
JanetFuncDef **lookup_defs;
|
||||
const uint8_t *end;
|
||||
@ -897,8 +954,12 @@ static const uint8_t *unmarshal_one(
|
||||
const uint8_t *str = janet_symbol(data, len);
|
||||
*out = janet_wrap_symbol(str);
|
||||
} else if (lead == LB_REGISTRY) {
|
||||
if (st->reg) {
|
||||
Janet regkey = janet_symbolv(data, len);
|
||||
*out = janet_table_get(janet_vm_registry, regkey);
|
||||
*out = janet_table_get(st->reg, regkey);
|
||||
} else {
|
||||
*out = janet_wrap_nil();
|
||||
}
|
||||
} else { /* (lead == LB_BUFFER) */
|
||||
JanetBuffer *buffer = janet_buffer(len);
|
||||
buffer->count = len;
|
||||
@ -1004,6 +1065,7 @@ int janet_unmarshal(
|
||||
size_t len,
|
||||
int flags,
|
||||
Janet *out,
|
||||
JanetTable *reg,
|
||||
const uint8_t **next) {
|
||||
int status;
|
||||
/* Avoid longjmp clobber warning in GCC */
|
||||
@ -1011,6 +1073,7 @@ int janet_unmarshal(
|
||||
st.end = bytes + len;
|
||||
st.lookup_defs = NULL;
|
||||
st.lookup_envs = NULL;
|
||||
st.reg = reg;
|
||||
janet_array_init(&st.lookup, 0);
|
||||
if (!(status = setjmp(st.err))) {
|
||||
const uint8_t *nextbytes = unmarshal_one(&st, bytes, out, flags);
|
||||
@ -1024,18 +1087,35 @@ int janet_unmarshal(
|
||||
|
||||
/* C functions */
|
||||
|
||||
static int cfun_env_lookups(JanetArgs args) {
|
||||
JanetTable *env;
|
||||
Janet tup[2];
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_ARG_TABLE(env, args, 0);
|
||||
tup[0] = janet_wrap_table(janet_env_rreg(env));
|
||||
tup[1] = janet_wrap_table(janet_env_reg(env));
|
||||
JANET_RETURN_TUPLE(args, janet_tuple_n(tup, 2));
|
||||
}
|
||||
|
||||
static int cfun_marshal(JanetArgs args) {
|
||||
JanetBuffer *buffer;
|
||||
JanetTable *rreg;
|
||||
int status;
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_MAXARITY(args, 2);
|
||||
if (args.n == 2) {
|
||||
JANET_MAXARITY(args, 3);
|
||||
if (args.n > 1) {
|
||||
/* Reverse Registry provided */
|
||||
JANET_ARG_TABLE(rreg, args, 1);
|
||||
} else {
|
||||
rreg = NULL;
|
||||
}
|
||||
if (args.n > 2) {
|
||||
/* Buffer provided */
|
||||
JANET_ARG_BUFFER(buffer, args, 1);
|
||||
JANET_ARG_BUFFER(buffer, args, 2);
|
||||
} else {
|
||||
buffer = janet_buffer(10);
|
||||
}
|
||||
status = janet_marshal(buffer, args.v[0], 0);
|
||||
status = janet_marshal(buffer, args.v[0], rreg, 0);
|
||||
if (status) {
|
||||
JANET_THROW(args, mr_strings[status]);
|
||||
}
|
||||
@ -1044,11 +1124,18 @@ static int cfun_marshal(JanetArgs args) {
|
||||
|
||||
static int cfun_unmarshal(JanetArgs args) {
|
||||
const uint8_t *bytes;
|
||||
JanetTable *reg;
|
||||
int32_t len;
|
||||
int status;
|
||||
JANET_FIXARITY(args, 1);
|
||||
JANET_MINARITY(args, 1);
|
||||
JANET_MAXARITY(args, 2);
|
||||
JANET_ARG_BYTES(bytes, len, args, 0);
|
||||
status = janet_unmarshal(bytes, (size_t) len, 0, args.ret, NULL);
|
||||
if (args.n > 1) {
|
||||
JANET_ARG_TABLE(reg, args, 1);
|
||||
} else {
|
||||
reg = NULL;
|
||||
}
|
||||
status = janet_unmarshal(bytes, (size_t) len, 0, args.ret, reg, NULL);
|
||||
if (status) {
|
||||
JANET_THROW(args, umr_strings[status]);
|
||||
}
|
||||
@ -1058,6 +1145,7 @@ static int cfun_unmarshal(JanetArgs args) {
|
||||
static const JanetReg cfuns[] = {
|
||||
{"marshal", cfun_marshal},
|
||||
{"unmarshal", cfun_unmarshal},
|
||||
{"env-lookups", cfun_env_lookups},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -194,7 +194,8 @@ const void *janet_strbinsearch(
|
||||
}
|
||||
|
||||
/* Register a value in the global registry */
|
||||
void janet_register(const char *name, Janet value) {
|
||||
void janet_register(const char *name, JanetCFunction cfun) {
|
||||
Janet value = janet_wrap_cfunction(cfun);
|
||||
Janet regkey = janet_csymbolv(name);
|
||||
janet_table_put(janet_vm_registry, regkey, value);
|
||||
janet_table_put(janet_vm_registry, value, regkey);
|
||||
|
@ -1025,13 +1025,20 @@ JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size);
|
||||
JANET_API JanetCFunction janet_native(const char *name, const uint8_t **error);
|
||||
|
||||
/* Marshaling */
|
||||
JANET_API int janet_marshal(JanetBuffer *buf, Janet x, int flags);
|
||||
JANET_API int janet_marshal(
|
||||
JanetBuffer *buf,
|
||||
Janet x,
|
||||
JanetTable *rreg,
|
||||
int flags);
|
||||
JANET_API int janet_unmarshal(
|
||||
const uint8_t *bytes,
|
||||
size_t len,
|
||||
int flags,
|
||||
Janet *out,
|
||||
JanetTable *reg,
|
||||
const uint8_t **next);
|
||||
JANET_API JanetTable *janet_env_rreg(JanetTable *env);
|
||||
JANET_API JanetTable *janet_env_reg(JanetTable *env);
|
||||
|
||||
/* GC */
|
||||
JANET_API void janet_mark(Janet x);
|
||||
@ -1075,7 +1082,7 @@ JANET_API void janet_var(JanetTable *env, const char *name, Janet val);
|
||||
JANET_API void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns);
|
||||
JANET_API JanetBindingType janet_resolve(JanetTable *env, const uint8_t *sym, Janet *out);
|
||||
JANET_API JanetTable *janet_env(JanetArgs args);
|
||||
JANET_API void janet_register(const char *name, Janet value);
|
||||
JANET_API void janet_register(const char *name, JanetCFunction cfun);
|
||||
|
||||
/* C Function helpers */
|
||||
JANET_API int janet_arity_err(JanetArgs args, int32_t n, const char *prefix);
|
||||
|
@ -42,7 +42,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
/* Expose line getter */
|
||||
janet_def(env, "getline", janet_wrap_cfunction(janet_line_getter));
|
||||
janet_register("getline", janet_wrap_cfunction(janet_line_getter));
|
||||
janet_register("getline", janet_line_getter);
|
||||
janet_line_init();
|
||||
|
||||
/* Run startup script */
|
||||
|
@ -74,11 +74,11 @@ void repl_init(void) {
|
||||
|
||||
/* Janet line getter */
|
||||
janet_def(env, "repl-yield", janet_wrap_cfunction(repl_yield));
|
||||
janet_register("repl-yield", janet_wrap_cfunction(repl_yield));
|
||||
janet_register("repl-yield", repl_yield);
|
||||
|
||||
/* Janet line getter */
|
||||
janet_def(env, "js", janet_wrap_cfunction(cfun_js));
|
||||
janet_register("js", janet_wrap_cfunction(cfun_js));
|
||||
janet_register("js", cfun_js);
|
||||
|
||||
/* Run startup script */
|
||||
Janet ret;
|
||||
|
@ -141,9 +141,11 @@
|
||||
|
||||
# Marshal
|
||||
|
||||
(def [m-lookup um-lookup] (env-lookups _env))
|
||||
|
||||
(defn testmarsh [x msg]
|
||||
(def marshx (marshal x))
|
||||
(def out (-> marshx unmarshal marshal))
|
||||
(def marshx (marshal x m-lookup))
|
||||
(def out (marshal (unmarshal marshx um-lookup) m-lookup))
|
||||
(assert (= (string marshx) (string out)) msg))
|
||||
|
||||
(testmarsh nil "marshal nil")
|
||||
|
Loading…
Reference in New Issue
Block a user