mirror of
https://github.com/janet-lang/janet
synced 2025-01-12 08:30:26 +00:00
Initial struct prototype code.
Also add a number of cfunctions for manipulating structs with prototypes.
This commit is contained in:
parent
7c757ef3bf
commit
4d983e54b5
@ -395,6 +395,23 @@ static Janet janet_core_table(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_table(table);
|
return janet_wrap_table(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet janet_core_getproto(int32_t argc, Janet *argv) {
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
static Janet janet_core_struct(int32_t argc, Janet *argv) {
|
static Janet janet_core_struct(int32_t argc, Janet *argv) {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
if (argc & 1)
|
if (argc & 1)
|
||||||
@ -731,6 +748,11 @@ static const JanetReg corelib_cfuns[] = {
|
|||||||
JDOC("(signal what x)\n\n"
|
JDOC("(signal what x)\n\n"
|
||||||
"Raise a signal with payload x. ")
|
"Raise a signal with payload x. ")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"getproto", janet_core_getproto,
|
||||||
|
JDOC("(getproto x)\n\n"
|
||||||
|
"Get the prototype of a table or struct. Will return nil if `x` has no prototype.")
|
||||||
|
},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1013,6 +1035,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);
|
||||||
|
@ -63,7 +63,8 @@ enum {
|
|||||||
LB_FUNCENV_REF, /* 219 */
|
LB_FUNCENV_REF, /* 219 */
|
||||||
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 */
|
||||||
} LeadBytes;
|
} LeadBytes;
|
||||||
|
|
||||||
/* Helper to look inside an entry in an environment */
|
/* Helper to look inside an entry in an environment */
|
||||||
@ -523,8 +524,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;
|
||||||
@ -1257,6 +1260,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 */
|
||||||
@ -1286,9 +1290,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);
|
||||||
|
@ -1149,8 +1149,8 @@ static uint32_t peg_compile1(Builder *b, Janet peg) {
|
|||||||
Janet nextPeg = janet_table_get_ex(grammar, peg, &grammar);
|
Janet nextPeg = janet_table_get_ex(grammar, peg, &grammar);
|
||||||
if (!grammar || janet_checktype(nextPeg, JANET_NIL)) {
|
if (!grammar || janet_checktype(nextPeg, JANET_NIL)) {
|
||||||
nextPeg = (b->default_grammar == NULL)
|
nextPeg = (b->default_grammar == NULL)
|
||||||
? janet_wrap_nil()
|
? janet_wrap_nil()
|
||||||
: janet_table_get(b->default_grammar, peg);
|
: janet_table_get(b->default_grammar, peg);
|
||||||
if (janet_checktype(nextPeg, JANET_NIL)) {
|
if (janet_checktype(nextPeg, JANET_NIL)) {
|
||||||
peg_panic(b, "unknown rule");
|
peg_panic(b, "unknown rule");
|
||||||
}
|
}
|
||||||
|
@ -568,12 +568,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;
|
||||||
@ -588,8 +588,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,52 @@ 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);
|
const JanetKV *kv = janet_struct_find(st, key);
|
||||||
return kv ? kv->value : janet_wrap_nil();
|
if (NULL != kv)
|
||||||
|
return kv->value;
|
||||||
|
/* Check prototypes */
|
||||||
|
{
|
||||||
|
int i = JANET_MAX_PROTO_DEPTH;
|
||||||
|
for (st = janet_struct_proto(st); st && i; st = janet_struct_proto(st), --i) {
|
||||||
|
kv = janet_struct_find(st, key);
|
||||||
|
if (NULL != kv)
|
||||||
|
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) {
|
||||||
|
const JanetKV *kv = janet_struct_find(st, key);
|
||||||
|
if (NULL != kv)
|
||||||
|
return kv->value;
|
||||||
|
/* Check prototypes */
|
||||||
|
{
|
||||||
|
int i = JANET_MAX_PROTO_DEPTH;
|
||||||
|
for (st = janet_struct_proto(st); st && i; st = janet_struct_proto(st), --i) {
|
||||||
|
kv = janet_struct_find(st, key);
|
||||||
|
if (NULL != kv) {
|
||||||
|
*which = kv;
|
||||||
|
return kv->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert struct to table */
|
/* Convert struct to table */
|
||||||
@ -167,3 +213,116 @@ JanetTable *janet_struct_to_table(const JanetKV *st) {
|
|||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* C Functions */
|
||||||
|
|
||||||
|
static Janet cfun_struct_with_proto(int32_t argc, Janet *argv) {
|
||||||
|
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);
|
||||||
|
janet_struct_proto(st) = proto;
|
||||||
|
for (int32_t i = 1; i < argc; i += 2) {
|
||||||
|
janet_struct_put(st, argv[i], argv[i + 1]);
|
||||||
|
}
|
||||||
|
return janet_wrap_struct(janet_struct_end(st));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_struct_getproto(int32_t argc, Janet *argv) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_struct_flatten(int32_t argc, Janet *argv) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_struct_to_table(int32_t argc, Janet *argv) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JanetReg struct_cfuns[] = {
|
||||||
|
{
|
||||||
|
"struct/with-proto", cfun_struct_with_proto,
|
||||||
|
JDOC("(struct/with-proto proto & kvs)\n\n"
|
||||||
|
"Create a structure, as with the usual struct constructor but set the "
|
||||||
|
"struct prototype as well.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"struct/getproto", cfun_struct_getproto,
|
||||||
|
JDOC("(struct/getproto st)\n\n"
|
||||||
|
"Get the prototype of a struct, or nil if it doesn't have one.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"struct/proto-flatten", cfun_struct_flatten,
|
||||||
|
JDOC("(struct/proto-flatten st)\n\n"
|
||||||
|
"Convert a struct with prototypes to a struct with no prototypes by merging "
|
||||||
|
"all key value pairs from recursive prototypes into one new struct.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"struct/to-table", cfun_struct_to_table,
|
||||||
|
JDOC("(struct/to-table st &opt recursive)\n\n"
|
||||||
|
"Convert a struct to a table. If recursive is true, also convert the "
|
||||||
|
"table's prototypes into the new struct's prototypes as well.")
|
||||||
|
},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Load the struct module */
|
||||||
|
void janet_lib_struct(JanetTable *env) {
|
||||||
|
janet_core_cfuns(env, NULL, struct_cfuns);
|
||||||
|
}
|
||||||
|
@ -208,6 +208,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;
|
||||||
@ -217,19 +234,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));
|
||||||
@ -266,6 +270,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 */
|
||||||
|
|
||||||
static Janet cfun_table_new(int32_t argc, Janet *argv) {
|
static Janet cfun_table_new(int32_t argc, Janet *argv) {
|
||||||
@ -311,6 +343,12 @@ static Janet cfun_table_clone(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_table(janet_table_clone(table));
|
return janet_wrap_table(janet_table_clone(table));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet cfun_table_proto_flatten(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
JanetTable *table = janet_gettable(argv, 0);
|
||||||
|
return janet_wrap_table(janet_table_proto_flatten(table));
|
||||||
|
}
|
||||||
|
|
||||||
static const JanetReg table_cfuns[] = {
|
static const JanetReg table_cfuns[] = {
|
||||||
{
|
{
|
||||||
"table/new", cfun_table_new,
|
"table/new", cfun_table_new,
|
||||||
@ -350,6 +388,11 @@ static const JanetReg table_cfuns[] = {
|
|||||||
"Create a copy of a table. Updates to the new table will not change the old table, "
|
"Create a copy of a table. Updates to the new table will not change the old table, "
|
||||||
"and vice versa.")
|
"and vice versa.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"table/proto-flatten", cfun_table_proto_flatten,
|
||||||
|
JDOC("(table/proto-flatten tab)\n\n"
|
||||||
|
"Create a new table that is the result of merging all prototypes into a new table.")
|
||||||
|
},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,6 +116,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);
|
||||||
|
@ -104,6 +104,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--;
|
||||||
}
|
}
|
||||||
@ -276,6 +287,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;
|
||||||
}
|
}
|
||||||
|
@ -922,6 +922,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[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1515,10 +1516,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,4 +161,22 @@
|
|||||||
([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 (= 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")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
@ -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