diff options
33 files changed, 282 insertions, 271 deletions
@@ -358,7 +358,7 @@ void visit_topologically(ast_list_t *asts, Closure_t fn) { // - visiting typedefs' dependencies first // - then function/variable declarations - Table_t definitions = {}; + Table_t definitions = EMPTY_TABLE; for (ast_list_t *stmt = asts; stmt; stmt = stmt->next) { if (stmt->ast->tag == StructDef) { DeclareMatch(def, stmt->ast, StructDef); @@ -373,7 +373,7 @@ void visit_topologically(ast_list_t *asts, Closure_t fn) { } void (*visit)(void *, ast_t *) = (void *)fn.fn; - Table_t visited = {}; + Table_t visited = EMPTY_TABLE; // First: 'use' statements in order: for (ast_list_t *stmt = asts; stmt; stmt = stmt->next) { if (stmt->ast->tag == Use) visit(fn.userdata, stmt->ast); diff --git a/src/compile/cli.c b/src/compile/cli.c index b082239d..d93e5f56 100644 --- a/src/compile/cli.c +++ b/src/compile/cli.c @@ -60,19 +60,19 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c type_t *t = get_arg_type(main_env, arg); if (arg->default_val || arg->type->tag == OptionalType) { OptionalText_t flag = flagify(arg->name, true); - assert(flag.length >= 0); + assert(flag.tag != TEXT_NONE); OptionalText_t alias_flag = flagify(arg->alias, true); - Text_t flags = alias_flag.length >= 0 ? Texts(flag, "|", alias_flag) : flag; + Text_t flags = alias_flag.tag != TEXT_NONE ? Texts(flag, "|", alias_flag) : flag; if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType)) usage = Texts(usage, "[", flags, "]"); else if (t->tag == ListType) usage = Texts(usage, "[", flags, " ", get_flag_options(t, "|"), "]"); else usage = Texts(usage, "[", flags, "=", get_flag_options(t, "|"), "]"); } else { OptionalText_t flag = flagify(arg->name, false); - assert(flag.length >= 0); + assert(flag.tag != TEXT_NONE); OptionalText_t alias_flag = flagify(arg->alias, true); if (t->tag == BoolType) - usage = Texts(usage, "<--", flag, alias_flag.length >= 0 ? Texts("|", alias_flag) : EMPTY_TEXT, + usage = Texts(usage, "<--", flag, alias_flag.tag != TEXT_NONE ? Texts("|", alias_flag) : EMPTY_TEXT, "|--no-", flag, ">"); else if (t->tag == EnumType) usage = Texts(usage, get_flag_options(t, "|")); else if (t->tag == ListType) usage = Texts(usage, "[", flag, "...]"); diff --git a/src/compile/expressions.c b/src/compile/expressions.c index a4603cd5..72fc5e73 100644 --- a/src/compile/expressions.c +++ b/src/compile/expressions.c @@ -41,8 +41,8 @@ Text_t compile_empty(type_t *t) { } case ByteType: return Text("((Byte_t)0)"); case BoolType: return Text("((Bool_t)no)"); - case ListType: return Text("((List_t){})"); - case TableType: return Text("((Table_t){})"); + case ListType: return Text("((List_t){.has_value=1})"); + case TableType: return Text("((Table_t){.entries.has_value=1})"); case TextType: return Text("Text(\"\")"); case CStringType: return Text("\"\""); case PointerType: { @@ -177,7 +177,7 @@ Text_t compile(env_t *env, ast_t *ast) { } case List: { DeclareMatch(list, ast, List); - if (!list->items) return Text("(List_t){.length=0}"); + if (!list->items) return Text("(List_t){.has_value=1, .length=0}"); type_t *list_type = get_type(env, ast); return compile_typed_list(env, ast, list_type); diff --git a/src/compile/functions.c b/src/compile/functions.c index d2320e04..a1bc15ae 100644 --- a/src/compile/functions.c +++ b/src/compile/functions.c @@ -62,7 +62,7 @@ Text_t compile_convert_declaration(env_t *env, ast_t *ast) { public Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) { - Table_t used_args = {}; + Table_t used_args = EMPTY_TABLE; Text_t code = EMPTY_TEXT; env_t *default_scope = new (env_t); *default_scope = *env; @@ -263,7 +263,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) { Table_t closed_vars = get_closed_vars(env, lambda->args, ast); if (Table$length(closed_vars) > 0) { // Create a typedef for the lambda's closure userdata Text_t def = Text("typedef struct {"); - for (int64_t i = 0; i < closed_vars.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)closed_vars.entries.length; i++) { struct { const char *name; binding_t *b; @@ -293,7 +293,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) { userdata = Text("NULL"); } else { userdata = Texts("new(", name, "$userdata_t"); - for (int64_t i = 0; i < closed_vars.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)closed_vars.entries.length; i++) { struct { const char *name; binding_t *b; @@ -596,7 +596,7 @@ Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block) { set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name)); } - Table_t closed_vars = {}; + Table_t closed_vars = EMPTY_TABLE; add_closed_vars(&closed_vars, env, body_scope, block); return closed_vars; } @@ -633,7 +633,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static } Text_t arg_signature = Text("("); - Table_t used_names = {}; + Table_t used_names = EMPTY_TABLE; for (arg_ast_t *arg = args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name))); @@ -727,7 +727,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static Text_t wrapper = Texts(is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n" - "static Table_t cache = {};\n", + "static Table_t cache = EMPTY_TABLE;\n", "const TypeInfo_t *table_type = Table$info(", compile_type_info(arg_type), ", ", compile_type_info(ret_t), ");\n", compile_declaration(Type(PointerType, .pointed = ret_t), Text("cached")), @@ -750,7 +750,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static type_t *t = Type(StructType, .name = String("func$", get_line_number(ast->file, ast->start), "$args"), .fields = fields, .env = env); - int64_t num_fields = used_names.entries.length; + int64_t num_fields = (int64_t)used_names.entries.length; const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods"; Text_t args_typeinfo = Texts("((TypeInfo_t[1]){{.size=sizeof(args), " ".align=__alignof__(args), .metamethods=", @@ -775,7 +775,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static Text_t wrapper = Texts( is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n" - "static Table_t cache = {};\n", + "static Table_t cache = EMPTY_TABLE;\n", args_type, " args = {", all_args, "};\n" "const TypeInfo_t *table_type = Table$info(", diff --git a/src/compile/lists.c b/src/compile/lists.c index e3aa951b..7bbf0471 100644 --- a/src/compile/lists.c +++ b/src/compile/lists.c @@ -20,7 +20,7 @@ static ast_t *add_to_list_comprehension(ast_t *item, ast_t *subject) { public Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) { DeclareMatch(list, ast, List); - if (!list->items) return Text("(List_t){.length=0}"); + if (!list->items) return Text("(List_t){.has_value=1, .length=0}"); type_t *item_type = Match(list_type, ListType)->item_type; @@ -48,7 +48,7 @@ list_comprehension: { LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = list_type, .is_stack = true)); Closure_t comp_action = {.fn = add_to_list_comprehension, .userdata = comprehension_var}; scope->comprehension_action = &comp_action; - Text_t code = Texts("({ List_t ", comprehension_name, " = {};"); + Text_t code = Texts("({ List_t ", comprehension_name, " = {.has_value=1};"); // set_binding(scope, comprehension_name, list_type, comprehension_name); for (ast_list_t *item = list->items; item; item = item->next) { if (item->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, item->ast)); diff --git a/src/compile/optionals.c b/src/compile/optionals.c index d74f0f31..e855c73c 100644 --- a/src/compile/optionals.c +++ b/src/compile/optionals.c @@ -54,7 +54,7 @@ Text_t compile_none(type_t *t) { if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type"); if (t == PATH_TYPE) return Text("NONE_PATH"); - else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})"); + else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){.type = PATH_NONE})"); switch (t->tag) { case BigIntType: return Text("NONE_INT"); @@ -99,10 +99,10 @@ Text_t check_none(type_t *t, Text_t value) { else if (t->tag == ClosureType) return Texts("((", value, ").fn == NULL)"); else if (t->tag == NumType) return Texts(Match(t, NumType)->bits == TYPE_NBITS64 ? "Num$isnan(" : "Num32$isnan(", value, ")"); - else if (t->tag == ListType) return Texts("((", value, ").length < 0)"); - else if (t->tag == TableType) return Texts("((", value, ").entries.length < 0)"); + else if (t->tag == ListType) return Texts("!(", value, ").has_value"); + else if (t->tag == TableType) return Texts("!(", value, ").entries.has_value"); else if (t->tag == BoolType) return Texts("((", value, ") == NONE_BOOL)"); - else if (t->tag == TextType) return Texts("((", value, ").length < 0)"); + else if (t->tag == TextType) return Texts("!(", value, ").has_value"); else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType) return Texts("(", value, ").is_none"); else if (t->tag == EnumType) { if (enum_has_fields(t)) return Texts("((", value, ").$tag == 0)"); diff --git a/src/compile/statements.c b/src/compile/statements.c index 37eff680..156cc8c0 100644 --- a/src/compile/statements.c +++ b/src/compile/statements.c @@ -91,7 +91,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) { static int defer_id = 0; env_t *defer_env = fresh_scope(env); Text_t code = EMPTY_TEXT; - for (int64_t i = 0; i < closed_vars.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)closed_vars.entries.length; i++) { struct { const char *name; binding_t *b; diff --git a/src/compile/tables.c b/src/compile/tables.c index 814d81f5..1ceb96b3 100644 --- a/src/compile/tables.c +++ b/src/compile/tables.c @@ -60,8 +60,8 @@ table_comprehension: { ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = table_type, .is_stack = true)); - Text_t code = Texts("({ Table_t ", comprehension_name, " = {"); - if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), "); + Text_t code = Texts("({ Table_t ", comprehension_name, " = {.entries.has_value=1"); + if (table->fallback) code = Texts(code, ", .fallback=heap(", compile(env, table->fallback), "), "); code = Texts(code, "};"); diff --git a/src/environment.c b/src/environment.c index c29aa29d..3f07787e 100644 --- a/src/environment.c +++ b/src/environment.c @@ -405,7 +405,7 @@ env_t *global_env(bool source_mapping) { binding_t *type_binding = Table$str_get(*env->globals, global_types[i].name); assert(type_binding); env_t *ns_env = Match(type_binding->type, TypeInfoType)->env; - for (int64_t j = 0; j < global_types[i].namespace.length; j++) { + for (int64_t j = 0; j < (int64_t)global_types[i].namespace.length; j++) { ns_entry_t *entry = global_types[i].namespace.data + j * global_types[i].namespace.stride; type_t *type = parse_type_string(ns_env, entry->type_str); if (!type) compiler_err(NULL, NULL, NULL, "Couldn't parse type string: ", entry->type_str); @@ -715,14 +715,14 @@ PUREFUNC binding_t *get_constructor(env_t *env, type_t *t, arg_ast_t *args, bool List_t constructors = type_env->namespace->constructors; // Prioritize exact matches: call_opts_t options = {.promotion = false, .underscores = allow_underscores}; - for (int64_t i = constructors.length - 1; i >= 0; i--) { + for (int64_t i = (int64_t)constructors.length - 1; i >= 0; i--) { binding_t *constructor = constructors.data + i * constructors.stride; DeclareMatch(fn, constructor->type, FunctionType); if (type_eq(fn->ret, t) && is_valid_call(env, fn->args, args, options)) return constructor; } // Fall back to promotion: options.promotion = true; - for (int64_t i = constructors.length - 1; i >= 0; i--) { + for (int64_t i = (int64_t)constructors.length - 1; i >= 0; i--) { binding_t *constructor = constructors.data + i * constructors.stride; DeclareMatch(fn, constructor->type, FunctionType); if (type_eq(fn->ret, t) && is_valid_call(env, fn->args, args, options)) return constructor; diff --git a/src/formatter/args.c b/src/formatter/args.c index 997a1e39..9d1a2f71 100644 --- a/src/formatter/args.c +++ b/src/formatter/args.c @@ -19,7 +19,7 @@ OptionalText_t format_inline_arg(arg_ast_t *arg, Table_t comments) { Text_t format_arg(arg_ast_t *arg, Table_t comments, Text_t indent) { OptionalText_t inline_arg = format_inline_arg(arg, comments); - if (inline_arg.length >= 0 && inline_arg.length <= MAX_WIDTH) return inline_arg; + if (inline_arg.tag != TEXT_NONE && inline_arg.length <= MAX_WIDTH) return inline_arg; if (arg->name == NULL && arg->value) return format_code(arg->value, comments, indent); Text_t code = Text$from_str(arg->name); if (arg->type) code = Texts(code, ":", format_type(arg->type)); @@ -43,7 +43,7 @@ OptionalText_t format_inline_args(arg_ast_t *args, Table_t comments) { Text_t format_args(arg_ast_t *args, Table_t comments, Text_t indent) { OptionalText_t inline_args = format_inline_args(args, comments); - if (inline_args.length >= 0 && inline_args.length <= MAX_WIDTH) return inline_args; + if (inline_args.tag != TEXT_NONE && inline_args.length <= MAX_WIDTH) return inline_args; Text_t code = EMPTY_TEXT; for (arg_ast_t *arg = args; arg; arg = arg->next) { if (arg->name && arg->next && arg->type == arg->next->type && arg->value == arg->next->value) { diff --git a/src/formatter/enums.c b/src/formatter/enums.c index 893f055b..e497e20c 100644 --- a/src/formatter/enums.c +++ b/src/formatter/enums.c @@ -20,7 +20,7 @@ OptionalText_t format_inline_tag(tag_ast_t *tag, Table_t comments) { Text_t format_tag(tag_ast_t *tag, Table_t comments, Text_t indent) { OptionalText_t inline_tag = format_inline_tag(tag, comments); - if (inline_tag.length >= 0) return inline_tag; + if (inline_tag.tag != TEXT_NONE) return inline_tag; Text_t code = Text$from_str(tag->name); if (tag->fields || tag->secret) { code = Texts(code, "(", format_args(tag->fields, comments, Texts(indent, single_indent))); @@ -42,7 +42,7 @@ OptionalText_t format_inline_tags(tag_ast_t *tags, Table_t comments) { Text_t format_tags(tag_ast_t *tags, Table_t comments, Text_t indent) { OptionalText_t inline_tags = format_inline_tags(tags, comments); - if (inline_tags.length >= 0) return inline_tags; + if (inline_tags.tag != TEXT_NONE) return inline_tags; Text_t code = EMPTY_TEXT; for (; tags; tags = tags->next) { add_line(&code, Texts(format_tag(tags, comments, indent), ","), indent); diff --git a/src/formatter/formatter.c b/src/formatter/formatter.c index 2d220493..9ff328d0 100644 --- a/src/formatter/formatter.c +++ b/src/formatter/formatter.c @@ -89,7 +89,7 @@ static Text_t format_text(text_opts_t opts, ast_list_t *chunks, Table_t comments List_t lines = Text$lines(literal); if (lines.length == 0) continue; current_line = Texts(current_line, Text$escaped(*(Text_t *)lines.data, false, opts.interp)); - for (int64_t i = 1; i < lines.length; i += 1) { + for (int64_t i = 1; i < (int64_t)lines.length; i += 1) { add_line(&code, current_line, Texts(indent, single_indent)); current_line = Text$escaped(*(Text_t *)(lines.data + i * lines.stride), false, opts.interp); } @@ -402,7 +402,7 @@ PUREFUNC static int64_t trailing_line_len(Text_t text) { Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { OptionalText_t inlined = format_inline_code(ast, comments); - bool inlined_fits = (inlined.length >= 0 && indent.length + inlined.length <= MAX_WIDTH); + bool inlined_fits = (inlined.tag != TEXT_NONE && indent.length + inlined.length <= MAX_WIDTH); switch (ast->tag) { /*multiline*/ case Unknown: @@ -758,7 +758,7 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { /*multiline*/ case Int: /*multiline*/ case Num: /*multiline*/ case Var: { - assert(inlined.length >= 0); + assert(inlined.tag != TEXT_NONE); return inlined; } /*multiline*/ case FunctionCall: { diff --git a/src/formatter/types.c b/src/formatter/types.c index 3c77fa7d..670405f6 100644 --- a/src/formatter/types.c +++ b/src/formatter/types.c @@ -22,7 +22,7 @@ Text_t format_type(type_ast_t *type) { Text_t code = Texts("{", format_type(table->key), ":", format_type(table->value)); if (table->default_value) { OptionalText_t val = format_inline_code(table->default_value, (Table_t){}); - assert(val.length >= 0); + assert(val.tag != TEXT_NONE); code = Texts(code, "=", val); } return Texts(code, "}"); diff --git a/src/formatter/utils.c b/src/formatter/utils.c index 9cd0227d..9829df4b 100644 --- a/src/formatter/utils.c +++ b/src/formatter/utils.c @@ -35,7 +35,7 @@ OptionalText_t next_comment(Table_t comments, const char **pos, const char *end) bool range_has_comment(const char *start, const char *end, Table_t comments) { OptionalText_t comment = next_comment(comments, &start, end); - return (comment.length >= 0); + return (comment.tag != TEXT_NONE); } CONSTFUNC int suggested_blank_lines(ast_t *first, ast_t *second) { diff --git a/src/formatter/utils.h b/src/formatter/utils.h index 880da0a9..ba96ed50 100644 --- a/src/formatter/utils.h +++ b/src/formatter/utils.h @@ -13,7 +13,7 @@ #define must(expr) \ ({ \ OptionalText_t _expr = expr; \ - if (_expr.length < 0) return NONE_TEXT; \ + if (_expr.tag == TEXT_NONE) return NONE_TEXT; \ (Text_t) _expr; \ }) diff --git a/src/modules.c b/src/modules.c index 08550f2e..9ebdca09 100644 --- a/src/modules.c +++ b/src/modules.c @@ -51,7 +51,7 @@ bool install_from_modules_ini(Path_t ini_file, bool ask_confirmation) { if (by_line.fn == NULL) return false; OptionalText_t (*next_line)(void *) = by_line.fn; module_info_t info = {}; - for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) { + for (OptionalText_t line; (line = next_line(by_line.userdata)).tag != TEXT_NONE;) { char *line_str = Text$as_c_string(line); const char *next_section = NULL; if (!strparse(line_str, "[", &next_section, "]")) { @@ -78,13 +78,13 @@ static void read_modules_ini(Path_t ini_file, module_info_t *info) { if (by_line.fn == NULL) return; OptionalText_t (*next_line)(void *) = by_line.fn; find_section:; - for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) { + for (OptionalText_t line; (line = next_line(by_line.userdata)).tag != TEXT_NONE;) { char *line_str = Text$as_c_string(line); if (line_str[0] == '[' && strncmp(line_str + 1, info->name, strlen(info->name)) == 0 && line_str[1 + strlen(info->name)] == ']') break; } - for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) { + for (OptionalText_t line; (line = next_line(by_line.userdata)).tag != TEXT_NONE;) { char *line_str = Text$as_c_string(line); if (line_str[0] == '[') goto find_section; if (!strparse(line_str, "version=", &info->version) || !strparse(line_str, "url=", &info->url) @@ -95,7 +95,7 @@ find_section:; } module_info_t get_used_module_info(ast_t *use) { - static Table_t cache = {}; + static Table_t cache = EMPTY_TABLE; TypeInfo_t *cache_type = Table$info(Pointer$info("@", &Memory$info), Pointer$info("@", &Memory$info)); module_info_t **cached = Table$get(cache, &use, cache_type); if (cached) return **cached; diff --git a/src/naming.c b/src/naming.c index 08a568ac..8f18b70e 100644 --- a/src/naming.c +++ b/src/naming.c @@ -112,6 +112,6 @@ Text_t get_id_suffix(const char *filename) { } Path_t id_file = Path$child(build_dir, Texts(Path$base_name(path), Text$from_str(".id"))); OptionalText_t id = Path$read(id_file); - if (id.length < 0) err(1, "Could not read ID file: %s", id_file); + if (id.tag != TEXT_NONE) err(1, "Could not read ID file: %s", Path$as_c_string(id_file)); return Texts("$", id); } diff --git a/src/parse/files.c b/src/parse/files.c index caecbbe8..5e0dc29c 100644 --- a/src/parse/files.c +++ b/src/parse/files.c @@ -17,7 +17,6 @@ #include "statements.h" #include "text.h" #include "typedefs.h" -#include "types.h" #include "utils.h" // The cache of {filename -> parsed AST} will hold at most this many entries: @@ -67,7 +66,7 @@ ast_t *parse_file(const char *path, jmp_buf *on_err) { // hold more than PARSE_CACHE_SIZE entries (see below), but each entry's // AST holds onto a reference to the file it came from, so they could // potentially be somewhat large. - static Table_t cached = {}; + static Table_t cached = EMPTY_TABLE; ast_t *ast = Table$str_get(cached, path); if (ast) return ast; @@ -106,6 +105,7 @@ ast_t *parse_file(const char *path, jmp_buf *on_err) { const char *path; ast_t *ast; } *to_remove = Table$entry(cached, 1); + assert(to_remove); Table$str_remove(&cached, to_remove->path); } diff --git a/src/stdlib/cli.c b/src/stdlib/cli.c index 62174f19..1e4324f9 100644 --- a/src/stdlib/cli.c +++ b/src/stdlib/cli.c @@ -124,9 +124,10 @@ static List_t parse_list(const TypeInfo_t *item_info, int n, char *args[]) { if ((padded_size % item_info->align) > 0) padded_size = padded_size + item_info->align - (padded_size % item_info->align); + uint64_t u = (uint64_t)n; List_t items = { .stride = padded_size, - .length = n, + .length = u, .data = GC_MALLOC((size_t)(padded_size * n)), }; for (int i = 0; i < n; i++) { @@ -145,9 +146,10 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) { padded_size += value->size; if ((padded_size % key->align) > 0) padded_size = padded_size + key->align - (padded_size % key->align); + uint64_t u = (uint64_t)n; List_t entries = { .stride = padded_size, - .length = n, + .length = u, .data = GC_MALLOC((size_t)(padded_size * n)), }; for (int i = 0; i < n; i++) { @@ -378,7 +380,7 @@ void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const c for (int s = 0; s < spec_len; s++) { if (!populated_args[s] && spec[s].required) { - if (spec[s].type->tag == ListInfo) *(OptionalList_t *)spec[s].dest = (List_t){}; + if (spec[s].type->tag == ListInfo) *(OptionalList_t *)spec[s].dest = EMPTY_LIST; else if (spec[s].type->tag == TableInfo) *(OptionalTable_t *)spec[s].dest = (Table_t){}; else print_err("The required argument '", spec[s].name, "' was not provided\n", usage); } diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index 373cbc47..cbf09519 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -41,7 +41,7 @@ typedef struct { // structs can be passed in two 64-bit registers. C will handle doing the // bit arithmetic to extract the necessary values, which is cheaper than // spilling onto the stack and needing to retrieve data from the stack. - int64_t length : LIST_LENGTH_BITS; + uint64_t length : LIST_LENGTH_BITS; uint64_t free : LIST_FREE_BITS; bool atomic : LIST_ATOMIC_BITS; uint8_t data_refcount : LIST_REFCOUNT_BITS; @@ -73,11 +73,11 @@ typedef struct { void *fn, *userdata; } Closure_t; -enum text_type { TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT, TEXT_BLOB }; +enum text_type { TEXT_NONE, TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT, TEXT_BLOB }; typedef struct Text_s { - int64_t length : 54; // Number of grapheme clusters - uint8_t tag : 2; + uint64_t length : 53; // Number of grapheme clusters + uint8_t tag : 3; uint8_t depth : 8; union { struct { diff --git a/src/stdlib/lists.c b/src/stdlib/lists.c index bae79dfd..516f37e2 100644 --- a/src/stdlib/lists.c +++ b/src/stdlib/lists.c @@ -18,6 +18,9 @@ // Use inline version of siphash code: #include "siphash-internals.h" +public +char _EMPTY_LIST_SENTINEL = '\0'; + PUREFUNC static INLINE int64_t get_padded_item_size(const TypeInfo_t *info) { int64_t size = info->ListInfo.item->size; if (info->ListInfo.item->align > 1 && size % info->ListInfo.item->align) errx(1, "Item size is not padded!"); @@ -35,7 +38,7 @@ void List$compact(List_t *list, int64_t padded_item_size) { if ((int64_t)list->stride == padded_item_size) { memcpy(copy, list->data, (size_t)list->length * (size_t)padded_item_size); } else { - for (int64_t i = 0; i < list->length; i++) + for (int64_t i = 0; i < (int64_t)list->length; i++) memcpy(copy + i * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size); } } @@ -50,7 +53,7 @@ void List$compact(List_t *list, int64_t padded_item_size) { public void List$insert(List_t *list, const void *item, Int_t int_index, int64_t padded_item_size) { int64_t index = Int64$from_int(int_index, false); - if (index <= 0) index = list->length + index + 1; + if (index <= 0) index = (int64_t)list->length + index + 1; if (index < 1) index = 1; else if (index > (int64_t)list->length + 1) @@ -74,9 +77,9 @@ void List$insert(List_t *list, const void *item, Int_t int_index, int64_t padded list->data_refcount = 0; list->stride = padded_item_size; } else { - if (index != list->length + 1) { - assert(list->length >= index); - size_t size = (size_t)((list->length - index + 1) * padded_item_size); + if (index != (int64_t)list->length + 1) { + assert((int64_t)list->length >= index); + size_t size = (size_t)(((int64_t)list->length - index + 1) * padded_item_size); assert(size < SIZE_MAX); memmove(list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size, size); } @@ -98,7 +101,7 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa return; } - if (index < 1) index = list->length + index + 1; + if (index < 1) index = (int64_t)list->length + index + 1; if (index < 1) index = 1; else if (index > (int64_t)list->length + 1) @@ -110,15 +113,15 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa // If we can fit this within the list's preallocated free space, do that: list->free -= to_insert.length; list->length += to_insert.length; - if (index != list->length + 1) + if (index != (int64_t)list->length + 1) memmove((void *)list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size, - (size_t)((list->length - index + to_insert.length - 1) * padded_item_size)); - for (int64_t i = 0; i < to_insert.length; i++) + (size_t)(((int64_t)list->length - index + (int64_t)to_insert.length - 1) * padded_item_size)); + for (int64_t i = 0; i < (int64_t)to_insert.length; i++) memcpy((void *)list->data + (index - 1 + i) * padded_item_size, to_insert.data + i * to_insert.stride, (size_t)padded_item_size); } else { // Otherwise, allocate a new chunk of memory for the list and populate it: - int64_t new_len = list->length + to_insert.length; + int64_t new_len = (int64_t)list->length + (int64_t)to_insert.length; list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, new_len / 4)); void *data = list->atomic ? GC_MALLOC_ATOMIC((size_t)((new_len + list->free) * padded_item_size)) : GC_MALLOC((size_t)((new_len + list->free) * padded_item_size)); @@ -139,8 +142,8 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa // Copy `to_insert` if (to_insert.stride == padded_item_size) { - memcpy(p, to_insert.data, (size_t)(to_insert.length * padded_item_size)); - p += to_insert.length * padded_item_size; + memcpy(p, to_insert.data, (size_t)((int64_t)to_insert.length * padded_item_size)); + p += (int64_t)to_insert.length * padded_item_size; } else { for (int64_t i = 0; i < index - 1; i++) { memcpy(p, to_insert.data + to_insert.stride * i, (size_t)padded_item_size); @@ -149,19 +152,19 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa } // Copy last chunk of `list` if needed: - if (index < list->length + 1) { + if (index < (int64_t)list->length + 1) { if (list->stride == padded_item_size) { memcpy(p, list->data + padded_item_size * (index - 1), - (size_t)((list->length - index + 1) * padded_item_size)); - p += (list->length - index + 1) * padded_item_size; + (size_t)(((int64_t)list->length - index + 1) * padded_item_size)); + p += ((int64_t)list->length - index + 1) * padded_item_size; } else { - for (int64_t i = index - 1; i < list->length - 1; i++) { + for (int64_t i = index - 1; i < (int64_t)list->length - 1; i++) { memcpy(p, list->data + list->stride * i, (size_t)padded_item_size); p += padded_item_size; } } } - list->length = new_len; + list->length = (uint64_t)new_len; list->stride = padded_item_size; list->data = data; list->data_refcount = 0; @@ -171,20 +174,20 @@ void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t pa public void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padded_item_size) { int64_t index = Int64$from_int(int_index, false); - if (index < 1) index = list->length + index + 1; + if (index < 1) index = (int64_t)list->length + index + 1; int64_t count = Int64$from_int(int_count, false); if (index < 1 || index > (int64_t)list->length || count < 1) return; - if (count > list->length - index + 1) count = (list->length - index) + 1; + if (count > (int64_t)list->length - index + 1) count = ((int64_t)list->length - index) + 1; if (index == 1) { list->data += list->stride * count; - } else if (index + count > list->length) { + } else if (index + count > (int64_t)list->length) { list->free += count; } else if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) { - void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)((list->length - 1) * padded_item_size)) - : GC_MALLOC((size_t)((list->length - 1) * padded_item_size)); + void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)(((int64_t)list->length - 1) * padded_item_size)) + : GC_MALLOC((size_t)(((int64_t)list->length - 1) * padded_item_size)); for (int64_t src = 1, dest = 1; src <= (int64_t)list->length; src++) { if (src < index || src >= index + count) { memcpy(copy + (dest - 1) * padded_item_size, list->data + list->stride * (src - 1), @@ -198,10 +201,10 @@ void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padd } else { memmove((void *)list->data + (index - 1) * padded_item_size, list->data + (index - 1 + count) * padded_item_size, - (size_t)((list->length - index + count - 1) * padded_item_size)); + (size_t)(((int64_t)list->length - index + count - 1) * padded_item_size)); list->free += count; } - list->length -= count; + list->length -= (uint64_t)count; if (list->length == 0) list->data = NULL; } @@ -211,7 +214,7 @@ void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeIn const Int_t ZERO = (Int_t){.small = (0 << 2) | 1}; const Int_t ONE = (Int_t){.small = (1 << 2) | 1}; const TypeInfo_t *item_type = type->ListInfo.item; - for (int64_t i = 0; i < list->length;) { + for (int64_t i = 0; i < (int64_t)list->length;) { if (max_removals.small == ZERO.small) // zero break; @@ -227,7 +230,7 @@ void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeIn public OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type) { const TypeInfo_t *item_type = type->ListInfo.item; - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { if (generic_equal(item, list.data + i * list.stride, item_type)) return I(i + 1); } return NONE_INT; @@ -236,7 +239,7 @@ OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type) { public OptionalInt_t List$first(List_t list, Closure_t predicate) { bool (*is_good)(void *, void *) = (void *)predicate.fn; - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { if (is_good(list.data + i * list.stride, predicate.userdata)) return I(i + 1); } return NONE_INT; @@ -300,9 +303,9 @@ void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_i typedef int64_t (*rng_fn_t)(int64_t, int64_t, void *); rng_fn_t rng_fn = random_int64.fn ? (rng_fn_t)random_int64.fn : _default_random_int64; char tmp[padded_item_size]; - for (int64_t i = list->length - 1; i > 1; i--) { + for (int64_t i = (int64_t)list->length - 1; i > 1; i--) { int64_t j = rng_fn(0, i, random_int64.userdata); - if unlikely (j < 0 || j > list->length - 1) + if unlikely (j < 0 || j > (int64_t)list->length - 1) fail("The provided random number function returned an invalid value: ", j, " (not between 0 and ", i, ")"); memcpy(tmp, list->data + i * padded_item_size, (size_t)padded_item_size); memcpy((void *)list->data + i * padded_item_size, list->data + j * padded_item_size, (size_t)padded_item_size); @@ -323,8 +326,8 @@ void *List$random(List_t list, OptionalClosure_t random_int64) { typedef int64_t (*rng_fn_t)(int64_t, int64_t, void *); rng_fn_t rng_fn = random_int64.fn ? (rng_fn_t)random_int64.fn : _default_random_int64; - int64_t index = rng_fn(0, list.length - 1, random_int64.userdata); - if unlikely (index < 0 || index > list.length - 1) + int64_t index = rng_fn(0, (int64_t)list.length - 1, random_int64.userdata); + if unlikely (index < 0 || index > (int64_t)list.length - 1) fail("The provided random number function returned an invalid value: ", index, " (not between 0 and ", (int64_t)list.length, ")"); return list.data + list.stride * index; @@ -332,9 +335,9 @@ void *List$random(List_t list, OptionalClosure_t random_int64) { public Table_t List$counts(List_t list, const TypeInfo_t *type) { - Table_t counts = {}; + Table_t counts = EMPTY_TABLE; const TypeInfo_t count_type = *Table$info(type->ListInfo.item, &Int$info); - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { void *key = list.data + i * list.stride; int64_t *count = Table$get(counts, key, &count_type); int64_t val = count ? *count + 1 : 1; @@ -362,7 +365,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r int64_t n = Int64$from_int(int_n, false); if (n < 0) fail("Cannot select a negative number of values"); - if (n == 0) return (List_t){}; + if (n == 0) return EMPTY_LIST; if (list.length == 0) fail("There are no elements in this list!"); @@ -370,7 +373,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r fail("List has ", (int64_t)list.length, " elements, but there are ", (int64_t)weights.length, " weights given"); double total = 0.0; - for (int64_t i = 0; i < weights.length && i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)weights.length && i < (int64_t)list.length; i++) { double weight = *(double *)(weights.data + weights.stride * i); if (isinf(weight)) fail("Infinite weight!"); else if (isnan(weight)) fail("NaN weight!"); @@ -389,19 +392,19 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r double odds; } aliases[list.length]; - for (int64_t i = 0; i < list.length; i++) { - double weight = i >= weights.length ? 0.0 : *(double *)(weights.data + weights.stride * i); + for (int64_t i = 0; i < (int64_t)list.length; i++) { + double weight = i >= (int64_t)weights.length ? 0.0 : *(double *)(weights.data + weights.stride * i); aliases[i].odds = weight * inverse_average; aliases[i].alias = -1; } int64_t small = 0; - for (int64_t big = 0; big < list.length; big++) { + for (int64_t big = 0; big < (int64_t)list.length; big++) { while (aliases[big].odds >= 1.0) { - while (small < list.length && (aliases[small].odds >= 1.0 || aliases[small].alias != -1)) + while (small < (int64_t)list.length && (aliases[small].odds >= 1.0 || aliases[small].alias != -1)) ++small; - if (small >= list.length) { + if (small >= (int64_t)list.length) { aliases[big].odds = 1.0; aliases[big].alias = big; break; @@ -413,7 +416,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r if (big < small) small = big; } - for (int64_t i = small; i < list.length; i++) + for (int64_t i = small; i < (int64_t)list.length; i++) if (aliases[i].alias == -1) aliases[i].alias = i; typedef double (*rng_fn_t)(void *); @@ -421,7 +424,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r List_t selected = {.data = list.atomic ? GC_MALLOC_ATOMIC((size_t)(n * padded_item_size)) : GC_MALLOC((size_t)(n * padded_item_size)), - .length = n, + .length = (uint64_t)n, .stride = padded_item_size, .atomic = list.atomic}; for (int64_t i = 0; i < n; i++) { @@ -430,7 +433,7 @@ List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t r fail("The random number function returned a value not between 0.0 (inclusive) and 1.0 (exclusive): ", r); r *= (double)list.length; int64_t index = (int64_t)r; - assert(index >= 0 && index < list.length); + assert(index >= 0 && index < (int64_t)list.length); if ((r - (double)index) > aliases[index].odds) index = aliases[index].alias; memcpy(selected.data + i * selected.stride, list.data + index * list.stride, (size_t)padded_item_size); } @@ -449,29 +452,29 @@ List_t List$by(List_t list, Int_t int_stride, int64_t padded_item_size) { // In the unlikely event that the stride value would be too large to fit in // a 15-bit integer, fall back to creating a copy of the list: if (unlikely(list.stride * stride < LIST_MIN_STRIDE || list.stride * stride > LIST_MAX_STRIDE)) { - void *copy = NULL; - int64_t len = (stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0); - if (len > 0) { - copy = list.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size)) - : GC_MALLOC((size_t)(len * padded_item_size)); - void *start = (stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data); - for (int64_t i = 0; i < len; i++) - memcpy(copy + i * padded_item_size, start + list.stride * stride * i, (size_t)padded_item_size); - } + int64_t len = (stride < 0 ? (int64_t)list.length / -stride : (int64_t)list.length / stride) + + (((int64_t)list.length % stride) != 0); + if (len <= 0) return list.atomic ? EMPTY_ATOMIC_LIST : EMPTY_LIST; + void *copy = list.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size)) + : GC_MALLOC((size_t)(len * padded_item_size)); + void *start = (stride < 0 ? list.data + (list.stride * ((int64_t)list.length - 1)) : list.data); + for (int64_t i = 0; i < len; i++) + memcpy(copy + i * padded_item_size, start + list.stride * stride * i, (size_t)padded_item_size); return (List_t){ .data = copy, - .length = len, + .length = (uint64_t)len, .stride = padded_item_size, .atomic = list.atomic, }; } - if (stride == 0) return (List_t){.atomic = list.atomic}; + if (stride == 0) return list.atomic ? EMPTY_ATOMIC_LIST : EMPTY_LIST; return (List_t){ .atomic = list.atomic, - .data = (stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data), - .length = (stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0), + .data = (stride < 0 ? list.data + (list.stride * ((int64_t)list.length - 1)) : list.data), + .length = (uint64_t)((stride < 0 ? (int64_t)list.length / -stride : (int64_t)list.length / stride) + + (((int64_t)list.length % stride) != 0)), .stride = list.stride * stride, .data_refcount = list.data_refcount, }; @@ -482,19 +485,19 @@ List_t List$slice(List_t list, Int_t int_first, Int_t int_last) { int64_t first = Int64$from_int(int_first, false); - if (first < 0) first = list.length + first + 1; + if (first < 0) first = (int64_t)list.length + first + 1; int64_t last = Int64$from_int(int_last, false); - if (last < 0) last = list.length + last + 1; + if (last < 0) last = (int64_t)list.length + last + 1; - if (last > list.length) last = list.length; + if (last > (int64_t)list.length) last = (int64_t)list.length; - if (first < 1 || first > list.length || last == 0) return (List_t){.atomic = list.atomic}; + if (first < 1 || first > (int64_t)list.length || last == 0) return EMPTY_ATOMIC_LIST; return (List_t){ .atomic = list.atomic, .data = list.data + list.stride * (first - 1), - .length = last - first + 1, + .length = (uint64_t)(last - first + 1), .stride = list.stride, .data_refcount = list.data_refcount, }; @@ -511,26 +514,26 @@ List_t List$reversed(List_t list, int64_t padded_item_size) { List_t reversed = list; reversed.stride = -list.stride; - reversed.data = list.data + (list.length - 1) * list.stride; + reversed.data = list.data + ((int64_t)list.length - 1) * list.stride; return reversed; } public List_t List$concat(List_t x, List_t y, int64_t padded_item_size) { - void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size * (x.length + y.length))) - : GC_MALLOC((size_t)(padded_item_size * (x.length + y.length))); + void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size * (int64_t)(x.length + y.length))) + : GC_MALLOC((size_t)(padded_item_size * (int64_t)(x.length + y.length))); if (x.stride == padded_item_size) { - memcpy(data, x.data, (size_t)(padded_item_size * x.length)); + memcpy(data, x.data, (size_t)(padded_item_size * (int64_t)x.length)); } else { - for (int64_t i = 0; i < x.length; i++) + for (int64_t i = 0; i < (int64_t)x.length; i++) memcpy(data + i * padded_item_size, x.data + i * padded_item_size, (size_t)padded_item_size); } - void *dest = data + padded_item_size * x.length; + void *dest = data + padded_item_size * (int64_t)x.length; if (y.stride == padded_item_size) { - memcpy(dest, y.data, (size_t)(padded_item_size * y.length)); + memcpy(dest, y.data, (size_t)(padded_item_size * (int64_t)y.length)); } else { - for (int64_t i = 0; i < y.length; i++) + for (int64_t i = 0; i < (int64_t)y.length; i++) memcpy(dest + i * padded_item_size, y.data + i * y.stride, (size_t)padded_item_size); } @@ -545,14 +548,14 @@ List_t List$concat(List_t x, List_t y, int64_t padded_item_size) { public bool List$has(List_t list, void *item, const TypeInfo_t *type) { const TypeInfo_t *item_type = type->ListInfo.item; - for (int64_t i = 0; i < list.length; i++) { + for (int64_t i = 0; i < (int64_t)list.length; i++) { if (generic_equal(list.data + i * list.stride, item, item_type)) return true; } return false; } public -void List$clear(List_t *list) { *list = (List_t){.data = 0, .length = 0}; } +void List$clear(List_t *list) { *list = list->atomic ? EMPTY_ATOMIC_LIST : EMPTY_LIST; } public int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) { @@ -568,7 +571,8 @@ int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) { if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size && item->size == item_padded_size) { - int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length) * item_padded_size)); + int32_t cmp = (int32_t)memcmp(x->data, y->data, + (size_t)(MIN((int64_t)x->length, (int64_t)y->length) * item_padded_size)); if (cmp != 0) return cmp; } else { for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) { @@ -597,7 +601,7 @@ Text_t List$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { const TypeInfo_t *item_type = type->ListInfo.item; Text_t text = Text("["); - for (int64_t i = 0; i < list->length; i++) { + for (int64_t i = 0; i < (int64_t)list->length; i++) { if (i > 0) text = Text$concat(text, Text(", ")); Text_t item_text = generic_as_text(list->data + i * list->stride, colorize, item_type); text = Text$concat(text, item_text); @@ -613,10 +617,10 @@ uint64_t List$hash(const void *obj, const TypeInfo_t *type) { siphash sh; siphashinit(&sh, sizeof(uint64_t[list->length])); if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void *))) { // Raw data hash - for (int64_t i = 0; i < list->length; i++) + for (int64_t i = 0; i < (int64_t)list->length; i++) siphashadd64bits(&sh, (uint64_t)(list->data + i * list->stride)); } else { - for (int64_t i = 0; i < list->length; i++) { + for (int64_t i = 0; i < (int64_t)list->length; i++) { uint64_t item_hash = generic_hash(list->data + i * list->stride, item); siphashadd64bits(&sh, item_hash); } @@ -625,7 +629,7 @@ uint64_t List$hash(const void *obj, const TypeInfo_t *type) { } static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comparison, int64_t padded_item_size) { - assert(pos > 0 && pos < heap->length); + assert(pos > 0 && pos < (int64_t)heap->length); char newitem[padded_item_size]; memcpy(newitem, heap->data + heap->stride * pos, (size_t)(padded_item_size)); while (pos > startpos) { @@ -641,7 +645,7 @@ static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comp } static void siftup(List_t *heap, int64_t pos, Closure_t comparison, int64_t padded_item_size) { - int64_t endpos = heap->length; + int64_t endpos = (int64_t)heap->length; int64_t startpos = pos; assert(pos < endpos); @@ -673,7 +677,7 @@ void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_ if (heap->length > 1) { if (heap->data_refcount != 0) List$compact(heap, padded_item_size); - siftdown(heap, 0, heap->length - 1, comparison, padded_item_size); + siftdown(heap, 0, (int64_t)heap->length - 1, comparison, padded_item_size); } } @@ -682,13 +686,13 @@ void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size) if (heap->length == 0) fail("Attempt to pop from an empty list"); if (heap->length == 1) { - *heap = (List_t){}; + *heap = EMPTY_LIST; } else if (heap->length == 2) { heap->data += heap->stride; --heap->length; } else { if (heap->data_refcount != 0) List$compact(heap, padded_item_size); - memcpy(heap->data, heap->data + heap->stride * (heap->length - 1), (size_t)(padded_item_size)); + memcpy(heap->data, heap->data + heap->stride * ((int64_t)heap->length - 1), (size_t)(padded_item_size)); --heap->length; siftup(heap, 0, comparison, padded_item_size); } @@ -701,7 +705,7 @@ void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) // It's necessary to bump the refcount because the user's comparison // function could do stuff that modifies the heap's data. LIST_INCREF(*heap); - int64_t i, n = heap->length; + int64_t i, n = (int64_t)heap->length; for (i = (n >> 1) - 1; i >= 0; i--) siftup(heap, i, comparison, padded_item_size); LIST_DECREF(*heap); @@ -710,7 +714,7 @@ void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) public Int_t List$binary_search(List_t list, void *target, Closure_t comparison) { typedef int32_t (*cmp_fn_t)(void *, void *, void *); - int64_t lo = 0, hi = list.length - 1; + int64_t lo = 0, hi = (int64_t)list.length - 1; while (lo <= hi) { int64_t mid = (lo + hi) / 2; int32_t cmp = ((cmp_fn_t)comparison.fn)(list.data + list.stride * mid, target, comparison.userdata); @@ -724,13 +728,13 @@ Int_t List$binary_search(List_t list, void *target, Closure_t comparison) { public PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *info) { (void)info; - return ((List_t *)obj)->length < 0; + return ((List_t *)obj)->data == NULL; } public void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { List_t list = *(List_t *)obj; - int64_t len = list.length; + int64_t len = (int64_t)list.length; Int64$serialize(&len, out, pointers, &Int64$info); serialize_fn_t item_serialize = type->ListInfo.item->metamethods.serialize; if (item_serialize) { @@ -752,7 +756,7 @@ void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *t if (type->ListInfo.item->align > 0 && padded_size % type->ListInfo.item->align > 0) padded_size += type->ListInfo.item->align - (padded_size % type->ListInfo.item->align); List_t list = { - .length = len, + .length = (uint64_t)len, .data = GC_MALLOC((size_t)(len * padded_size)), .stride = padded_size, }; diff --git a/src/stdlib/lists.h b/src/stdlib/lists.h index 1386b2fa..457fed52 100644 --- a/src/stdlib/lists.h +++ b/src/stdlib/lists.h @@ -9,6 +9,10 @@ #include "types.h" #include "util.h" +extern char _EMPTY_LIST_SENTINEL; +#define EMPTY_LIST ((List_t){.data = &_EMPTY_LIST_SENTINEL}) +#define EMPTY_ATOMIC_LIST ((List_t){.data = &_EMPTY_LIST_SENTINEL, .atomic = 1}) + // Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1 #define List_get_checked(list_expr, index_expr, item_type, start, end) \ ({ \ diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c index 6161918c..3eff2dd3 100644 --- a/src/stdlib/metamethods.c +++ b/src/stdlib/metamethods.c @@ -6,6 +6,7 @@ #include "lists.h" #include "metamethods.h" #include "siphash.h" +#include "tables.h" #include "types.h" #include "util.h" @@ -50,12 +51,12 @@ List_t generic_serialize(const void *x, const TypeInfo_t *type) { char *buf = NULL; size_t size = 0; FILE *stream = open_memstream(&buf, &size); - Table_t pointers = {}; + Table_t pointers = EMPTY_TABLE; _serialize(x, stream, &pointers, type); fclose(stream); List_t bytes = { .data = GC_MALLOC_ATOMIC(size), - .length = (int64_t)size, + .length = (uint64_t)size, .stride = 1, .atomic = 1, }; @@ -79,7 +80,7 @@ void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type) { if (bytes.stride != 1) List$compact(&bytes, 1); FILE *input = fmemopen(bytes.data, (size_t)bytes.length, "r"); - List_t pointers = {}; + List_t pointers = EMPTY_LIST; _deserialize(input, outval, &pointers, type); fclose(input); } diff --git a/src/stdlib/optionals.c b/src/stdlib/optionals.c index e9184e4d..41d38a19 100644 --- a/src/stdlib/optionals.c +++ b/src/stdlib/optionals.c @@ -64,8 +64,8 @@ void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeIn _deserialize(in, outval, pointers, nonnull); } else { if (nonnull->tag == TextInfo) *(Text_t *)outval = NONE_TEXT; - else if (nonnull->tag == ListInfo) *(List_t *)outval = (List_t){.length = -1}; - else if (nonnull->tag == TableInfo) *(Table_t *)outval = (Table_t){.entries = {.length = -1}}; + else if (nonnull->tag == ListInfo) *(List_t *)outval = NONE_LIST; + else if (nonnull->tag == TableInfo) *(Table_t *)outval = NONE_TABLE; else if (nonnull == &Num$info) *(double *)outval = (double)NAN; else if (nonnull == &Num32$info) *(float *)outval = (float)NAN; else if (nonnull->tag == StructInfo || (nonnull->tag == OpaqueInfo && type->size > nonnull->size)) diff --git a/src/stdlib/optionals.h b/src/stdlib/optionals.h index 145fda60..9c875bd1 100644 --- a/src/stdlib/optionals.h +++ b/src/stdlib/optionals.h @@ -9,12 +9,12 @@ #include "types.h" #include "util.h" -#define NONE_LIST ((List_t){.length = -1}) +#define NONE_LIST ((List_t){.data = NULL}) #define NONE_BOOL ((OptionalBool_t)2) #define NONE_INT ((OptionalInt_t){.small = 0}) -#define NONE_TABLE ((OptionalTable_t){.entries.length = -1}) +#define NONE_TABLE ((OptionalTable_t){.entries.data = NULL}) #define NONE_CLOSURE ((OptionalClosure_t){.fn = NULL}) -#define NONE_TEXT ((OptionalText_t){.length = -1}) +#define NONE_TEXT ((OptionalText_t){.tag = TEXT_NONE}) #define NONE_PATH ((Path_t){.type = PATH_NONE}) PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type); diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c index 385f3bdf..6db51e41 100644 --- a/src/stdlib/paths.c +++ b/src/stdlib/paths.c @@ -36,7 +36,7 @@ static const Path_t HOME_PATH = {.type.$tag = PATH_HOME}, ROOT_PATH = {.type.$ta CURDIR_PATH = {.type.$tag = PATH_RELATIVE}; static void clean_components(List_t *components) { - for (int64_t i = 0; i < components->length;) { + for (int64_t i = 0; i < (int64_t)components->length;) { Text_t *component = (Text_t *)(components->data + i * components->stride); if (component->length == 0 || Text$equal_values(*component, Text("."))) { List$remove_at(components, I(i + 1), I(1), sizeof(Text_t)); @@ -83,10 +83,11 @@ Path_t Path$from_str(const char *str) { // ignore /./ } else if (component_len == 2 && strncmp(str, "..", 2) == 0 && result.components.length > 1 && !Text$equal_values( - Text(".."), *(Text_t *)(result.components.data - + result.components.stride * (result.components.length - 1)))) { + Text(".."), + *(Text_t *)(result.components.data + + result.components.stride * ((int64_t)result.components.length - 1)))) { // Pop off /foo/baz/.. -> /foo - List$remove_at(&result.components, I(result.components.length), I(1), sizeof(Text_t)); + List$remove_at(&result.components, I((int64_t)result.components.length), I(1), sizeof(Text_t)); } else { Text_t component = Text$from_strn(str, component_len); List$insert_value(&result.components, component, I(0), sizeof(Text_t)); @@ -149,16 +150,16 @@ Path_t Path$relative_to(Path_t path, Path_t relative_to) { Path_t result = {.type.$tag = PATH_RELATIVE}; int64_t shared = 0; - for (; shared < path.components.length && shared < relative_to.components.length; shared++) { + for (; shared < (int64_t)path.components.length && shared < (int64_t)relative_to.components.length; shared++) { Text_t *p = (Text_t *)(path.components.data + shared * path.components.stride); Text_t *r = (Text_t *)(relative_to.components.data + shared * relative_to.components.stride); if (!Text$equal_values(*p, *r)) break; } - for (int64_t i = shared; i < relative_to.components.length; i++) + for (int64_t i = shared; i < (int64_t)relative_to.components.length; i++) List$insert_value(&result.components, Text(".."), I(1), sizeof(Text_t)); - for (int64_t i = shared; i < path.components.length; i++) { + for (int64_t i = shared; i < (int64_t)path.components.length; i++) { Text_t *p = (Text_t *)(path.components.data + i * path.components.stride); List$insert(&result.components, p, I(0), sizeof(Text_t)); } @@ -331,7 +332,7 @@ OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) { if (count.small && (int64_t)sb.st_size < target_count) fail("Could not read ", target_count, " bytes from ", path, " (only got ", (uint64_t)sb.st_size, ")"); int64_t len = count.small ? target_count : (int64_t)sb.st_size; - return (List_t){.data = content, .atomic = 1, .stride = 1, .length = len}; + return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (uint64_t)len}; } else { size_t capacity = 256, len = 0; char *content = GC_MALLOC_ATOMIC(capacity); @@ -359,14 +360,14 @@ OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) { close(fd); if (count.small != 0 && (int64_t)len < target_count) fail("Could not read ", target_count, " bytes from ", path, " (only got ", (uint64_t)len, ")"); - return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (int64_t)len}; + return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (uint64_t)len}; } } public OptionalText_t Path$read(Path_t path) { List_t bytes = Path$read_bytes(path, NONE_INT); - if (bytes.length < 0) return NONE_TEXT; + if (bytes.data == NULL) return NONE_TEXT; return Text$from_utf8(bytes); } @@ -391,14 +392,14 @@ OptionalText_t Path$group(Path_t path, bool follow_symlinks) { public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t group, bool follow_symlinks) { uid_t owner_id = (uid_t)-1; - if (owner.length >= 0) { + if (owner.tag == TEXT_NONE) { struct passwd *pwd = getpwnam(Text$as_c_string(owner)); if (pwd == NULL) fail("Not a valid user: ", owner); owner_id = pwd->pw_uid; } gid_t group_id = (gid_t)-1; - if (group.length >= 0) { + if (group.tag == TEXT_NONE) { struct group *grp = getgrnam(Text$as_c_string(group)); if (grp == NULL) fail("Not a valid group: ", group); group_id = grp->gr_gid; @@ -459,7 +460,7 @@ void Path$create_directory(Path_t path, int permissions) { static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter) { path = Path$expand_home(path); struct dirent *dir; - List_t children = {}; + List_t children = EMPTY_LIST; const char *path_str = Path$as_c_string(path); size_t path_len = strlen(path_str); DIR *d = opendir(path_str); @@ -545,7 +546,7 @@ Path_t Path$parent(Path_t path) { return path; } else if (path.components.length > 0 && !Text$equal_values( - *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)), + *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)), Text(".."))) { return (Path_t){.type.$tag = path.type.$tag, .components = List$slice(path.components, I(1), I(-2))}; } else { @@ -559,7 +560,7 @@ Path_t Path$parent(Path_t path) { public PUREFUNC Text_t Path$base_name(Path_t path) { if (path.components.length >= 1) - return *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)); + return *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)); else if (path.type.$tag == PATH_HOME) return Text("~"); else if (path.type.$tag == PATH_RELATIVE) return Text("."); else return EMPTY_TEXT; @@ -577,7 +578,7 @@ public bool Path$has_extension(Path_t path, Text_t extension) { if (path.components.length < 2) return extension.length == 0; - Text_t last = *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)); + Text_t last = *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)); if (extension.length == 0) return !Text$has(Text$from(last, I(2)), Text(".")) || Text$equal_values(last, Text("..")); @@ -615,7 +616,7 @@ Path_t Path$with_extension(Path_t path, Text_t extension, bool replace) { .components = path.components, }; LIST_INCREF(result.components); - Text_t last = *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)); + Text_t last = *(Text_t *)(path.components.data + path.components.stride * ((int64_t)path.components.length - 1)); List$remove_at(&result.components, I(-1), I(1), sizeof(Text_t)); if (replace) { const char *base = Text$as_c_string(last); @@ -675,7 +676,7 @@ List_t Path$glob(Path_t path) { int status = glob(Path$as_c_string(path), GLOB_BRACE | GLOB_TILDE, NULL, &glob_result); if (status != 0 && status != GLOB_NOMATCH) fail("Failed to perform globbing"); - List_t glob_files = {}; + List_t glob_files = EMPTY_LIST; for (size_t i = 0; i < glob_result.gl_pathc; i++) { size_t len = strlen(glob_result.gl_pathv[i]); if ((len >= 2 && glob_result.gl_pathv[i][len - 1] == '.' && glob_result.gl_pathv[i][len - 2] == '/') @@ -701,7 +702,7 @@ PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type) { Path_t *path = (Path_t *)obj; siphash sh; siphashinit(&sh, (uint64_t)path->type.$tag); - for (int64_t i = 0; i < path->components.length; i++) { + for (int64_t i = 0; i < (int64_t)path->components.length; i++) { uint64_t item_hash = Text$hash(path->components.data + i * path->components.stride, &Text$info); siphashadd64bits(&sh, item_hash); } @@ -748,10 +749,10 @@ int Path$print(FILE *f, Path_t path) { if (!Text$equal_values(*(Text_t *)path.components.data, Text(".."))) n += fputs("./", f); } - for (int64_t i = 0; i < path.components.length; i++) { + for (int64_t i = 0; i < (int64_t)path.components.length; i++) { Text_t *comp = (Text_t *)(path.components.data + i * path.components.stride); n += Text$print(f, *comp); - if (i + 1 < path.components.length) n += fputc('/', f); + if (i + 1 < (int64_t)path.components.length) n += fputc('/', f); } return n; } diff --git a/src/stdlib/pointers.c b/src/stdlib/pointers.c index 0a1623a0..74037613 100644 --- a/src/stdlib/pointers.c +++ b/src/stdlib/pointers.c @@ -30,7 +30,7 @@ Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) { } static const void *root = NULL; - static Table_t pending = {}; + static Table_t pending = EMPTY_TABLE; bool top_level = (root == NULL); // Check for recursive references, so if `x.foo = x`, then it prints as @@ -47,7 +47,7 @@ Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) { Text_t text = Texts(Text$from_str(ptr_info.sigil), Int64$value_as_text(*id)); return colorize ? Texts(Text("\x1b[34;1m"), text, Text("\x1b[m")) : text; } - int64_t next_id = pending.entries.length + 2; + int64_t next_id = (int64_t)pending.entries.length + 2; Table$set(&pending, x, &next_id, &rec_table); } @@ -97,7 +97,7 @@ void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const Type if (id_ptr) { id = *id_ptr; } else { - id = pointers->entries.length + 1; + id = (int64_t)pointers->entries.length + 1; Table$set(pointers, &ptr, &id, &ptr_to_int_table); } @@ -112,7 +112,7 @@ void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInf Int64$deserialize(in, &id, pointers, &Int64$info); assert(id != 0); - if (id > pointers->length) { + if (id > (int64_t)pointers->length) { void *obj = GC_MALLOC((size_t)type->PointerInfo.pointed->size); List$insert(pointers, &obj, I(0), sizeof(void *)); _deserialize(in, obj, pointers, type->PointerInfo.pointed); diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c index 6698dea3..c093e4c2 100644 --- a/src/stdlib/tables.c +++ b/src/stdlib/tables.c @@ -187,7 +187,7 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type t->bucket_info->count = new_capacity; t->bucket_info->last_free = new_capacity - 1; // Rehash: - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { hdebug("Rehashing ", i, "\n"); Table$set_bucket(t, GET_ENTRY(*t, i), i, type); } @@ -252,7 +252,7 @@ void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeIn else if (value_size > 0) memset(buf + value_offset(type), 0, (size_t)value_size); List$insert(&t->entries, buf, I(0), (int64_t)entry_size(type)); - int64_t entry_index = t->entries.length - 1; + int64_t entry_index = (int64_t)t->entries.length - 1; void *entry = GET_ENTRY(*t, entry_index); Table$set_bucket(t, entry, entry_index, type); return entry + value_offset(type); @@ -276,7 +276,7 @@ void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) { maybe_copy_on_write(t, type); // If unspecified, pop the last key: - if (!key) key = GET_ENTRY(*t, t->entries.length - 1); + if (!key) key = GET_ENTRY(*t, (int64_t)t->entries.length - 1); // Steps: look up the bucket for the removed key // If missing, then return immediately @@ -316,7 +316,7 @@ found_it:; // swap the other entry into the last position and then remove the last // entry. This disturbs the ordering of the table, but keeps removal O(1) // instead of O(N) - int64_t last_entry = t->entries.length - 1; + int64_t last_entry = (int64_t)t->entries.length - 1; if (bucket->index != last_entry) { hdebug("Removing key/value from the middle of the entries list\n"); @@ -336,7 +336,7 @@ found_it:; // Last entry is being removed, so clear it out to be safe: memset(GET_ENTRY(*t, last_entry), 0, entry_size(type)); - List$remove_at(&t->entries, I(t->entries.length), I(1), (int64_t)entry_size(type)); + List$remove_at(&t->entries, I((int64_t)t->entries.length), I(1), (int64_t)entry_size(type)); int64_t bucket_to_clear; if (prev) { // Middle (or end) of a chain @@ -359,7 +359,7 @@ found_it:; } CONSTFUNC public void *Table$entry(Table_t t, int64_t n) { - if (n < 1 || n > Table$length(t)) return NULL; + if (n < 1 || n > (int64_t)Table$length(t)) return NULL; return GET_ENTRY(t, n - 1); } @@ -386,7 +386,7 @@ PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_ const TypeInfo_t *value_type = type->TableInfo.value; size_t offset = value_offset(type); - for (int64_t i = 0; i < x->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)x->entries.length; i++) { void *x_key = x->entries.data + i * x->entries.stride; void *y_value = Table$get_raw(*y, x_key, type); if (!y_value) return false; @@ -418,7 +418,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // `x[k] != y[k]`, as well as the largest key in `x` and `y`. void *mismatched_key = NULL, *max_x_key = NULL; - for (int64_t i = 0; i < x->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)x->entries.length; i++) { void *key = x->entries.data + x->entries.stride * i; if (max_x_key == NULL || generic_compare(key, max_x_key, table.key) > 0) max_x_key = key; @@ -433,7 +433,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // If the keys are not all equal, we gotta check to see if there exists a // `y[k]` such that `k` is smaller than all keys that `x` has and `y` doesn't: void *max_y_key = NULL; - for (int64_t i = 0; i < y->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)y->entries.length; i++) { void *key = y->entries.data + y->entries.stride * i; if (max_y_key == NULL || generic_compare(key, max_y_key, table.key) > 0) max_y_key = key; @@ -474,7 +474,7 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type // Assuming keys are the same, compare values: if (table.value->size > 0) { - for (int64_t i = 0; i < x->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)x->entries.length; i++) { void *key = x->entries.data + x->entries.stride * i; void *x_value = key + value_offset(type); void *y_value = Table$get_raw(*y, key, type); @@ -504,12 +504,12 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) { uint64_t keys_hash = 0, values_hash = 0; size_t offset = value_offset(type); if (table.value->size > 0) { - for (int64_t i = 0; i < t->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)t->entries.length; i++) { keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key); values_hash ^= generic_hash(t->entries.data + i * t->entries.stride + offset, table.value); } } else { - for (int64_t i = 0; i < t->entries.length; i++) + for (int64_t i = 0; i < (int64_t)t->entries.length; i++) keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key); } @@ -517,7 +517,7 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) { int64_t length; uint64_t keys_hash, values_hash, fallback_hash; } components = { - t->entries.length, + (int64_t)t->entries.length, keys_hash, values_hash, t->fallback ? Table$hash(t->fallback, type) : 0, @@ -540,7 +540,7 @@ Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type) { int64_t val_off = (int64_t)value_offset(type); Text_t text = Text("{"); - for (int64_t i = 0, length = Table$length(*t); i < length; i++) { + for (int64_t i = 0, length = (int64_t)Table$length(*t); i < length; i++) { if (i > 0) text = Text$concat(text, Text(", ")); void *entry = GET_ENTRY(*t, i); text = Text$concat(text, generic_as_text(entry, colorize, table.key)); @@ -561,8 +561,8 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { assert(type->tag == TableInfo); if (entries.length == 0) return (Table_t){}; - Table_t t = {}; - int64_t length = entries.length + entries.length / 4; + Table_t t = EMPTY_TABLE; + int64_t length = (int64_t)entries.length + (int64_t)entries.length / 4; size_t alloc_size = sizeof(bucket_info_t) + sizeof(bucket_t[length]); t.bucket_info = GC_MALLOC_ATOMIC(alloc_size); memset(t.bucket_info->buckets, 0, sizeof(bucket_t[length])); @@ -570,7 +570,7 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { t.bucket_info->last_free = length - 1; size_t offset = value_offset(type); - for (int64_t i = 0; i < entries.length; i++) { + for (int64_t i = 0; i < (int64_t)entries.length; i++) { void *key = entries.data + i * entries.stride; Table$set(&t, key, key + offset, type); } @@ -581,10 +581,10 @@ Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) { public Table_t Table$intersection(Table_t a, Table_t b, const TypeInfo_t *type) { // Return a table such that t[k]==a[k] for all k such that a.has(k), b.has(k), and a[k]==b[k] - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); void *a_value = key + offset; void *b_value = Table$get(b, key, type); @@ -600,16 +600,16 @@ public Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) { // return a table such that t[k]==b[k] for all k such that b.has(k), and t[k]==a[k] for all k such that a.has(k) and // not b.has(k) - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); Table$set(&result, key, key + offset, type); } } for (Table_t *t = &b; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); Table$set(&result, key, key + offset, type); } @@ -621,16 +621,16 @@ Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) { public Table_t Table$difference(Table_t a, Table_t b, const TypeInfo_t *type) { // return a table with elements in `a` or `b`, but not both - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); if (Table$get(b, key, type) == NULL) Table$set(&result, key, key + offset, type); } } for (Table_t *t = &b; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); if (Table$get(a, key, type) == NULL) Table$set(&result, key, key + offset, type); } @@ -642,10 +642,10 @@ Table_t Table$difference(Table_t a, Table_t b, const TypeInfo_t *type) { public Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type) { // Return a table such that t[k]==a[k] for all k such that not b.has(k) or b[k] != a[k] - Table_t result = {}; + Table_t result = EMPTY_TABLE; const size_t offset = value_offset(type); for (Table_t *t = &a; t; t = t->fallback) { - for (int64_t i = 0; i < Table$length(*t); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(*t); i++) { void *key = GET_ENTRY(*t, i); void *a_value = key + offset; void *b_value = Table$get(b, key, type); @@ -672,7 +672,7 @@ Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback) { PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type) { if (a.entries.length > b.entries.length || (strict && a.entries.length == b.entries.length)) return false; - for (int64_t i = 0; i < Table$length(a); i++) { + for (int64_t i = 0; i < (int64_t)Table$length(a); i++) { void *found = Table$get_raw(b, GET_ENTRY(a, i), type); if (!found) return false; } @@ -708,13 +708,13 @@ CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n) { return Table$entr PUREFUNC public bool Table$is_none(const void *obj, const TypeInfo_t *info) { (void)info; - return ((Table_t *)obj)->entries.length < 0; + return ((Table_t *)obj)->entries.data == NULL; } public void Table$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) { Table_t *t = (Table_t *)obj; - int64_t len = t->entries.length; + int64_t len = (int64_t)t->entries.length; Int64$serialize(&len, out, pointers, &Int64$info); size_t offset = value_offset(type); @@ -737,7 +737,7 @@ void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_ int64_t len; Int64$deserialize(in, &len, pointers, &Int$info); - Table_t t = {}; + Table_t t = EMPTY_TABLE; for (int64_t i = 0; i < len; i++) { char key[type->TableInfo.key->size]; _deserialize(in, key, pointers, type->TableInfo.key); diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h index f4870f80..cc2b3b91 100644 --- a/src/stdlib/tables.h +++ b/src/stdlib/tables.h @@ -11,6 +11,8 @@ #include "types.h" #include "util.h" +#define EMPTY_TABLE ((Table_t){.entries.data = &_EMPTY_LIST_SENTINEL}) + #define Table(key_t, val_t, key_info, value_info, fb, N, ...) \ ({ \ struct { \ diff --git a/src/stdlib/text.c b/src/stdlib/text.c index cda7dd31..0f40aef9 100644 --- a/src/stdlib/text.c +++ b/src/stdlib/text.c @@ -127,7 +127,7 @@ typedef struct { } synthetic_grapheme_t; // Synthetic grapheme clusters (clusters of more than one codepoint): -static Table_t grapheme_ids_by_codepoints = {}; // ucs4_t* length-prefixed codepoints -> int32_t ID +static Table_t grapheme_ids_by_codepoints = EMPTY_TABLE; // ucs4_t* length-prefixed codepoints -> int32_t ID // This will hold a dynamically growing list of synthetic graphemes: static synthetic_grapheme_t *synthetic_graphemes = NULL; @@ -521,8 +521,7 @@ static Text_t concat2(Text_t a, Text_t b) { } OptionalText_t glue = - Text$from_utf32((List_t){.data = normalized, .length = (int64_t)norm_length, .stride = sizeof(ucs4_t)}); - assert(glue.length >= 0); + Text$from_utf32((List_t){.data = normalized, .length = (uint64_t)norm_length, .stride = sizeof(ucs4_t)}); if (normalized != norm_buf) free(normalized); @@ -743,14 +742,14 @@ static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters) { void *blob = GC_MALLOC_ATOMIC(blob_size); int32_t *map = blob; uint8_t *bytes = blob + sizeof(int32_t[unique_clusters.entries.length]); - for (int64_t i = 0; i < unique_clusters.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)unique_clusters.entries.length; i++) { struct { int32_t g; uint8_t b; } *entry = unique_clusters.entries.data + i * unique_clusters.entries.stride; map[entry->b] = entry->g; } - for (int64_t i = 0; i < graphemes.length; i++) { + for (int64_t i = 0; i < (int64_t)graphemes.length; i++) { int32_t g = *(int32_t *)(graphemes.data + i * graphemes.stride); uint8_t *byte = Table$get(unique_clusters, &g, Table$info(&Int32$info, &Byte$info)); assert(byte); @@ -785,8 +784,8 @@ OptionalText_t Text$from_strn(const char *str, size_t len) { } if (u8_check((uint8_t *)str, len) != NULL) return NONE_TEXT; - List_t graphemes = {}; - Table_t unique_clusters = {}; + List_t graphemes = EMPTY_LIST; + Table_t unique_clusters = EMPTY_TABLE; const uint8_t *pos = (const uint8_t *)str; const uint8_t *end = (const uint8_t *)&str[len]; // Iterate over grapheme clusters @@ -1138,7 +1137,7 @@ Text_t Text$translate(Text_t text, Table_t translations) { int64_t span_start = 0; List_t replacement_list = translations.entries; for (int64_t i = 0; i < text.length;) { - for (int64_t r = 0; r < replacement_list.length; r++) { + for (int64_t r = 0; r < (int64_t)replacement_list.length; r++) { struct { Text_t target, replacement; } *entry = replacement_list.data + r * replacement_list.stride; @@ -1194,7 +1193,7 @@ List_t Text$split(Text_t text, Text_t delimiters) { if (delimiters.length == 0) return Text$clusters(text); TextIter_t text_state = NEW_TEXT_ITER_STATE(text), delim_state = NEW_TEXT_ITER_STATE(delimiters); - List_t splits = {}; + List_t splits = EMPTY_LIST; for (int64_t i = 0; i < text.length;) { int64_t span_len = 0; while (i + span_len < text.length && !_matches(&text_state, &delim_state, i + span_len)) { @@ -1216,7 +1215,7 @@ List_t Text$split_any(Text_t text, Text_t delimiters) { if (delimiters.length == 0) return List(text); TextIter_t text_state = NEW_TEXT_ITER_STATE(text), delim_state = NEW_TEXT_ITER_STATE(delimiters); - List_t splits = {}; + List_t splits = EMPTY_LIST; for (int64_t i = 0; i < text.length;) { int64_t span_len = 0; while (i + span_len < text.length @@ -1370,8 +1369,7 @@ Text_t Text$upper(Text_t text, Text_t language) { uint32_t buf[out_len]; ucs4_t *upper = u32_toupper(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, buf, &out_len); OptionalText_t ret = - Text$from_utf32((List_t){.data = upper, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); - assert(ret.length >= 0); + Text$from_utf32((List_t){.data = upper, .length = (uint64_t)out_len, .stride = sizeof(int32_t)}); if (upper != buf) free(upper); return ret; } @@ -1386,8 +1384,7 @@ Text_t Text$lower(Text_t text, Text_t language) { uint32_t buf[out_len]; ucs4_t *lower = u32_tolower(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, buf, &out_len); OptionalText_t ret = - Text$from_utf32((List_t){.data = lower, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); - assert(ret.length >= 0); + Text$from_utf32((List_t){.data = lower, .length = (uint64_t)out_len, .stride = sizeof(int32_t)}); if (lower != buf) free(lower); return ret; } @@ -1402,8 +1399,7 @@ Text_t Text$title(Text_t text, Text_t language) { uint32_t buf[out_len]; ucs4_t *title = u32_totitle(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, buf, &out_len); OptionalText_t ret = - Text$from_utf32((List_t){.data = title, .length = (int64_t)out_len, .stride = sizeof(int32_t)}); - assert(ret.length >= 0); + Text$from_utf32((List_t){.data = title, .length = (uint64_t)out_len, .stride = sizeof(int32_t)}); if (title != buf) free(title); return ret; } @@ -1543,7 +1539,7 @@ Text_t Text$join(Text_t glue, List_t pieces) { if (pieces.length == 0) return EMPTY_TEXT; Text_t result = *(Text_t *)pieces.data; - for (int64_t i = 1; i < pieces.length; i++) { + for (int64_t i = 1; i < (int64_t)pieces.length; i++) { result = Text$concat(result, glue, *(Text_t *)(pieces.data + i * pieces.stride)); } return result; @@ -1551,8 +1547,8 @@ Text_t Text$join(Text_t glue, List_t pieces) { public List_t Text$clusters(Text_t text) { - List_t clusters = {}; - for (int64_t i = 1; i <= text.length; i++) { + List_t clusters = EMPTY_LIST; + for (int64_t i = 1; i <= (int64_t)text.length; i++) { Text_t cluster = Text$slice(text, I(i), I(i)); List$insert(&clusters, &cluster, I_small(0), sizeof(Text_t)); } @@ -1561,27 +1557,27 @@ List_t Text$clusters(Text_t text) { public List_t Text$utf8(Text_t text) { - if (text.length == 0) return (List_t){.atomic = 1}; - int64_t capacity = text.length; + if (text.length == 0) return EMPTY_ATOMIC_LIST; + int64_t capacity = (int64_t)text.length; Byte_t *buf = GC_MALLOC_ATOMIC(sizeof(Byte_t[capacity])); int64_t i = 0; u8_buf_append(text, &buf, &capacity, &i); return (List_t){ - .data = buf, .length = i, .stride = 1, .atomic = 1, .free = MIN(LIST_MAX_FREE_ENTRIES, capacity - i)}; + .data = buf, .length = (uint64_t)i, .stride = 1, .atomic = 1, .free = MIN(LIST_MAX_FREE_ENTRIES, capacity - i)}; } public List_t Text$utf16(Text_t text) { - if (text.length == 0) return (List_t){.atomic = 1}; + if (text.length == 0) return EMPTY_ATOMIC_LIST; List_t utf32 = Text$utf32(text); List_t utf16 = {.free = MIN(LIST_MAX_FREE_ENTRIES, (uint64_t)utf32.length), .atomic = 1}; utf16.data = GC_MALLOC_ATOMIC(sizeof(int32_t[utf16.free])); - for (int64_t i = 0; i < utf32.length; i++) { + for (int64_t i = 0; i < (int64_t)utf32.length; i++) { uint16_t u16_buf[4]; size_t u16_len = sizeof(u16_buf) / sizeof(u16_buf[0]); uint16_t *chunk_u16 = u32_to_u16(utf32.data + utf32.stride * i, 1, u16_buf, &u16_len); if (chunk_u16 == NULL) fail("Invalid codepoints encountered!"); - List$insert_all(&utf16, (List_t){.data = chunk_u16, .stride = sizeof(uint16_t), .length = (int64_t)u16_len}, + List$insert_all(&utf16, (List_t){.data = chunk_u16, .stride = sizeof(uint16_t), .length = (uint64_t)u16_len}, I(0), sizeof(uint16_t)); if (chunk_u16 != u16_buf) free(chunk_u16); } @@ -1590,10 +1586,10 @@ List_t Text$utf16(Text_t text) { public List_t Text$utf32(Text_t text) { - if (text.length == 0) return (List_t){.atomic = 1}; - List_t codepoints = {.atomic = 1}; + if (text.length == 0) return EMPTY_ATOMIC_LIST; + List_t codepoints = EMPTY_ATOMIC_LIST; TextIter_t state = NEW_TEXT_ITER_STATE(text); - for (int64_t i = 0; i < text.length; i++) { + for (int64_t i = 0; i < (int64_t)text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state, i); if (grapheme < 0) { for (int64_t c = 0; c < NUM_GRAPHEME_CODEPOINTS(grapheme); c++) { @@ -1618,7 +1614,7 @@ static INLINE const char *codepoint_name(ucs4_t c) { public List_t Text$codepoint_names(Text_t text) { - List_t names = {}; + List_t names = EMPTY_LIST; TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0; i < text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state, i); @@ -1653,7 +1649,7 @@ OptionalText_t Text$from_utf16(List_t units) { uint8_t buf[length]; uint8_t *u8 = u16_to_u8(units.data, (size_t)units.length, buf, &length); Text_t ret = - Text$from_utf8((List_t){.data = u8, .length = (int64_t)length, .stride = sizeof(uint8_t), .atomic = 1}); + Text$from_utf8((List_t){.data = u8, .length = (uint64_t)length, .stride = sizeof(uint8_t), .atomic = 1}); if (u8 != buf) free(u8); return ret; } @@ -1663,8 +1659,8 @@ OptionalText_t Text$from_utf32(List_t codepoints) { if (codepoints.length == 0) return EMPTY_TEXT; if (codepoints.stride != sizeof(uint32_t)) List$compact(&codepoints, sizeof(uint32_t)); - List_t graphemes = {}; - Table_t unique_clusters = {}; + List_t graphemes = EMPTY_ATOMIC_LIST; + Table_t unique_clusters = EMPTY_TABLE; const uint32_t *pos = (const uint32_t *)codepoints.data; const uint32_t *end = (const uint32_t *)&pos[codepoints.length]; // Iterate over grapheme clusters @@ -1684,12 +1680,12 @@ OptionalText_t Text$from_utf32(List_t codepoints) { if (unique_clusters.entries.length == 256) { List_t remaining_codepoints = { - .length = (int64_t)(end - next), + .length = (uint64_t)(end - next), .data = (void *)next, .stride = sizeof(int32_t), }; OptionalText_t remainder = Text$from_utf32(remaining_codepoints); - if (remainder.length < 0) return NONE_TEXT; + if (remainder.tag == TEXT_NONE) return NONE_TEXT; return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters), remainder); } } @@ -1698,8 +1694,8 @@ OptionalText_t Text$from_utf32(List_t codepoints) { public OptionalText_t Text$from_codepoint_names(List_t codepoint_names) { - List_t codepoints = {}; - for (int64_t i = 0; i < codepoint_names.length; i++) { + List_t codepoints = EMPTY_LIST; + for (int64_t i = 0; i < (int64_t)codepoint_names.length; i++) { Text_t *name = ((Text_t *)(codepoint_names.data + i * codepoint_names.stride)); const char *name_str = Text$as_c_string(*name); ucs4_t codepoint = unicode_name_character(name_str); @@ -1711,9 +1707,9 @@ OptionalText_t Text$from_codepoint_names(List_t codepoint_names) { public List_t Text$lines(Text_t text) { - List_t lines = {}; + List_t lines = EMPTY_LIST; TextIter_t state = NEW_TEXT_ITER_STATE(text); - for (int64_t i = 0, line_start = 0; i < text.length; i++) { + for (int64_t i = 0, line_start = 0; i < (int64_t)text.length; i++) { int32_t grapheme = Text$get_grapheme_fast(&state, i); if (grapheme == '\r' && Text$get_grapheme_fast(&state, i + 1) == '\n') { // CRLF Text_t line = Text$slice(text, I(line_start + 1), I(i)); @@ -1768,7 +1764,7 @@ Closure_t Text$by_line(Text_t text) { PUREFUNC public bool Text$is_none(const void *t, const TypeInfo_t *info) { (void)info; - return ((Text_t *)t)->length < 0; + return ((Text_t *)t)->tag == TEXT_NONE; } public diff --git a/src/stdlib/text.h b/src/stdlib/text.h index 281c1880..75f300eb 100644 --- a/src/stdlib/text.h +++ b/src/stdlib/text.h @@ -59,7 +59,7 @@ OptionalText_t Text$cluster(Text_t text, Int_t index_int); const Text_t text = text_expr; \ Int_t index = index_expr; \ OptionalText_t cluster = Text$cluster(text, index); \ - if (unlikely(cluster.length < 0)) \ + if (unlikely(!cluster.has_value)) \ fail_source(__SOURCE_FILE__, start, end, "Invalid text index: ", index, " (text has length ", \ (int64_t)text.length, ")\n"); \ cluster; \ @@ -61,7 +61,7 @@ static struct stat compiler_stat; static const char *paths_str(List_t paths) { Text_t result = EMPTY_TEXT; - for (int64_t i = 0; i < paths.length; i++) { + for (int64_t i = 0; i < (int64_t)paths.length; i++) { if (i > 0) result = Texts(result, Text(" ")); result = Texts(result, Path$as_text((Path_t *)(paths.data + i * paths.stride), false, &Path$info)); } @@ -283,14 +283,14 @@ int main(int argc, char *argv[]) { as_owner = Texts(Text(SUDO " -u "), owner, Text(" ")); } - for (int64_t i = 0; i < uninstall.length; i++) { + for (int64_t i = 0; i < (int64_t)uninstall.length; i++) { Text_t *u = (Text_t *)(uninstall.data + i * uninstall.stride); xsystem(as_owner, "rm -rvf '", TOMO_PATH, "'/lib/tomo_" TOMO_VERSION "/", *u); print("Uninstalled ", *u); } Path_t cwd = Path$current_dir(); - for (int64_t i = 0; i < libraries.length; i++) { + for (int64_t i = 0; i < (int64_t)libraries.length; i++) { Path_t *lib = (Path_t *)(libraries.data + i * libraries.stride); *lib = Path$resolved(*lib, cwd); // Fork a child process to build the library to prevent cross-contamination @@ -323,7 +323,7 @@ int main(int argc, char *argv[]) { // Convert `foo` to `foo/foo.tm` and resolve all paths to absolute paths: Path_t cur_dir = Path$current_dir(); - for (int64_t i = 0; i < files.length; i++) { + for (int64_t i = 0; i < (int64_t)files.length; i++) { Path_t *path = (Path_t *)(files.data + i * files.stride); if (Path$is_directory(*path, true)) *path = Path$child(*path, Texts(Path$base_name(*path), Text(".tm"))); @@ -335,7 +335,7 @@ int main(int argc, char *argv[]) { if (!compile_exe && !stop_at_transpile && !stop_at_obj_compilation) quiet = !verbose; - for (int64_t i = 0; i < files.length; i++) { + for (int64_t i = 0; i < (int64_t)files.length; i++) { Path_t path = *(Path_t *)(files.data + i * files.stride); if (show_parse_tree) { ast_t *ast = parse_file(Path$as_c_string(path), NULL); @@ -360,7 +360,7 @@ int main(int argc, char *argv[]) { pid_t child = fork(); if (child == 0) { env_t *env = global_env(source_mapping); - List_t object_files = {}, extra_ldlibs = {}; + List_t object_files = EMPTY_LIST, extra_ldlibs = EMPTY_LIST; compile_files(env, files, &object_files, &extra_ldlibs); compile_executable(env, path, exe_path, object_files, extra_ldlibs); @@ -368,7 +368,7 @@ int main(int argc, char *argv[]) { char *prog_args[1 + args.length + 1]; prog_args[0] = (char *)Path$as_c_string(exe_path); - for (int64_t j = 0; j < args.length; j++) + for (int64_t j = 0; j < (int64_t)args.length; j++) prog_args[j + 1] = Text$as_c_string(*(Text_t *)(args.data + j * args.stride)); prog_args[1 + args.length] = NULL; execv(prog_args[0], prog_args); @@ -379,7 +379,7 @@ int main(int argc, char *argv[]) { } if (compile_exe && should_install) { - for (int64_t i = 0; i < files.length; i++) { + for (int64_t i = 0; i < (int64_t)files.length; i++) { Path_t path = *(Path_t *)(files.data + i * files.stride); Path_t exe = Path$with_extension(path, Text(""), true); xsystem(as_owner, "cp -v '", exe, "' '", TOMO_PATH, "'/bin/"); @@ -417,7 +417,7 @@ void build_library(Path_t lib_dir) { List_t tm_files = Path$glob(Path$child(lib_dir, Text("[!._0-9]*.tm"))); env_t *env = fresh_scope(global_env(source_mapping)); - List_t object_files = {}, extra_ldlibs = {}; + List_t object_files = EMPTY_LIST, extra_ldlibs = EMPTY_LIST; compile_files(env, tm_files, &object_files, &extra_ldlibs); @@ -472,9 +472,10 @@ void install_library(Path_t lib_dir) { } void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *extra_ldlibs) { - Table_t to_link = {}; - Table_t dependency_files = {}; - for (int64_t i = 0; i < to_compile.length; i++) { + Table_t to_link = EMPTY_TABLE; + Table_t dependency_files = EMPTY_TABLE; + for (int64_t i = 0; i < (int64_t)to_compile.length; i++) { + Path_t filename = *(Path_t *)(to_compile.data + i * to_compile.stride); Text_t extension = Path$extension(filename, true); if (!Text$equal_values(extension, Text("tm"))) @@ -484,7 +485,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t * } // Make sure all files and dependencies have a .id file: - for (int64_t i = 0; i < dependency_files.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)dependency_files.entries.length; i++) { struct { Path_t filename; staleness_t staleness; @@ -513,7 +514,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t * // (Re)compile header files, eagerly for explicitly passed in files, lazily // for downstream dependencies: - for (int64_t i = 0; i < dependency_files.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)dependency_files.entries.length; i++) { struct { Path_t filename; staleness_t staleness; @@ -537,7 +538,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t * // (Re)transpile and compile object files, eagerly for files explicitly // specified and lazily for downstream dependencies: - for (int64_t i = 0; i < dependency_files.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)dependency_files.entries.length; i++) { struct { Path_t filename; staleness_t staleness; @@ -564,7 +565,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t * wait_for_child_success(child_processes->pid); if (object_files) { - for (int64_t i = 0; i < dependency_files.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)dependency_files.entries.length; i++) { struct { Path_t filename; staleness_t staleness; @@ -575,7 +576,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t * } } if (extra_ldlibs) { - for (int64_t i = 0; i < to_link.entries.length; i++) { + for (int64_t i = 0; i < (int64_t)to_link.entries.length; i++) { Text_t lib = *(Text_t *)(to_link.entries.data + i * to_link.entries.stride); List$insert(extra_ldlibs, &lib, I(0), sizeof(Text_t)); } @@ -584,7 +585,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t * bool is_config_outdated(Path_t path) { OptionalText_t config = Path$read(build_file(path, ".config")); - if (config.length < 0) return true; + if (config.tag == TEXT_NONE) return true; return !Text$equal_values(config, config_summary); } @@ -636,9 +637,9 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l List_t children = Path$glob(Path$from_str(String(TOMO_PATH, "/lib/tomo_" TOMO_VERSION "/", full_name, "/[!._0-9]*.tm"))); - for (int64_t i = 0; i < children.length; i++) { + for (int64_t i = 0; i < (int64_t)children.length; i++) { Path_t *child = (Path_t *)(children.data + i * children.stride); - Table_t discarded = {.fallback = to_compile}; + Table_t discarded = {.entries = EMPTY_LIST, .fallback = to_compile}; build_file_dependency_graph(*child, &discarded, to_link); } break; @@ -676,7 +677,7 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l } time_t latest_included_modification_time(Path_t path) { - static Table_t c_modification_times = {}; + static Table_t c_modification_times = EMPTY_TABLE; const TypeInfo_t time_info = {.size = sizeof(time_t), .align = __alignof__(time_t), .tag = OpaqueInfo}; time_t *cached_latest = Table$get(c_modification_times, &path, Table$info(&Path$info, &time_info)); if (cached_latest) return *cached_latest; @@ -691,7 +692,7 @@ time_t latest_included_modification_time(Path_t path) { OptionalText_t (*next_line)(void *) = by_line.fn; Path_t parent = Path$parent(path); bool allow_dot_include = Path$has_extension(path, Text("s")) || Path$has_extension(path, Text("S")); - for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) { + for (OptionalText_t line; (line = next_line(by_line.userdata)).tag != TEXT_NONE;) { line = Text$trim(line, Text(" \t"), true, false); if (!Text$starts_with(line, Text("#include"), NULL) && !(allow_dot_include && Text$starts_with(line, Text(".include"), NULL))) @@ -742,7 +743,7 @@ bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing) { } bool is_stale_for_any(Path_t path, List_t relative_to, bool ignore_missing) { - for (int64_t i = 0; i < relative_to.length; i++) { + for (int64_t i = 0; i < (int64_t)relative_to.length; i++) { Path_t r = *(Path_t *)(relative_to.data + i * relative_to.stride); if (is_stale(path, r, ignore_missing)) return true; } diff --git a/src/typecheck.c b/src/typecheck.c index 3c820fa9..76ffe8ad 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -246,7 +246,7 @@ static env_t *load_module(env_t *env, ast_t *use_ast) { env_t *module_file_env = fresh_scope(module_env); module_file_env->namespace = NULL; env_t *subenv = load_module_env(module_file_env, ast); - for (int64_t j = 0; j < subenv->locals->entries.length; j++) { + for (int64_t j = 0; j < (int64_t)subenv->locals->entries.length; j++) { struct { const char *name; binding_t *binding; @@ -332,7 +332,7 @@ void prebind_statement(env_t *env, ast_t *statement) { for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next) prebind_statement(extended, stmt->ast); List_t new_bindings = extended->locals->entries; - for (int64_t i = 0; i < new_bindings.length; i++) { + for (int64_t i = 0; i < (int64_t)new_bindings.length; i++) { struct { const char *name; binding_t *binding; @@ -562,7 +562,7 @@ void bind_statement(env_t *env, ast_t *statement) { for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next) bind_statement(extended, stmt->ast); List_t new_bindings = extended->locals->entries; - for (int64_t i = 0; i < new_bindings.length; i++) { + for (int64_t i = 0; i < (int64_t)new_bindings.length; i++) { struct { const char *name; binding_t *binding; @@ -581,7 +581,7 @@ void bind_statement(env_t *env, ast_t *statement) { if (!module_env) break; for (Table_t *bindings = module_env->locals; bindings != module_env->globals; bindings = bindings->fallback) { List_t entries = bindings->entries; - for (int64_t i = 0; i < entries.length; i++) { + for (int64_t i = 0; i < (int64_t)entries.length; i++) { struct { const char *name; binding_t *binding; @@ -594,7 +594,7 @@ void bind_statement(env_t *env, ast_t *statement) { "', which would clobber another variable"); } } - for (int64_t i = 0; i < module_env->types->entries.length; i++) { + for (int64_t i = 0; i < (int64_t)module_env->types->entries.length; i++) { struct { const char *name; type_t *type; @@ -1599,7 +1599,7 @@ type_t *get_arg_type(env_t *env, arg_t *arg) { } bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, call_opts_t options) { - Table_t used_args = {}; + Table_t used_args = EMPTY_TABLE; // Populate keyword args: for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { |
