From 09942b27ae6fd7e7d394b2d251ef77c8a6f69e07 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 7 Dec 2025 19:02:13 -0500 Subject: Rename `Empty()` -> `Present()` for set-like tables --- CHANGES.md | 3 ++- src/compile/cli.c | 2 +- src/compile/lists.c | 2 +- src/compile/tables.c | 10 +++++----- src/environment.c | 8 ++++---- src/environment.h | 2 +- src/stdlib/datatypes.h | 14 +++++++------- src/stdlib/structs.c | 11 ----------- src/stdlib/structs.h | 2 -- src/stdlib/tables.c | 12 ++++++++++++ src/stdlib/tables.h | 2 ++ src/typecheck.c | 10 +++++----- src/types.c | 2 +- 13 files changed, 41 insertions(+), 39 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 3e94c85d..4689e5aa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,12 +2,13 @@ ## v2025-12-06 -- You can now discard Empty values. +- You can now discard empty struct values. - For an enum `Foo(A,B,C)`, the syntax `f!` now desugars to `f.A!` using the first tag defined in the enum. - Error messages are more helpful for `foo.Whatever!` enum field accessing. - Simplified logic for enums so there is less difference between enums that have tags with member fields and those without. +- Rename `Empty()` to `Present()` for set-like tables. ## v2025-11-30 diff --git a/src/compile/cli.c b/src/compile/cli.c index 5130b97b..63a467ca 100644 --- a/src/compile/cli.c +++ b/src/compile/cli.c @@ -38,7 +38,7 @@ static Text_t get_flag_options(type_t *t, Text_t separator) { } else if (t->tag == ListType) { Text_t item_option = get_flag_options(Match(t, ListType)->item_type, separator); return Texts(item_option, "1 ", item_option, "2..."); - } else if (t->tag == TableType && Match(t, TableType)->value_type == EMPTY_TYPE) { + } else if (t->tag == TableType && Match(t, TableType)->value_type == PRESENT_TYPE) { Text_t item_option = get_flag_options(Match(t, TableType)->key_type, separator); return Texts(item_option, "1 ", item_option, "2..."); } else if (t->tag == TableType) { diff --git a/src/compile/lists.c b/src/compile/lists.c index 97b0b85d..31255c1e 100644 --- a/src/compile/lists.c +++ b/src/compile/lists.c @@ -254,7 +254,7 @@ Text_t compile_list_method_call(env_t *env, ast_t *ast) { } else if (streq(call->name, "unique")) { self = compile_to_pointer_depth(env, call->self, 0, false); (void)compile_arguments(env, ast, NULL, call->args); - return Texts("Table$from_entries(", self, ", Table$info(", compile_type_info(item_t), ", &Empty$$info))"); + return Texts("Table$from_entries(", self, ", Table$info(", compile_type_info(item_t), ", &Present$$info))"); } else if (streq(call->name, "pop")) { EXPECT_POINTER(); arg_t *arg_spec = new (arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, "-1")); diff --git a/src/compile/tables.c b/src/compile/tables.c index 54276c3b..e624f9fb 100644 --- a/src/compile/tables.c +++ b/src/compile/tables.c @@ -13,7 +13,7 @@ static ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject) { return WrapAST( entry, MethodCall, .name = "set", .self = subject, .args = new (arg_ast_t, .value = e->key, - .next = new (arg_ast_t, .value = e->value ? e->value : WrapAST(entry, Var, .name = "EMPTY")))); + .next = new (arg_ast_t, .value = e->value ? e->value : WrapAST(entry, Var, .name = "PRESENT")))); } Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) { @@ -51,10 +51,10 @@ Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) { for (ast_list_t *entry = table->entries; entry; entry = entry->next) { DeclareMatch(e, entry->ast, TableEntry); - code = Texts( - code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ", - compile_to_type(value_scope, e->value ? e->value : WrapAST(entry->ast, Var, .name = "EMPTY"), value_t), - "}"); + code = Texts(code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ", + compile_to_type(value_scope, e->value ? e->value : WrapAST(entry->ast, Var, .name = "PRESENT"), + value_t), + "}"); } return Texts(code, ")"); } diff --git a/src/environment.c b/src/environment.c index 7e04fe79..c5932e30 100644 --- a/src/environment.c +++ b/src/environment.c @@ -19,7 +19,7 @@ type_t *PATH_TYPE = NULL; public type_t *PATH_TYPE_TYPE = NULL; public -type_t *EMPTY_TYPE = NULL; +type_t *PRESENT_TYPE = NULL; static type_t *declare_type(env_t *env, const char *def_str) { ast_t *ast = parse_file_str(def_str); @@ -70,7 +70,7 @@ env_t *global_env(bool source_mapping) { PATH_TYPE_TYPE = declare_type(env, "enum PathType(Relative, Absolute, Home)"); PATH_TYPE = declare_type(env, "struct Path(type:PathType, components:[Text])"); - EMPTY_TYPE = declare_type(env, "struct Empty()"); + PRESENT_TYPE = declare_type(env, "struct Present()"); typedef struct { const char *name, *code, *type_str; @@ -90,7 +90,7 @@ env_t *global_env(bool source_mapping) { MAKE_TYPE("Void", Type(VoidType), Text("void"), Text("Void$info")), MAKE_TYPE("Abort", Type(AbortType), Text("void"), Text("Abort$info")), MAKE_TYPE("Memory", Type(MemoryType), Text("void"), Text("Memory$info")), - MAKE_TYPE("Empty", EMPTY_TYPE, Text("Empty$$type"), Text("Empty$$info")), + MAKE_TYPE("Present", PRESENT_TYPE, Text("Present$$type"), Text("Present$$info")), MAKE_TYPE( // "Bool", Type(BoolType), Text("Bool_t"), Text("Bool$info"), {"parse", "Bool$parse", "func(text:Text, remainder:&Text?=none -> Bool?)"}), @@ -530,7 +530,7 @@ env_t *global_env(bool source_mapping) { struct { const char *name, *code, *type_str; } global_vars[] = { - {"EMPTY", "EMPTY", "Empty"}, + {"PRESENT", "PRESENT", "Present"}, {"TOMO_VERSION", "TOMO_VERSION_TEXT", "Text"}, {"USE_COLOR", "USE_COLOR", "Bool"}, {"ask", "ask", "func(prompt:Text, bold=yes, force_tty=yes -> Text?)"}, diff --git a/src/environment.h b/src/environment.h index 6389cc7a..f48271b5 100644 --- a/src/environment.h +++ b/src/environment.h @@ -87,4 +87,4 @@ binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name); extern type_t *TEXT_TYPE; extern type_t *PATH_TYPE; extern type_t *PATH_TYPE_TYPE; -extern type_t *EMPTY_TYPE; +extern type_t *PRESENT_TYPE; diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index d51db8ab..fbd2ce73 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -69,18 +69,18 @@ typedef struct table_s { struct table_s *fallback; } Table_t; -typedef struct Empty$$struct { -} Empty$$type; +typedef struct Present$$struct { +} Present$$type; -#define EMPTY_STRUCT ((Empty$$type){}) +#define PRESENT_STRUCT ((Present$$type){}) typedef struct { bool has_value; - Empty$$type value; -} $OptionalEmpty$$type; + Present$$type value; +} $OptionalPresent$$type; -#define NONE_EMPTY_STRUCT (($OptionalEmpty$$type){.has_value = false}) -#define OPTIONAL_EMPTY_STRUCT (($OptionalEmpty$$type){.has_value = true}) +#define NONE_PRESENT_STRUCT (($OptionalPresent$$type){.has_value = false}) +#define OPTIONAL_PRESENT_STRUCT (($OptionalPresent$$type){.has_value = true}) typedef struct { void *fn, *userdata; diff --git a/src/stdlib/structs.c b/src/stdlib/structs.c index 89b5581b..da8f1461 100644 --- a/src/stdlib/structs.c +++ b/src/stdlib/structs.c @@ -215,14 +215,3 @@ void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo } } } - -public -const TypeInfo_t Empty$$info = {.size = 0, - .align = 0, - .tag = StructInfo, - .metamethods = Struct$metamethods, - .StructInfo.name = "Empty", - .StructInfo.num_fields = 0}; - -public -const Empty$$type EMPTY = {}; diff --git a/src/stdlib/structs.h b/src/stdlib/structs.h index 83904377..a582e9fb 100644 --- a/src/stdlib/structs.h +++ b/src/stdlib/structs.h @@ -15,8 +15,6 @@ PUREFUNC bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *t PUREFUNC Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type); void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type); void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type); -extern const TypeInfo_t Empty$$info; -extern const Empty$$type EMPTY; #define Struct$metamethods \ { \ diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index 6e774c53..a801957f 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -18,6 +18,7 @@ #include "metamethods.h" #include "pointers.h" #include "siphash.h" +#include "structs.h" #include "tables.h" #include "text.h" #include "types.h" @@ -757,3 +758,14 @@ void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_ *(Table_t *)outval = t; } + +public +const TypeInfo_t Present$$info = {.size = 0, + .align = 0, + .tag = StructInfo, + .metamethods = Struct$metamethods, + .StructInfo.name = "Present", + .StructInfo.num_fields = 0}; + +public +const Present$$type PRESENT = {}; diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h index cc2b3b91..cf1c3625 100644 --- a/src/stdlib/tables.h +++ b/src/stdlib/tables.h @@ -130,6 +130,8 @@ void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_ #define Table$length(t) ((t).entries.length) +extern const TypeInfo_t Present$$info; +extern const Present$$type PRESENT; extern const TypeInfo_t CStrToVoidStarTable; #define Table$metamethods \ diff --git a/src/typecheck.c b/src/typecheck.c index af726a14..139f0655 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -74,7 +74,7 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) { if (has_stack_memory(key_type)) code_err(key_type_ast, "Tables can't have stack references because the list may outlive the stack frame."); - type_t *val_type = table_type->value ? parse_type_ast(env, table_type->value) : EMPTY_TYPE; + type_t *val_type = table_type->value ? parse_type_ast(env, table_type->value) : PRESENT_TYPE; if (!val_type) code_err(ast, "I can't figure out what the value type for this entry is."); if (table_type->value && has_stack_memory(val_type)) @@ -809,7 +809,7 @@ type_t *get_type(env_t *env, ast_t *ast) { DeclareMatch(e, entry_ast, TableEntry); type_t *key_t = get_type(scope, e->key); - type_t *value_t = e->value ? get_type(scope, e->value) : EMPTY_TYPE; + type_t *value_t = e->value ? get_type(scope, e->value) : PRESENT_TYPE; type_t *key_merged = key_type ? type_or_type(key_type, key_t) : key_t; if (!key_merged) ambiguous_key_type = true; @@ -842,7 +842,7 @@ type_t *get_type(env_t *env, ast_t *ast) { } else if (comp->expr->tag == TableEntry) { DeclareMatch(e, comp->expr, TableEntry); return Type(TableType, .key_type = get_type(scope, e->key), - .value_type = e->value ? get_type(scope, e->value) : EMPTY_TYPE, .env = env); + .value_type = e->value ? get_type(scope, e->value) : PRESENT_TYPE, .env = env); } else { return Type(ListType, .item_type = get_type(scope, comp->expr)); } @@ -964,7 +964,7 @@ type_t *get_type(env_t *env, ast_t *ast) { else if (streq(call->name, "sorted")) return self_value_t; else if (streq(call->name, "to")) return self_value_t; else if (streq(call->name, "unique")) - return Type(TableType, .key_type = item_type, .value_type = EMPTY_TYPE); + return Type(TableType, .key_type = item_type, .value_type = PRESENT_TYPE); else code_err(ast, "There is no '", call->name, "' method for lists"); } case TableType: { @@ -1718,7 +1718,7 @@ PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed) { if (entry->ast->tag != TableEntry) continue; // TODO: fix this DeclareMatch(e, entry->ast, TableEntry); if (!can_compile_to_type(env, e->key, key_type) - || !(e->value ? can_compile_to_type(env, e->value, value_type) : type_eq(value_type, EMPTY_TYPE))) + || !(e->value ? can_compile_to_type(env, e->value, value_type) : type_eq(value_type, PRESENT_TYPE))) return false; } return true; diff --git a/src/types.c b/src/types.c index e3bf326c..5c52992b 100644 --- a/src/types.c +++ b/src/types.c @@ -47,7 +47,7 @@ Text_t type_to_text(type_t *t) { } case TableType: { DeclareMatch(table, t, TableType); - return (table->value_type && table->value_type != EMPTY_TYPE) + return (table->value_type && table->value_type != PRESENT_TYPE) ? Texts("{", type_to_text(table->key_type), ":", type_to_text(table->value_type), "}") : Texts("{", type_to_text(table->key_type), "}"); } -- cgit v1.2.3