summaryrefslogtreecommitdiffstats
path: root/tree.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-07-08 19:17:39 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-07-08 19:17:39 -0700
commitfc22de3079459193253522efccdd7519879e34b7 (patch)
tree6c665cc9b800b81827a2a5214ed1125cb0dd49f3 /tree.c
parentc0a9036d15d9f0a910aab82905e6b5e7d6ce71da (diff)
downloadtxr-fc22de3079459193253522efccdd7519879e34b7.tar.gz
txr-fc22de3079459193253522efccdd7519879e34b7.tar.bz2
txr-fc22de3079459193253522efccdd7519879e34b7.zip
type: disallow structs using built-in type names.
This is a big commit motivated by the need to clean up the situation with built-in type symbols, COBJ objects and structs. The struct type system allows struct types to be defined for symbols like regex or str, which are used by built-in or cobj types. This is a bad thing. What is worse, structure instances are COBJ types which identify their type using the COBJ class symbol mechanism. There are places in the C implementation which assume that when a COBJ has a certain class symbol, it is of a certain expected type, which is totally different from and incompatible form a struct instance. User code can define a structure object which will fool that code. There are multiple things going on in this patch. The major theme is that the COBJ representation is changing. Instead of a class symbol, COBJ instances now carry a "struct cobj_class *" pointer. This pointer is obtained by registration via the cobj_register function. All modules must register their class symbols to obtain these class handles, which are then used in cobj() calls for instantiation. The CPTR type was identical to COBJ until now, except for the type tag. This is changing; CPTR objects will keep the old representation with the class symbol. commit 20fdfc6008297001491308849c17498c006fe7b4 Author: Kaz Kylheku <kaz@kylheku.com> Date: Thu Jul 8 19:17:39 2021 -0700 * ffi.h (carray_cls): Declared. * hash.h (hash_cls): Declared. (hash_early_init): Declared. * lib.h (struct cobj_class): New struct. (struct cobj): cls member changing to struct cobj_class *. (struct cptr): New struct, same as previous struct cobj. (union obj): New member cp of type struct cptr, for CPTR. (builtin_type): Declared. (class_check): Declaration moved closer to COBJ-related functions and updated. (cobj_register, cobj_register_super, cobj_class_exists): New functions declared. (cobjclassp, cobj_handle, cobj_ops): Declarations updated. * parser.h (parser_cls): Declared. * rand.h (random_state_cls): Declared. * regex.h (regex_cls): Declared. * stream.h (stream_cls, stdio_stream_cls): Declared. * struct.h (struct_cls): Declared. * tree.h (tree_cls, tree_iter_cls): Declared. * vm.h (vm_desc_cls): Declared. * buf.c (buf_strm, make_buf_stream): Pass stream_cls functions instead of stream_s class symbol. * chksum.c (sha256_ctx_cls, md5_ctx_cls): New static class handles. (sha256_begin, sha256_hash, sha256_end, md5_begin, md5_hash, md5_end): Pass class handles to instead of class symbols. (chksum_init): Initialize class handle variables. * ffi.c (ffi_type_cls, ffi_call_desc_cls, ffi_closure_cls, union_cls): New static class handles. (carray_cls): New global variable. (ffi_type_struct_checked, ffi_type_print_op, ffi_closure_struct_checked, ffi_closure_print_op, make_ffi_type_builtin, make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_union, make_ffi_type_array, make_ffi_type_enum, ffi_call_desc_checked, ffi_call_desc_print_op, ffi_make_call_desc, ffi_make_closure, carray_struct_checked, carray_print_op, make_carray, cptr_getobj, cptr_out, uni_struct_checked, make_union_common): Pass class handles instead of class symbols. (ffi_init): Initialize class handle variables. * filter.c (regex_from_trie): Use hash_cls class handle instead of hash_s. * gc.c (mark_obj): Split COBJ and CPTR cases since the representation is different. * hash.c (hash_cls, hash_iter_cls): New class handles. (make_similar_hash, copy_hash, gethash_c, gethash_e, remhash, clearhash, hash_count, get_hash_userdata, set_hash_userdata, hashp, hash_iter_init, hash_begin, hash_next, hash_peek, hash_reset, hash_reset, hash_uni, hash_diff, hash_symdiff, hash_isec): Pass class handles instead of class symbols. (hash_early_init): New function. (hash_init): Set the class symbols in the class handles that were created in hash_early_init at a time when these symbols did not exist. * lib.c (nelem): New macro. (cobj_class): New static array. (cobj_ptr): New static pointer. (cobj_hash): New static hash. (seq_iter_cls): New static class handle. (builtin_type_p): New function. (typeof): Struct instances now all carry the same symbol, struct, as their COBJ class symbol. To get their type, we must call struct_type_name. (subtypep): Rearrangement of two cases: let's make the reflexive case first. Adjust code for different location of COBJ class symbol. (seq_iter_init_with_info, seq_begin, seq_next, seq_reset, iter_begin, iter_more, iter_item, iter_step, iter_reset, make_like, list_collect, do_generic_funcall): Use class handles instead of class symbols. (class_check, cobj, cobjclassp, cobj_handle, cobj_ops): Take class handle argument instead of class symbol. (cobj_register, cobj_register_super, cobj_class_exists): New functions. (cobj_populate_hash): New static function. (cobj_print_op): Adjust for different location of class (cptr_print_op, cptr_typed, cptr_type, cptr_handle, cptr_get): cptr functions now refer to obj->cp rather than obj->co. (copy, length, sub, ref, refset, replace, dwim_set, dwim_del, obj_print): Use class handles for various COBJ types rather than class symbols. (obj_init): gc-protect cobj_hash. Initialize seq_iter_cls class symbol and cobj_hash. Populate cobj_hash as the last initialization step. (init): Call hash_early_init immediately after gc_init. diff --git a/lib.c b/lib.c * match.c (do_match_line): Refer to regex_cls class handle instead of regex_s.. * parser.c (parser_cls): New global class handle. (parse, parser_get_impl, lisp_parse_impl, txr_parse, parser_errors): Use class handles instead of class symbols. (parse_init): Initialize parser_cls. * rand.c (random_state_cls): New global class handle. (make_state, random_state_p, make_random_state, random_state_get_vec, random_fixnum, random_float, random): Use class handles instead of class symbols. (rand_init): Initialize random_state_cls. * regex.c (regex_cls): New global class handle. (chset_cls): New static class handle. (reg_compile_csets, reg_derivative, regex_compile, regexp, regex_source, regex_print, regex_run, regex_machine_init): Use class handles instead of class symbols. (regex_init): Initialize regex_cls and chset_cls. * socket.c (make_dgram_sock_stream): Use stream_cls class symbol instead of stream_s. * stream.c (stream_cls, stdio_stream_cls): New class handles. (make_null_stream, stdio_get_fd, make_stdio_stream_common, stream_fd, sock_family, sock_type, sock_peer, sock_set_peer, make_dir_stream, make_string_input_stream, make_string_byte_input_stream, make_strlist_input_stream, make_string_output_stream, make_strlist_output_stream, get_list_from_stream, make_catenated_stream, make_delegate_stream, make_delegate_stream, stream_set_prop, stream_get_prop, close_stream, get_error, get_error_str, clear_error, get_line, get_char, get_byte, get_bytes, unget_char, unget_byte, put_buf, fill_buf, fill_buf_adjust, get_line_as_buf, format, put_string, put_char, put_byte, flush_stream, seek_stream, truncate_stream, get_indent_mode, test_set_indent_mode, test_neq_set_indent_mode, set_indent_mode, get_indent, set_indent, inc_indent, width_check, force_break, set_max_length, set_max_depth): Use class handle instead of symbol. (stream_init): Initialize stream_cls and stdio_stream_cls. * struct.c (struct_type_cls, struct_cls): New class handles. (struct_init): Initialize struct_type_cls and struct_cls. (struct_handle): Static function moved to avoid forward declaration. (stype_handle): Refer to struct_type_cls class handle instead of struct_type_s symbol. Handle instance objects in addition to types. (make_struct_type): Throw error if a built-in type is being defined as a struct type. Refer to class handle instead of class symbol. (find_struct_type, allocate_struct, make_struct_impl, make_lazy_struct, copy_struct): Refer to class handle instead of class symbol. * strudel.c (make_struct_delegate_stream): Refer to stream_cls class handle instead of stream_s symbol. * sysif.c (dir_cls): New class handle. (poll_wrap): Use typep instead of subtypep, eliminating access to class symbol. (opendir_wrap, closedir_wrap, readdir_wrap): Use class handles instead of class symbols. (sysif_init): Initialize dir_cls. * syslog.c (make_syslog_stream): Refer to stream_cls class handle instead of stream_s symbol. * tree.c (tree_cls, tree_iter_cls): New class handles. (tree_insert_node, tree_lookup_node, tree_delete_node, tree_root, tree_equal_op, tree, copy_search_tree, make_similar_tree, treep, tree_begin, copy_tree_iter, replace_tree_iter, tree_reset, tree_next, tree_peek, tree_clear): Use class handle instead of class symbol. (tree_init): Initialize tree_cls and tree_iter_cls. * unwind.c (sys_cont_cls): New static class handle. (revive_cont, capture_cont): Use class handle instead of class symbol. (uw_late_init): Initialize sys_cont_cls. * vm.c (vm_desc_cls): New global class handle. (vm_closure_cls): New static class handle. (vm_desc_struct, vm_make_desc, vm_closure_struct, vm_make_closure, vm_copy_closure): Use class handle instead of class symbol. (vm_init): Initialize vm_desc_cls and vm_closure_cls.
Diffstat (limited to 'tree.c')
-rw-r--r--tree.c56
1 files changed, 31 insertions, 25 deletions
diff --git a/tree.c b/tree.c
index fb70c903..a0a0faf8 100644
--- a/tree.c
+++ b/tree.c
@@ -82,6 +82,8 @@ struct tree_diter {
val tree_s, tree_iter_s, tree_fun_whitelist_s;
+struct cobj_class *tree_cls, *tree_iter_cls;
+
val tnode(val key, val left, val right)
{
val obj = make_obj();
@@ -501,7 +503,7 @@ static val tr_delete(val tree, struct tree *tr, val key)
val tree_insert_node(val tree, val node)
{
val self = lit("tree-insert-node");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
type_check(self, node, TNOD);
@@ -530,7 +532,7 @@ val tree_insert(val tree, val key)
val tree_lookup_node(val tree, val key)
{
val self = lit("tree-lookup-node");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
return tr_lookup(tr, key);
}
@@ -543,7 +545,7 @@ val tree_lookup(val tree, val key)
val tree_delete_node(val tree, val key)
{
val self = lit("tree-delete-node");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
return tr_delete(tree, tr, key);
}
@@ -556,15 +558,15 @@ val tree_delete(val tree, val key)
static val tree_root(val tree)
{
val self = lit("tree-root");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
return tr->root;
}
static val tree_equal_op(val left, val right)
{
val self = lit("equal");
- struct tree *ltr = coerce(struct tree *, cobj_handle(self, left, tree_s));
- struct tree *rtr = coerce(struct tree *, cobj_handle(self, right, tree_s));
+ struct tree *ltr = coerce(struct tree *, cobj_handle(self, left, tree_cls));
+ struct tree *rtr = coerce(struct tree *, cobj_handle(self, right, tree_cls));
if (ltr->size != rtr->size)
return nil;
@@ -683,7 +685,7 @@ val tree(val keys_in, val key_fn, val less_fn, val equal_fn)
{
struct tree *tr = coerce(struct tree *, chk_calloc(1, sizeof *tr));
val keys = default_null_arg(keys_in), key;
- val tree = cobj(coerce(mem_t *, tr), tree_s, &tree_ops);
+ val tree = cobj(coerce(mem_t *, tr), tree_cls, &tree_ops);
seq_iter_t ki;
uses_or2;
@@ -743,9 +745,9 @@ val copy_search_tree(val tree)
{
val self = lit("copy-search-tree");
struct tree *ntr = coerce(struct tree *, malloc(sizeof *ntr));
- struct tree *otr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *otr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
val nroot = deep_copy_tnode(otr->root);
- val ntree = cobj(coerce(mem_t *, ntr), tree_s, &tree_ops);
+ val ntree = cobj(coerce(mem_t *, ntr), tree_cls, &tree_ops);
*ntr = *otr;
ntr->root = nroot;
return ntree;
@@ -755,8 +757,8 @@ val make_similar_tree(val tree)
{
val self = lit("make-similar-tree");
struct tree *ntr = coerce(struct tree *, malloc(sizeof *ntr));
- struct tree *otr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
- val ntree = cobj(coerce(mem_t *, ntr), tree_s, &tree_ops);
+ struct tree *otr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
+ val ntree = cobj(coerce(mem_t *, ntr), tree_cls, &tree_ops);
*ntr = *otr;
ntr->root = nil;
ntr->size = ntr->max_size = 0;
@@ -765,7 +767,7 @@ val make_similar_tree(val tree)
val treep(val obj)
{
- return tnil(type(obj) == COBJ && obj->co.cls == tree_s);
+ return tnil(type(obj) == COBJ && obj->co.cls == tree_cls);
}
static void tree_iter_mark(val tree_iter)
@@ -790,10 +792,10 @@ static struct cobj_ops tree_iter_ops = cobj_ops_init(eq,
val tree_begin(val tree, val lowkey, val highkey)
{
val self = lit("tree-begin");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
struct tree_diter *tdi = coerce(struct tree_diter *,
chk_calloc(1, sizeof *tdi));
- val iter = cobj(coerce(mem_t *, tdi), tree_iter_s, &tree_iter_ops);
+ val iter = cobj(coerce(mem_t *, tdi), tree_iter_cls, &tree_iter_ops);
tdi->ti.self = iter;
tdi->tree = tree;
@@ -815,10 +817,10 @@ val copy_tree_iter(val iter)
{
val self = lit("copy-tree-iter");
struct tree_diter *tdis = coerce(struct tree_diter *,
- cobj_handle(self, iter, tree_iter_s));
+ cobj_handle(self, iter, tree_iter_cls));
struct tree_diter *tdid = coerce(struct tree_diter *,
chk_calloc(1, sizeof *tdid));
- val iter_copy = cobj(coerce(mem_t *, tdid), tree_iter_s, &tree_iter_ops);
+ val iter_copy = cobj(coerce(mem_t *, tdid), tree_iter_cls, &tree_iter_ops);
int depth = tdis->ti.depth;
tdid->ti.self = iter_copy;
@@ -841,9 +843,9 @@ val replace_tree_iter(val diter, val siter)
{
val self = lit("replace-tree-iter");
struct tree_diter *tdid = coerce(struct tree_diter *,
- cobj_handle(self, diter, tree_iter_s));
+ cobj_handle(self, diter, tree_iter_cls));
struct tree_diter *tdis = coerce(struct tree_diter *,
- cobj_handle(self, siter, tree_iter_s));
+ cobj_handle(self, siter, tree_iter_cls));
int depth = tdis->ti.depth;
tdid->ti.depth = depth;
@@ -866,9 +868,9 @@ val replace_tree_iter(val diter, val siter)
val tree_reset(val iter, val tree, val lowkey, val highkey)
{
val self = lit("tree-reset");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
struct tree_diter *tdi = coerce(struct tree_diter *,
- cobj_handle(self, iter, tree_iter_s));
+ cobj_handle(self, iter, tree_iter_cls));
const struct tree_iter it = tree_iter_init(0);
tdi->ti = it;
@@ -894,8 +896,8 @@ val tree_next(val iter)
{
val self = lit("tree-next");
struct tree_diter *tdi = coerce(struct tree_diter *,
- cobj_handle(self, iter, tree_iter_s));
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tdi->tree, tree_s));
+ cobj_handle(self, iter, tree_iter_cls));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tdi->tree, tree_cls));
if (tdi->lastnode) {
val node = tn_find_next(tdi->lastnode, &tdi->ti);
@@ -923,8 +925,8 @@ val tree_peek(val iter)
{
val self = lit("tree-peek");
struct tree_diter *tdi = coerce(struct tree_diter *,
- cobj_handle(self, iter, tree_iter_s));
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tdi->tree, tree_s));
+ cobj_handle(self, iter, tree_iter_cls));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tdi->tree, tree_cls));
if (tdi->lastnode) {
val node = tn_peek_next(tdi->lastnode, &tdi->ti);
@@ -948,7 +950,7 @@ val tree_peek(val iter)
val tree_clear(val tree)
{
val self = lit("tree-clear");
- struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_s));
+ struct tree *tr = coerce(struct tree *, cobj_handle(self, tree, tree_cls));
cnum oldsize = tr->size;
tr->root = nil;
tr->size = tr->max_size = 0;
@@ -972,6 +974,10 @@ void tree_init(void)
tree_s = intern(lit("tree"), user_package);
tree_iter_s = intern(lit("tree-iter"), user_package);
tree_fun_whitelist_s = intern(lit("*tree-fun-whitelist*"), user_package);
+
+ tree_cls = cobj_register(tree_s);
+ tree_iter_cls = cobj_register(tree_iter_s);
+
reg_fun(tnode_s, func_n3(tnode));
reg_fun(intern(lit("left"), user_package), func_n1(left));
reg_fun(intern(lit("right"), user_package), func_n1(right));