mirror of
https://github.com/janet-lang/janet
synced 2024-12-26 08:20:27 +00:00
Merge branch 'struct-proto'
This commit is contained in:
commit
899a9b025e
@ -3689,15 +3689,6 @@
|
|||||||
|
|
||||||
(do
|
(do
|
||||||
|
|
||||||
(defn proto-flatten
|
|
||||||
"Flatten a table and its prototypes into a single table."
|
|
||||||
[into x]
|
|
||||||
(when x
|
|
||||||
(proto-flatten into (table/getproto x))
|
|
||||||
(loop [k :keys x]
|
|
||||||
(put into k (x k))))
|
|
||||||
into)
|
|
||||||
|
|
||||||
# Deprecate file/popen
|
# Deprecate file/popen
|
||||||
(when-let [v (get root-env 'file/popen)]
|
(when-let [v (get root-env 'file/popen)]
|
||||||
(put v :deprecated true))
|
(put v :deprecated true))
|
||||||
@ -3706,7 +3697,7 @@
|
|||||||
# flatten nested tables.
|
# flatten nested tables.
|
||||||
(loop [[k v] :in (pairs root-env)
|
(loop [[k v] :in (pairs root-env)
|
||||||
:when (symbol? k)]
|
:when (symbol? k)]
|
||||||
(def flat (proto-flatten @{} v))
|
(def flat (table/proto-flatten v))
|
||||||
(when (boot/config :no-docstrings)
|
(when (boot/config :no-docstrings)
|
||||||
(put flat :doc nil))
|
(put flat :doc nil))
|
||||||
(when (boot/config :no-sourcemaps)
|
(when (boot/config :no-sourcemaps)
|
||||||
|
@ -465,6 +465,25 @@ JANET_CORE_FN(janet_core_table,
|
|||||||
return janet_wrap_table(table);
|
return janet_wrap_table(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(janet_core_getproto,
|
||||||
|
"(getproto x)",
|
||||||
|
"Get the prototype of a table or struct. Will return nil if `x` has no prototype.") {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
if (janet_checktype(argv[0], JANET_TABLE)) {
|
||||||
|
JanetTable *t = janet_unwrap_table(argv[0]);
|
||||||
|
return t->proto
|
||||||
|
? janet_wrap_table(t->proto)
|
||||||
|
: janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_checktype(argv[0], JANET_STRUCT)) {
|
||||||
|
JanetStruct st = janet_unwrap_struct(argv[0]);
|
||||||
|
return janet_struct_proto(st)
|
||||||
|
? janet_wrap_struct(janet_struct_proto(st))
|
||||||
|
: janet_wrap_nil();
|
||||||
|
}
|
||||||
|
janet_panicf("expected struct|table, got %v", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
JANET_CORE_FN(janet_core_struct,
|
JANET_CORE_FN(janet_core_struct,
|
||||||
"(struct & kvs)",
|
"(struct & kvs)",
|
||||||
"Create a new struct from a sequence of key value pairs. "
|
"Create a new struct from a sequence of key value pairs. "
|
||||||
@ -472,8 +491,9 @@ JANET_CORE_FN(janet_core_struct,
|
|||||||
"an odd number of elements, an error will be thrown. Returns the "
|
"an odd number of elements, an error will be thrown. Returns the "
|
||||||
"new struct.") {
|
"new struct.") {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
if (argc & 1)
|
if (argc & 1) {
|
||||||
janet_panic("expected even number of arguments");
|
janet_panic("expected even number of arguments");
|
||||||
|
}
|
||||||
JanetKV *st = janet_struct_begin(argc >> 1);
|
JanetKV *st = janet_struct_begin(argc >> 1);
|
||||||
for (i = 0; i < argc; i += 2) {
|
for (i = 0; i < argc; i += 2) {
|
||||||
janet_struct_put(st, argv[i], argv[i + 1]);
|
janet_struct_put(st, argv[i], argv[i + 1]);
|
||||||
@ -960,6 +980,7 @@ static void janet_load_libs(JanetTable *env) {
|
|||||||
JANET_CORE_REG("nat?", janet_core_check_nat),
|
JANET_CORE_REG("nat?", janet_core_check_nat),
|
||||||
JANET_CORE_REG("slice", janet_core_slice),
|
JANET_CORE_REG("slice", janet_core_slice),
|
||||||
JANET_CORE_REG("signal", janet_core_signal),
|
JANET_CORE_REG("signal", janet_core_signal),
|
||||||
|
JANET_CORE_REG("getproto", janet_core_getproto),
|
||||||
JANET_REG_END
|
JANET_REG_END
|
||||||
};
|
};
|
||||||
janet_core_cfuns_ext(env, NULL, corelib_cfuns);
|
janet_core_cfuns_ext(env, NULL, corelib_cfuns);
|
||||||
@ -969,6 +990,7 @@ static void janet_load_libs(JanetTable *env) {
|
|||||||
janet_lib_tuple(env);
|
janet_lib_tuple(env);
|
||||||
janet_lib_buffer(env);
|
janet_lib_buffer(env);
|
||||||
janet_lib_table(env);
|
janet_lib_table(env);
|
||||||
|
janet_lib_struct(env);
|
||||||
janet_lib_fiber(env);
|
janet_lib_fiber(env);
|
||||||
janet_lib_os(env);
|
janet_lib_os(env);
|
||||||
janet_lib_parse(env);
|
janet_lib_parse(env);
|
||||||
|
@ -162,10 +162,13 @@ recur: /* Manual tail recursion */
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void janet_mark_struct(const JanetKV *st) {
|
static void janet_mark_struct(const JanetKV *st) {
|
||||||
|
recur:
|
||||||
if (janet_gc_reachable(janet_struct_head(st)))
|
if (janet_gc_reachable(janet_struct_head(st)))
|
||||||
return;
|
return;
|
||||||
janet_gc_mark(janet_struct_head(st));
|
janet_gc_mark(janet_struct_head(st));
|
||||||
janet_mark_kvs(st, janet_struct_capacity(st));
|
janet_mark_kvs(st, janet_struct_capacity(st));
|
||||||
|
st = janet_struct_proto(st);
|
||||||
|
if (st) goto recur;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void janet_mark_tuple(const Janet *tuple) {
|
static void janet_mark_tuple(const Janet *tuple) {
|
||||||
|
@ -64,8 +64,9 @@ enum {
|
|||||||
LB_FUNCDEF_REF, /* 220 */
|
LB_FUNCDEF_REF, /* 220 */
|
||||||
LB_UNSAFE_CFUNCTION, /* 221 */
|
LB_UNSAFE_CFUNCTION, /* 221 */
|
||||||
LB_UNSAFE_POINTER, /* 222 */
|
LB_UNSAFE_POINTER, /* 222 */
|
||||||
|
LB_STRUCT_PROTO, /* 223 */
|
||||||
#ifdef JANET_EV
|
#ifdef JANET_EV
|
||||||
LB_THREADED_ABSTRACT/* 223 */
|
LB_THREADED_ABSTRACT/* 224 */
|
||||||
#endif
|
#endif
|
||||||
} LeadBytes;
|
} LeadBytes;
|
||||||
|
|
||||||
@ -542,8 +543,10 @@ static void marshal_one(MarshalState *st, Janet x, int flags) {
|
|||||||
int32_t count;
|
int32_t count;
|
||||||
const JanetKV *struct_ = janet_unwrap_struct(x);
|
const JanetKV *struct_ = janet_unwrap_struct(x);
|
||||||
count = janet_struct_length(struct_);
|
count = janet_struct_length(struct_);
|
||||||
pushbyte(st, LB_STRUCT);
|
pushbyte(st, janet_struct_proto(struct_) ? LB_STRUCT_PROTO : LB_STRUCT);
|
||||||
pushint(st, count);
|
pushint(st, count);
|
||||||
|
if (janet_struct_proto(struct_))
|
||||||
|
marshal_one(st, janet_wrap_struct(janet_struct_proto(struct_)), flags + 1);
|
||||||
for (int32_t i = 0; i < janet_struct_capacity(struct_); i++) {
|
for (int32_t i = 0; i < janet_struct_capacity(struct_); i++) {
|
||||||
if (janet_checktype(struct_[i].key, JANET_NIL))
|
if (janet_checktype(struct_[i].key, JANET_NIL))
|
||||||
continue;
|
continue;
|
||||||
@ -1281,6 +1284,7 @@ static const uint8_t *unmarshal_one(
|
|||||||
case LB_ARRAY:
|
case LB_ARRAY:
|
||||||
case LB_TUPLE:
|
case LB_TUPLE:
|
||||||
case LB_STRUCT:
|
case LB_STRUCT:
|
||||||
|
case LB_STRUCT_PROTO:
|
||||||
case LB_TABLE:
|
case LB_TABLE:
|
||||||
case LB_TABLE_PROTO:
|
case LB_TABLE_PROTO:
|
||||||
/* Things that open with integers */
|
/* Things that open with integers */
|
||||||
@ -1310,9 +1314,15 @@ static const uint8_t *unmarshal_one(
|
|||||||
}
|
}
|
||||||
*out = janet_wrap_tuple(janet_tuple_end(tup));
|
*out = janet_wrap_tuple(janet_tuple_end(tup));
|
||||||
janet_v_push(st->lookup, *out);
|
janet_v_push(st->lookup, *out);
|
||||||
} else if (lead == LB_STRUCT) {
|
} else if (lead == LB_STRUCT || lead == LB_STRUCT_PROTO) {
|
||||||
/* Struct */
|
/* Struct */
|
||||||
JanetKV *struct_ = janet_struct_begin(len);
|
JanetKV *struct_ = janet_struct_begin(len);
|
||||||
|
if (lead == LB_STRUCT_PROTO) {
|
||||||
|
Janet proto;
|
||||||
|
data = unmarshal_one(st, data, &proto, flags + 1);
|
||||||
|
janet_asserttype(proto, JANET_STRUCT);
|
||||||
|
janet_struct_proto(struct_) = janet_unwrap_struct(proto);
|
||||||
|
}
|
||||||
for (int32_t i = 0; i < len; i++) {
|
for (int32_t i = 0; i < len; i++) {
|
||||||
Janet key, value;
|
Janet key, value;
|
||||||
data = unmarshal_one(st, data, &key, flags + 1);
|
data = unmarshal_one(st, data, &key, flags + 1);
|
||||||
|
@ -562,12 +562,12 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
|||||||
case JANET_STRUCT:
|
case JANET_STRUCT:
|
||||||
case JANET_TABLE: {
|
case JANET_TABLE: {
|
||||||
int istable = janet_checktype(x, JANET_TABLE);
|
int istable = janet_checktype(x, JANET_TABLE);
|
||||||
janet_buffer_push_cstring(S->buffer, istable ? "@" : "{");
|
|
||||||
|
|
||||||
/* For object-like tables, print class name */
|
/* For object-like tables, print class name */
|
||||||
if (istable) {
|
if (istable) {
|
||||||
JanetTable *t = janet_unwrap_table(x);
|
JanetTable *t = janet_unwrap_table(x);
|
||||||
JanetTable *proto = t->proto;
|
JanetTable *proto = t->proto;
|
||||||
|
janet_buffer_push_cstring(S->buffer, "@");
|
||||||
if (NULL != proto) {
|
if (NULL != proto) {
|
||||||
Janet name = janet_table_get(proto, janet_ckeywordv("_name"));
|
Janet name = janet_table_get(proto, janet_ckeywordv("_name"));
|
||||||
const uint8_t *n;
|
const uint8_t *n;
|
||||||
@ -582,8 +582,25 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
janet_buffer_push_cstring(S->buffer, "{");
|
} else {
|
||||||
|
JanetStruct st = janet_unwrap_struct(x);
|
||||||
|
JanetStruct proto = janet_struct_proto(st);
|
||||||
|
if (NULL != proto) {
|
||||||
|
Janet name = janet_struct_get(proto, janet_ckeywordv("_name"));
|
||||||
|
const uint8_t *n;
|
||||||
|
int32_t len;
|
||||||
|
if (janet_bytes_view(name, &n, &len)) {
|
||||||
|
if (S->flags & JANET_PRETTY_COLOR) {
|
||||||
|
janet_buffer_push_cstring(S->buffer, janet_class_color);
|
||||||
|
}
|
||||||
|
janet_buffer_push_bytes(S->buffer, n, len);
|
||||||
|
if (S->flags & JANET_PRETTY_COLOR) {
|
||||||
|
janet_buffer_push_cstring(S->buffer, "\x1B[0m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
janet_buffer_push_cstring(S->buffer, "{");
|
||||||
|
|
||||||
S->depth--;
|
S->depth--;
|
||||||
S->indent += 2;
|
S->indent += 2;
|
||||||
|
@ -39,13 +39,14 @@ JanetKV *janet_struct_begin(int32_t count) {
|
|||||||
head->length = count;
|
head->length = count;
|
||||||
head->capacity = capacity;
|
head->capacity = capacity;
|
||||||
head->hash = 0;
|
head->hash = 0;
|
||||||
|
head->proto = NULL;
|
||||||
|
|
||||||
JanetKV *st = (JanetKV *)(head->data);
|
JanetKV *st = (JanetKV *)(head->data);
|
||||||
janet_memempty(st, capacity);
|
janet_memempty(st, capacity);
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find an item in a struct. Should be similar to janet_dict_find, but
|
/* Find an item in a struct without looking for prototypes. Should be similar to janet_dict_find, but
|
||||||
* specialized to structs (slightly more compact). */
|
* specialized to structs (slightly more compact). */
|
||||||
const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
|
const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
|
||||||
int32_t cap = janet_struct_capacity(st);
|
int32_t cap = janet_struct_capacity(st);
|
||||||
@ -68,7 +69,7 @@ const JanetKV *janet_struct_find(const JanetKV *st, Janet key) {
|
|||||||
* preforms an in-place insertion sort. This ensures the internal structure of the
|
* preforms an in-place insertion sort. This ensures the internal structure of the
|
||||||
* hash map is independent of insertion order.
|
* hash map is independent of insertion order.
|
||||||
*/
|
*/
|
||||||
void janet_struct_put(JanetKV *st, Janet key, Janet value) {
|
void janet_struct_put_ext(JanetKV *st, Janet key, Janet value, int replace) {
|
||||||
int32_t cap = janet_struct_capacity(st);
|
int32_t cap = janet_struct_capacity(st);
|
||||||
int32_t hash = janet_hash(key);
|
int32_t hash = janet_hash(key);
|
||||||
int32_t index = janet_maphash(cap, hash);
|
int32_t index = janet_maphash(cap, hash);
|
||||||
@ -123,13 +124,19 @@ void janet_struct_put(JanetKV *st, Janet key, Janet value) {
|
|||||||
dist = otherdist;
|
dist = otherdist;
|
||||||
hash = otherhash;
|
hash = otherhash;
|
||||||
} else if (status == 0) {
|
} else if (status == 0) {
|
||||||
/* A key was added to the struct more than once - replace old value */
|
if (replace) {
|
||||||
kv->value = value;
|
/* A key was added to the struct more than once - replace old value */
|
||||||
|
kv->value = value;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void janet_struct_put(JanetKV *st, Janet key, Janet value) {
|
||||||
|
janet_struct_put_ext(st, key, value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Finish building a struct */
|
/* Finish building a struct */
|
||||||
const JanetKV *janet_struct_end(JanetKV *st) {
|
const JanetKV *janet_struct_end(JanetKV *st) {
|
||||||
if (janet_struct_hash(st) != janet_struct_length(st)) {
|
if (janet_struct_hash(st) != janet_struct_length(st)) {
|
||||||
@ -146,13 +153,39 @@ const JanetKV *janet_struct_end(JanetKV *st) {
|
|||||||
st = newst;
|
st = newst;
|
||||||
}
|
}
|
||||||
janet_struct_hash(st) = janet_kv_calchash(st, janet_struct_capacity(st));
|
janet_struct_hash(st) = janet_kv_calchash(st, janet_struct_capacity(st));
|
||||||
|
if (janet_struct_proto(st)) {
|
||||||
|
janet_struct_hash(st) += 2654435761u * janet_struct_hash(janet_struct_proto(st));
|
||||||
|
}
|
||||||
return (const JanetKV *)st;
|
return (const JanetKV *)st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get an item from a struct without looking into prototypes. */
|
||||||
|
Janet janet_struct_rawget(const JanetKV *st, Janet key) {
|
||||||
|
const JanetKV *kv = janet_struct_find(st, key);
|
||||||
|
return kv ? kv->value : janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
/* Get an item from a struct */
|
/* Get an item from a struct */
|
||||||
Janet janet_struct_get(const JanetKV *st, Janet key) {
|
Janet janet_struct_get(const JanetKV *st, Janet key) {
|
||||||
const JanetKV *kv = janet_struct_find(st, key);
|
for (int i = JANET_MAX_PROTO_DEPTH; st && i; --i, st = janet_struct_proto(st)) {
|
||||||
return kv ? kv->value : janet_wrap_nil();
|
const JanetKV *kv = janet_struct_find(st, key);
|
||||||
|
if (NULL != kv && !janet_checktype(kv->key, JANET_NIL)) {
|
||||||
|
return kv->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get an item from a struct, and record which prototype the item came from. */
|
||||||
|
Janet janet_struct_get_ex(const JanetKV *st, Janet key, JanetStruct *which) {
|
||||||
|
for (int i = JANET_MAX_PROTO_DEPTH; st && i; --i, st = janet_struct_proto(st)) {
|
||||||
|
const JanetKV *kv = janet_struct_find(st, key);
|
||||||
|
if (NULL != kv && !janet_checktype(kv->key, JANET_NIL)) {
|
||||||
|
*which = st;
|
||||||
|
return kv->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert struct to table */
|
/* Convert struct to table */
|
||||||
@ -167,3 +200,107 @@ JanetTable *janet_struct_to_table(const JanetKV *st) {
|
|||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* C Functions */
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_struct_with_proto,
|
||||||
|
"(struct/with-proto proto & kvs)",
|
||||||
|
"Create a structure, as with the usual struct constructor but set the "
|
||||||
|
"struct prototype as well.") {
|
||||||
|
janet_arity(argc, 1, -1);
|
||||||
|
JanetStruct proto = janet_optstruct(argv, argc, 0, NULL);
|
||||||
|
if (!(argc & 1))
|
||||||
|
janet_panic("expected odd number of arguments");
|
||||||
|
JanetKV *st = janet_struct_begin(argc / 2);
|
||||||
|
for (int32_t i = 1; i < argc; i += 2) {
|
||||||
|
janet_struct_put(st, argv[i], argv[i + 1]);
|
||||||
|
}
|
||||||
|
janet_struct_proto(st) = proto;
|
||||||
|
return janet_wrap_struct(janet_struct_end(st));
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_struct_getproto,
|
||||||
|
"(struct/getproto st)",
|
||||||
|
"Return the prototype of a struct, or nil if it doesn't have one.") {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
JanetStruct st = janet_getstruct(argv, 0);
|
||||||
|
return janet_struct_proto(st)
|
||||||
|
? janet_wrap_struct(janet_struct_proto(st))
|
||||||
|
: janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_struct_flatten,
|
||||||
|
"(struct/proto-flatten st)",
|
||||||
|
"Convert a struct with prototypes to a struct with no prototypes by merging "
|
||||||
|
"all key value pairs from recursive prototypes into one new struct.") {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
JanetStruct st = janet_getstruct(argv, 0);
|
||||||
|
|
||||||
|
/* get an upper bounds on the number of items in the final struct */
|
||||||
|
int64_t pair_count = 0;
|
||||||
|
JanetStruct cursor = st;
|
||||||
|
while (cursor) {
|
||||||
|
pair_count += janet_struct_length(cursor);
|
||||||
|
cursor = janet_struct_proto(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair_count > INT32_MAX) {
|
||||||
|
janet_panic("struct too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
JanetKV *accum = janet_struct_begin((int32_t) pair_count);
|
||||||
|
cursor = st;
|
||||||
|
while (cursor) {
|
||||||
|
for (int32_t i = 0; i < janet_struct_capacity(cursor); i++) {
|
||||||
|
const JanetKV *kv = cursor + i;
|
||||||
|
if (!janet_checktype(kv->key, JANET_NIL)) {
|
||||||
|
janet_struct_put_ext(accum, kv->key, kv->value, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor = janet_struct_proto(cursor);
|
||||||
|
}
|
||||||
|
return janet_wrap_struct(janet_struct_end(accum));
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_struct_to_table,
|
||||||
|
"(struct/to-table st &opt recursive)",
|
||||||
|
"Convert a struct to a table. If recursive is true, also convert the "
|
||||||
|
"table's prototypes into the new struct's prototypes as well.") {
|
||||||
|
janet_arity(argc, 1, 2);
|
||||||
|
JanetStruct st = janet_getstruct(argv, 0);
|
||||||
|
int recursive = argc > 1 && janet_truthy(argv[1]);
|
||||||
|
JanetTable *tab = NULL;
|
||||||
|
JanetStruct cursor = st;
|
||||||
|
JanetTable *tab_cursor = tab;
|
||||||
|
do {
|
||||||
|
if (tab) {
|
||||||
|
tab_cursor->proto = janet_table(janet_struct_length(cursor));
|
||||||
|
tab_cursor = tab_cursor->proto;
|
||||||
|
} else {
|
||||||
|
tab = janet_table(janet_struct_length(cursor));
|
||||||
|
tab_cursor = tab;
|
||||||
|
}
|
||||||
|
/* TODO - implement as memcpy since struct memory should be compatible
|
||||||
|
* with table memory */
|
||||||
|
for (int32_t i = 0; i < janet_struct_capacity(cursor); i++) {
|
||||||
|
const JanetKV *kv = cursor + i;
|
||||||
|
if (!janet_checktype(kv->key, JANET_NIL)) {
|
||||||
|
janet_table_put(tab_cursor, kv->key, kv->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor = janet_struct_proto(cursor);
|
||||||
|
} while (recursive && cursor);
|
||||||
|
return janet_wrap_table(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the struct module */
|
||||||
|
void janet_lib_struct(JanetTable *env) {
|
||||||
|
JanetRegExt struct_cfuns[] = {
|
||||||
|
JANET_CORE_REG("struct/with-proto", cfun_struct_with_proto),
|
||||||
|
JANET_CORE_REG("struct/getproto", cfun_struct_getproto),
|
||||||
|
JANET_CORE_REG("struct/proto-flatten", cfun_struct_flatten),
|
||||||
|
JANET_CORE_REG("struct/to-table", cfun_struct_to_table),
|
||||||
|
JANET_REG_END
|
||||||
|
};
|
||||||
|
janet_core_cfuns_ext(env, NULL, struct_cfuns);
|
||||||
|
}
|
||||||
|
101
src/core/table.c
101
src/core/table.c
@ -132,37 +132,21 @@ static void janet_table_rehash(JanetTable *t, int32_t size) {
|
|||||||
|
|
||||||
/* Get a value out of the table */
|
/* Get a value out of the table */
|
||||||
Janet janet_table_get(JanetTable *t, Janet key) {
|
Janet janet_table_get(JanetTable *t, Janet key) {
|
||||||
JanetKV *bucket = janet_table_find(t, key);
|
for (int i = JANET_MAX_PROTO_DEPTH; t && i; t = t->proto, --i) {
|
||||||
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL))
|
JanetKV *bucket = janet_table_find(t, key);
|
||||||
return bucket->value;
|
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL))
|
||||||
/* Check prototypes */
|
return bucket->value;
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = JANET_MAX_PROTO_DEPTH, t = t->proto; t && i; t = t->proto, --i) {
|
|
||||||
bucket = janet_table_find(t, key);
|
|
||||||
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL))
|
|
||||||
return bucket->value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a value out of the table, and record which prototype it was from. */
|
/* Get a value out of the table, and record which prototype it was from. */
|
||||||
Janet janet_table_get_ex(JanetTable *t, Janet key, JanetTable **which) {
|
Janet janet_table_get_ex(JanetTable *t, Janet key, JanetTable **which) {
|
||||||
JanetKV *bucket = janet_table_find(t, key);
|
for (int i = JANET_MAX_PROTO_DEPTH; t && i; t = t->proto, --i) {
|
||||||
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL)) {
|
JanetKV *bucket = janet_table_find(t, key);
|
||||||
*which = t;
|
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL)) {
|
||||||
return bucket->value;
|
*which = t;
|
||||||
}
|
return bucket->value;
|
||||||
/* Check prototypes */
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = JANET_MAX_PROTO_DEPTH, t = t->proto; t && i; t = t->proto, --i) {
|
|
||||||
bucket = janet_table_find(t, key);
|
|
||||||
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL)) {
|
|
||||||
*which = t;
|
|
||||||
return bucket->value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
@ -217,6 +201,23 @@ void janet_table_put(JanetTable *t, Janet key, Janet value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Used internally so don't check arguments
|
||||||
|
* Put into a table, but if the key already exists do nothing. */
|
||||||
|
static void janet_table_put_no_overwrite(JanetTable *t, Janet key, Janet value) {
|
||||||
|
JanetKV *bucket = janet_table_find(t, key);
|
||||||
|
if (NULL != bucket && !janet_checktype(bucket->key, JANET_NIL))
|
||||||
|
return;
|
||||||
|
if (NULL == bucket || 2 * (t->count + t->deleted + 1) > t->capacity) {
|
||||||
|
janet_table_rehash(t, janet_tablen(2 * t->count + 2));
|
||||||
|
}
|
||||||
|
bucket = janet_table_find(t, key);
|
||||||
|
if (janet_checktype(bucket->value, JANET_BOOLEAN))
|
||||||
|
--t->deleted;
|
||||||
|
bucket->key = key;
|
||||||
|
bucket->value = value;
|
||||||
|
++t->count;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear a table */
|
/* Clear a table */
|
||||||
void janet_table_clear(JanetTable *t) {
|
void janet_table_clear(JanetTable *t) {
|
||||||
int32_t capacity = t->capacity;
|
int32_t capacity = t->capacity;
|
||||||
@ -226,19 +227,6 @@ void janet_table_clear(JanetTable *t) {
|
|||||||
t->deleted = 0;
|
t->deleted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert table to struct */
|
|
||||||
const JanetKV *janet_table_to_struct(JanetTable *t) {
|
|
||||||
JanetKV *st = janet_struct_begin(t->count);
|
|
||||||
JanetKV *kv = t->data;
|
|
||||||
JanetKV *end = t->data + t->capacity;
|
|
||||||
while (kv < end) {
|
|
||||||
if (!janet_checktype(kv->key, JANET_NIL))
|
|
||||||
janet_struct_put(st, kv->key, kv->value);
|
|
||||||
kv++;
|
|
||||||
}
|
|
||||||
return janet_struct_end(st);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clone a table. */
|
/* Clone a table. */
|
||||||
JanetTable *janet_table_clone(JanetTable *table) {
|
JanetTable *janet_table_clone(JanetTable *table) {
|
||||||
JanetTable *newTable = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable));
|
JanetTable *newTable = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable));
|
||||||
@ -275,6 +263,34 @@ void janet_table_merge_struct(JanetTable *table, const JanetKV *other) {
|
|||||||
janet_table_mergekv(table, other, janet_struct_capacity(other));
|
janet_table_mergekv(table, other, janet_struct_capacity(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert table to struct */
|
||||||
|
const JanetKV *janet_table_to_struct(JanetTable *t) {
|
||||||
|
JanetKV *st = janet_struct_begin(t->count);
|
||||||
|
JanetKV *kv = t->data;
|
||||||
|
JanetKV *end = t->data + t->capacity;
|
||||||
|
while (kv < end) {
|
||||||
|
if (!janet_checktype(kv->key, JANET_NIL))
|
||||||
|
janet_struct_put(st, kv->key, kv->value);
|
||||||
|
kv++;
|
||||||
|
}
|
||||||
|
return janet_struct_end(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
JanetTable *janet_table_proto_flatten(JanetTable *t) {
|
||||||
|
JanetTable *newTable = janet_table(0);
|
||||||
|
while (t) {
|
||||||
|
JanetKV *kv = t->data;
|
||||||
|
JanetKV *end = t->data + t->capacity;
|
||||||
|
while (kv < end) {
|
||||||
|
if (!janet_checktype(kv->key, JANET_NIL))
|
||||||
|
janet_table_put_no_overwrite(newTable, kv->key, kv->value);
|
||||||
|
kv++;
|
||||||
|
}
|
||||||
|
t = t->proto;
|
||||||
|
}
|
||||||
|
return newTable;
|
||||||
|
}
|
||||||
|
|
||||||
/* C Functions */
|
/* C Functions */
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_table_new,
|
JANET_CORE_FN(cfun_table_new,
|
||||||
@ -349,6 +365,14 @@ JANET_CORE_FN(cfun_table_clear,
|
|||||||
return janet_wrap_table(table);
|
return janet_wrap_table(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_table_proto_flatten,
|
||||||
|
"(table/proto-flatten tab)",
|
||||||
|
"Create a new table that is the result of merging all prototypes into a new table.") {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
JanetTable *table = janet_gettable(argv, 0);
|
||||||
|
return janet_wrap_table(janet_table_proto_flatten(table));
|
||||||
|
}
|
||||||
|
|
||||||
/* Load the table module */
|
/* Load the table module */
|
||||||
void janet_lib_table(JanetTable *env) {
|
void janet_lib_table(JanetTable *env) {
|
||||||
JanetRegExt table_cfuns[] = {
|
JanetRegExt table_cfuns[] = {
|
||||||
@ -359,6 +383,7 @@ void janet_lib_table(JanetTable *env) {
|
|||||||
JANET_CORE_REG("table/rawget", cfun_table_rawget),
|
JANET_CORE_REG("table/rawget", cfun_table_rawget),
|
||||||
JANET_CORE_REG("table/clone", cfun_table_clone),
|
JANET_CORE_REG("table/clone", cfun_table_clone),
|
||||||
JANET_CORE_REG("table/clear", cfun_table_clear),
|
JANET_CORE_REG("table/clear", cfun_table_clear),
|
||||||
|
JANET_CORE_REG("table/proto-flatten", cfun_table_proto_flatten),
|
||||||
JANET_REG_END
|
JANET_REG_END
|
||||||
};
|
};
|
||||||
janet_core_cfuns_ext(env, NULL, table_cfuns);
|
janet_core_cfuns_ext(env, NULL, table_cfuns);
|
||||||
|
@ -128,6 +128,7 @@ void janet_lib_array(JanetTable *env);
|
|||||||
void janet_lib_tuple(JanetTable *env);
|
void janet_lib_tuple(JanetTable *env);
|
||||||
void janet_lib_buffer(JanetTable *env);
|
void janet_lib_buffer(JanetTable *env);
|
||||||
void janet_lib_table(JanetTable *env);
|
void janet_lib_table(JanetTable *env);
|
||||||
|
void janet_lib_struct(JanetTable *env);
|
||||||
void janet_lib_fiber(JanetTable *env);
|
void janet_lib_fiber(JanetTable *env);
|
||||||
void janet_lib_os(JanetTable *env);
|
void janet_lib_os(JanetTable *env);
|
||||||
void janet_lib_string(JanetTable *env);
|
void janet_lib_string(JanetTable *env);
|
||||||
|
@ -101,6 +101,17 @@ static int traversal_next(Janet *x, Janet *y) {
|
|||||||
janet_vm.traversal = t;
|
janet_vm.traversal = t;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Traverse prototype */
|
||||||
|
JanetStruct sproto = sself->proto;
|
||||||
|
JanetStruct oproto = sother->proto;
|
||||||
|
if (sproto && !oproto) return 3;
|
||||||
|
if (!sproto && oproto) return 1;
|
||||||
|
if (oproto && sproto) {
|
||||||
|
*x = janet_wrap_struct(sproto);
|
||||||
|
*y = janet_wrap_struct(oproto);
|
||||||
|
janet_vm.traversal = t - 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t--;
|
t--;
|
||||||
}
|
}
|
||||||
@ -273,6 +284,8 @@ int janet_equals(Janet x, Janet y) {
|
|||||||
if (s1 == s2) break;
|
if (s1 == s2) break;
|
||||||
if (janet_struct_hash(s1) != janet_struct_hash(s2)) return 0;
|
if (janet_struct_hash(s1) != janet_struct_hash(s2)) return 0;
|
||||||
if (janet_struct_length(s1) != janet_struct_length(s2)) return 0;
|
if (janet_struct_length(s1) != janet_struct_length(s2)) return 0;
|
||||||
|
if (janet_struct_proto(s1) && !janet_struct_proto(s2)) return 0;
|
||||||
|
if (!janet_struct_proto(s1) && janet_struct_proto(s2)) return 0;
|
||||||
push_traversal_node(janet_struct_head(s1), janet_struct_head(s2), 0);
|
push_traversal_node(janet_struct_head(s1), janet_struct_head(s2), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -961,6 +961,7 @@ struct JanetStructHead {
|
|||||||
int32_t length;
|
int32_t length;
|
||||||
int32_t hash;
|
int32_t hash;
|
||||||
int32_t capacity;
|
int32_t capacity;
|
||||||
|
const JanetKV *proto;
|
||||||
const JanetKV data[];
|
const JanetKV data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1620,10 +1621,13 @@ JANET_API JanetSymbol janet_symbol_gen(void);
|
|||||||
#define janet_struct_length(t) (janet_struct_head(t)->length)
|
#define janet_struct_length(t) (janet_struct_head(t)->length)
|
||||||
#define janet_struct_capacity(t) (janet_struct_head(t)->capacity)
|
#define janet_struct_capacity(t) (janet_struct_head(t)->capacity)
|
||||||
#define janet_struct_hash(t) (janet_struct_head(t)->hash)
|
#define janet_struct_hash(t) (janet_struct_head(t)->hash)
|
||||||
|
#define janet_struct_proto(t) (janet_struct_head(t)->proto)
|
||||||
JANET_API JanetKV *janet_struct_begin(int32_t count);
|
JANET_API JanetKV *janet_struct_begin(int32_t count);
|
||||||
JANET_API void janet_struct_put(JanetKV *st, Janet key, Janet value);
|
JANET_API void janet_struct_put(JanetKV *st, Janet key, Janet value);
|
||||||
JANET_API JanetStruct janet_struct_end(JanetKV *st);
|
JANET_API JanetStruct janet_struct_end(JanetKV *st);
|
||||||
JANET_API Janet janet_struct_get(JanetStruct st, Janet key);
|
JANET_API Janet janet_struct_get(JanetStruct st, Janet key);
|
||||||
|
JANET_API Janet janet_struct_rawget(JanetStruct st, Janet key);
|
||||||
|
JANET_API Janet janet_struct_get_ex(JanetStruct st, Janet key, JanetStruct *which);
|
||||||
JANET_API JanetTable *janet_struct_to_table(JanetStruct st);
|
JANET_API JanetTable *janet_struct_to_table(JanetStruct st);
|
||||||
JANET_API const JanetKV *janet_struct_find(JanetStruct st, Janet key);
|
JANET_API const JanetKV *janet_struct_find(JanetStruct st, Janet key);
|
||||||
|
|
||||||
|
@ -161,6 +161,28 @@
|
|||||||
([err] :caught))))
|
([err] :caught))))
|
||||||
"regression #638"))
|
"regression #638"))
|
||||||
|
|
||||||
|
|
||||||
|
# Struct prototypes
|
||||||
|
(def x (struct/with-proto {1 2 3 4} 5 6))
|
||||||
|
(def y (-> x marshal unmarshal))
|
||||||
|
(def z {1 2 3 4})
|
||||||
|
(assert (= 2 (get x 1)) "struct get proto value 1")
|
||||||
|
(assert (= 4 (get x 3)) "struct get proto value 2")
|
||||||
|
(assert (= 6 (get x 5)) "struct get proto value 3")
|
||||||
|
(assert (= x y) "struct proto marshal equality 1")
|
||||||
|
(assert (= (getproto x) (getproto y)) "struct proto marshal equality 2")
|
||||||
|
(assert (= 0 (cmp x y)) "struct proto comparison 1")
|
||||||
|
(assert (= 0 (cmp (getproto x) (getproto y))) "struct proto comparison 2")
|
||||||
|
(assert (not= (cmp x z) 0) "struct proto comparison 3")
|
||||||
|
(assert (not= (cmp y z) 0) "struct proto comparison 4")
|
||||||
|
(assert (not= x z) "struct proto comparison 5")
|
||||||
|
(assert (not= y z) "struct proto comparison 6")
|
||||||
|
(assert (= (x 5) 6) "struct proto get 1")
|
||||||
|
(assert (= (y 5) 6) "struct proto get 1")
|
||||||
|
(assert (deep= x y) "struct proto deep= 1")
|
||||||
|
(assert (deep-not= x z) "struct proto deep= 2")
|
||||||
|
(assert (deep-not= y z) "struct proto deep= 3")
|
||||||
|
|
||||||
# Issue #751
|
# Issue #751
|
||||||
(def t {:side false})
|
(def t {:side false})
|
||||||
(assert (nil? (get-in t [:side :note])) "get-in with false value")
|
(assert (nil? (get-in t [:side :note])) "get-in with false value")
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
# Format all code with astyle
|
# Format all code with astyle
|
||||||
|
|
||||||
STYLEOPTS="--style=attach --indent-switches --convert-tabs \
|
STYLEOPTS="--style=attach --indent-switches --convert-tabs \
|
||||||
--align-pointer=name --pad-header --pad-oper --unpad-paren --indent-labels"
|
--align-pointer=name --pad-header --pad-oper --unpad-paren --indent-labels --formatted"
|
||||||
|
|
||||||
astyle $STYLEOPTS */*.c
|
astyle $STYLEOPTS */*.c
|
||||||
astyle $STYLEOPTS */*/*.c
|
astyle $STYLEOPTS */*/*.c
|
||||||
astyle $STYLEOPTS */*/*.h
|
astyle $STYLEOPTS */*/*.h
|
||||||
|
rm -f */*.c.orig
|
||||||
|
rm -f */*/*.c.orig
|
||||||
|
rm -f */*/*.h.orig
|
||||||
|
Loading…
Reference in New Issue
Block a user