diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | src/README.md | 1 | ||||
| -rw-r--r-- | src/ast.c | 100 | ||||
| -rw-r--r-- | src/ast.h | 7 | ||||
| -rw-r--r-- | src/compile.c | 2143 | ||||
| -rw-r--r-- | src/compile.h | 25 | ||||
| -rw-r--r-- | src/cordhelpers.c | 66 | ||||
| -rw-r--r-- | src/cordhelpers.h | 11 | ||||
| -rw-r--r-- | src/enums.c | 108 | ||||
| -rw-r--r-- | src/enums.h | 9 | ||||
| -rw-r--r-- | src/environment.c | 79 | ||||
| -rw-r--r-- | src/environment.h | 23 | ||||
| -rw-r--r-- | src/parse.c | 59 | ||||
| -rw-r--r-- | src/stdlib/print.h | 1 | ||||
| -rw-r--r-- | src/stdlib/text.h | 15 | ||||
| -rw-r--r-- | src/structs.c | 51 | ||||
| -rw-r--r-- | src/structs.h | 6 | ||||
| -rw-r--r-- | src/tomo.c | 24 | ||||
| -rw-r--r-- | src/typecheck.c | 83 | ||||
| -rw-r--r-- | src/types.c | 73 | ||||
| -rw-r--r-- | src/types.h | 2 |
21 files changed, 1408 insertions, 1480 deletions
@@ -73,7 +73,7 @@ CFLAGS=$(CCONFIG) $(INCLUDE_DIRS) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS) $(LTO) -DTOMO_PREFIX='"$(PREFIX)"' -DSUDO='"$(SUDO)"' -DDEFAULT_C_COMPILER='"$(DEFAULT_C_COMPILER)"' \ -DTOMO_VERSION='"$(TOMO_VERSION)"' -DGIT_VERSION='"$(GIT_VERSION)"' CFLAGS_PLACEHOLDER="$$(printf '\033[2m<flags...>\033[m\n')" -LDLIBS=-lgc -lcord -lm -lunistring -lgmp -ldl +LDLIBS=-lgc -lm -lunistring -lgmp -ldl LIBTOMO_FLAGS=-shared DEFINE_AS_OWNER=as_owner() { \ diff --git a/src/README.md b/src/README.md index 9c08593e..fa89ccdd 100644 --- a/src/README.md +++ b/src/README.md @@ -4,7 +4,6 @@ This directory contains the source files for the Tomo compiler: - Abstract syntax trees: [ast.c](ast.c)/[ast.h](ast.h) - Compilation: [compile.c](compile.c)/[compile.h](compile.h) -- Helper functions for Cords: [cordhelpers.c](cordhelpers.c)/[cordhelpers.h](cordhelpers.h) - Compilation logic for enums: [enums.c](enums.c)/[enums.h](enums.h) - Compilation environments: [environment.c](environment.c)/[environment.h](environment.h) - Parsing: [parse.c](parse.c)/[parse.h](parse.h) @@ -1,6 +1,5 @@ // Some basic operations defined on AST nodes, mainly converting to // strings for debugging. -#include <gc/cord.h> #include <stdarg.h> #include "ast.h" @@ -9,7 +8,10 @@ #include "stdlib/integers.h" #include "stdlib/tables.h" #include "stdlib/text.h" -#include "cordhelpers.h" + +static Text_t quoted_text(const char *text) { + return Text$quoted(Text$from_str(text), false, Text("\"")); +} CONSTFUNC const char *binop_method_name(ast_e tag) { switch (tag) { @@ -54,65 +56,65 @@ CONSTFUNC const char *binop_operator(ast_e tag) { } }; -static CORD ast_list_to_sexp(ast_list_t *asts); -static CORD arg_list_to_sexp(arg_ast_t *args); -static CORD arg_defs_to_sexp(arg_ast_t *args); -static CORD when_clauses_to_sexp(when_clause_t *clauses); -static CORD tags_to_sexp(tag_ast_t *tags); -static CORD optional_sexp(const char *tag, ast_t *ast); -static CORD optional_type_sexp(const char *tag, type_ast_t *ast); +static Text_t ast_list_to_sexp(ast_list_t *asts); +static Text_t arg_list_to_sexp(arg_ast_t *args); +static Text_t arg_defs_to_sexp(arg_ast_t *args); +static Text_t when_clauses_to_sexp(when_clause_t *clauses); +static Text_t tags_to_sexp(tag_ast_t *tags); +static Text_t optional_sexp(const char *tag, ast_t *ast); +static Text_t optional_type_sexp(const char *tag, type_ast_t *ast); -CORD ast_list_to_sexp(ast_list_t *asts) +Text_t ast_list_to_sexp(ast_list_t *asts) { - CORD c = CORD_EMPTY; + Text_t c = EMPTY_TEXT; for (; asts; asts = asts->next) { - c = CORD_all(c, " ", ast_to_sexp(asts->ast)); + c = Texts(c, " ", ast_to_sexp(asts->ast)); } return c; } -CORD arg_defs_to_sexp(arg_ast_t *args) { - CORD c = "(args"; +Text_t arg_defs_to_sexp(arg_ast_t *args) { + Text_t c = Text("(args"); for (arg_ast_t *arg = args; arg; arg = arg->next) { - c = CORD_all(c, " (arg ", arg->name ? CORD_quoted(arg->name) : "nil", + c = Texts(c, " (arg ", arg->name ? quoted_text(arg->name) : Text("nil"), " ", type_ast_to_sexp(arg->type), " ", ast_to_sexp(arg->value), ")"); } - return CORD_cat(c, ")"); + return Texts(c, ")"); } -CORD arg_list_to_sexp(arg_ast_t *args) { - CORD c = CORD_EMPTY; +Text_t arg_list_to_sexp(arg_ast_t *args) { + Text_t c = EMPTY_TEXT; for (arg_ast_t *arg = args; arg; arg = arg->next) { assert(arg->value && !arg->type); if (arg->name) - c = CORD_all(c, " :", arg->name); - c = CORD_all(c, " ", ast_to_sexp(arg->value)); + c = Texts(c, " :", arg->name); + c = Texts(c, " ", ast_to_sexp(arg->value)); } return c; } -CORD when_clauses_to_sexp(when_clause_t *clauses) { - CORD c = CORD_EMPTY; +Text_t when_clauses_to_sexp(when_clause_t *clauses) { + Text_t c = EMPTY_TEXT; for (; clauses; clauses = clauses->next) { - c = CORD_all(c, " (case ", ast_to_sexp(clauses->pattern), " ", ast_to_sexp(clauses->body), ")"); + c = Texts(c, " (case ", ast_to_sexp(clauses->pattern), " ", ast_to_sexp(clauses->body), ")"); } return c; } -CORD tags_to_sexp(tag_ast_t *tags) { - CORD c = CORD_EMPTY; +Text_t tags_to_sexp(tag_ast_t *tags) { + Text_t c = EMPTY_TEXT; for (; tags; tags = tags->next) { - c = CORD_all(c, "(tag \"", tags->name, "\" ", arg_defs_to_sexp(tags->fields), ")"); + c = Texts(c, "(tag \"", tags->name, "\" ", arg_defs_to_sexp(tags->fields), ")"); } return c; } -CORD type_ast_to_sexp(type_ast_t *t) +Text_t type_ast_to_sexp(type_ast_t *t) { - if (!t) return "nil"; + if (!t) return Text("nil"); switch (t->tag) { -#define T(type, ...) case type: { __typeof(t->__data.type) data = t->__data.type; (void)data; return CORD_all(__VA_ARGS__); } +#define T(type, ...) case type: { __typeof(t->__data.type) data = t->__data.type; (void)data; return Texts(__VA_ARGS__); } T(UnknownTypeAST, "(UnknownType)") T(VarTypeAST, "(VarType \"", data.name, "\")") T(PointerTypeAST, "(PointerType \"", data.is_stack ? "stack" : "heap", "\" ", type_ast_to_sexp(data.pointed), ")") @@ -122,35 +124,35 @@ CORD type_ast_to_sexp(type_ast_t *t) T(FunctionTypeAST, "(FunctionType ", arg_defs_to_sexp(data.args), " ", type_ast_to_sexp(data.ret), ")") T(OptionalTypeAST, "(OptionalType ", type_ast_to_sexp(data.type), ")") #undef T - default: return CORD_EMPTY; + default: return EMPTY_TEXT; } } -CORD optional_sexp(const char *name, ast_t *ast) +Text_t optional_sexp(const char *name, ast_t *ast) { - return ast ? CORD_all(" :", name, " ", ast_to_sexp(ast)) : CORD_EMPTY; + return ast ? Texts(" :", name, " ", ast_to_sexp(ast)) : EMPTY_TEXT; } -CORD optional_type_sexp(const char *name, type_ast_t *ast) +Text_t optional_type_sexp(const char *name, type_ast_t *ast) { - return ast ? CORD_all(" :", name, " ", type_ast_to_sexp(ast)) : CORD_EMPTY; + return ast ? Texts(" :", name, " ", type_ast_to_sexp(ast)) : EMPTY_TEXT; } -CORD ast_to_sexp(ast_t *ast) +Text_t ast_to_sexp(ast_t *ast) { - if (!ast) return "nil"; + if (!ast) return Text("nil"); switch (ast->tag) { -#define T(type, ...) case type: { __typeof(ast->__data.type) data = ast->__data.type; (void)data; return CORD_all(__VA_ARGS__); } +#define T(type, ...) case type: { __typeof(ast->__data.type) data = ast->__data.type; (void)data; return Texts(__VA_ARGS__); } T(Unknown, "(Unknown)") T(None, "(None)") T(Bool, "(Bool ", data.b ? "yes" : "no", ")") - T(Var, "(Var ", CORD_quoted(data.name), ")") - T(Int, "(Int ", CORD_quoted(ast_source(ast)), ")") - T(Num, "(Num ", CORD_quoted(ast_source(ast)), ")") - T(TextLiteral, CORD_quoted(data.cord)) - T(TextJoin, "(Text", data.lang ? CORD_all(" :lang ", CORD_quoted(data.lang)) : CORD_EMPTY, ast_list_to_sexp(data.children), ")") - T(Path, "(Path ", CORD_quoted(data.path), ")") + T(Var, "(Var ", quoted_text(data.name), ")") + T(Int, "(Int ", quoted_text(ast_source(ast)), ")") + T(Num, "(Num ", quoted_text(ast_source(ast)), ")") + T(TextLiteral, Text$quoted(data.text, false, Text("\""))) + T(TextJoin, "(Text", data.lang ? Texts(" :lang ", quoted_text(data.lang)) : EMPTY_TEXT, ast_list_to_sexp(data.children), ")") + T(Path, "(Path ", quoted_text(data.path), ")") T(Declare, "(Declare ", ast_to_sexp(data.var), " ", type_ast_to_sexp(data.type), " ", ast_to_sexp(data.value), ")") T(Assign, "(Assign (targets ", ast_list_to_sexp(data.targets), ") (values ", ast_list_to_sexp(data.values), "))") #define BINOP(name) T(name, "(" #name " ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), ")") @@ -179,7 +181,7 @@ CORD ast_to_sexp(ast_t *ast) T(ConvertDef, "(ConvertDef ", arg_defs_to_sexp(data.args), " ", type_ast_to_sexp(data.ret_type), " ", ast_to_sexp(data.body), ")") T(Lambda, "(Lambda ", arg_defs_to_sexp(data.args), optional_type_sexp("return", data.ret_type), " ", ast_to_sexp(data.body), ")") T(FunctionCall, "(FunctionCall ", ast_to_sexp(data.fn), arg_list_to_sexp(data.args), ")") - T(MethodCall, "(MethodCall ", ast_to_sexp(data.self), " ", CORD_quoted(data.name), arg_list_to_sexp(data.args), ")") + T(MethodCall, "(MethodCall ", ast_to_sexp(data.self), " ", quoted_text(data.name), arg_list_to_sexp(data.args), ")") T(Block, "(Block", ast_list_to_sexp(data.statements), ")") T(For, "(For (vars", ast_list_to_sexp(data.vars), ") ", ast_to_sexp(data.iter), " ", ast_to_sexp(data.body), " ", ast_to_sexp(data.empty), ")") @@ -187,9 +189,9 @@ CORD ast_to_sexp(ast_t *ast) T(Repeat, "(Repeat ", ast_to_sexp(data.body), ")") T(If, "(If ", ast_to_sexp(data.condition), " ", ast_to_sexp(data.body), optional_sexp("else", data.else_body), ")") T(When, "(When ", ast_to_sexp(data.subject), when_clauses_to_sexp(data.clauses), optional_sexp("else", data.else_body), ")") - T(Reduction, "(Reduction ", CORD_quoted(binop_method_name(data.op)), " ", ast_to_sexp(data.key), " ", ast_to_sexp(data.iter), ")") - T(Skip, "(Skip ", CORD_quoted(data.target), ")") - T(Stop, "(Stop ", CORD_quoted(data.target), ")") + T(Reduction, "(Reduction ", quoted_text(binop_method_name(data.op)), " ", ast_to_sexp(data.key), " ", ast_to_sexp(data.iter), ")") + T(Skip, "(Skip ", quoted_text(data.target), ")") + T(Stop, "(Stop ", quoted_text(data.target), ")") T(Pass, "(Pass)") T(Defer, "(Defer ", ast_to_sexp(data.body), ")") T(Return, "(Return ", ast_to_sexp(data.value), ")") @@ -203,7 +205,7 @@ CORD ast_to_sexp(ast_t *ast) T(NonOptional, "(NonOptional ", ast_to_sexp(data.value), ")") T(DocTest, "(DocTest ", ast_to_sexp(data.expr), optional_sexp("expected", data.expected), ")") T(Assert, "(Assert ", ast_to_sexp(data.expr), " ", optional_sexp("message", data.message), ")") - T(Use, "(Use ", optional_sexp("var", data.var), " ", CORD_quoted(data.path), ")") + T(Use, "(Use ", optional_sexp("var", data.var), " ", quoted_text(data.path), ")") T(InlineCCode, "(InlineCCode ", ast_list_to_sexp(data.chunks), optional_type_sexp("type", data.type_ast), ")") T(Deserialize, "(Deserialize ", type_ast_to_sexp(data.type), " ", ast_to_sexp(data.value), ")") T(Extend, "(Extend \"", data.name, "\" ", ast_to_sexp(data.body), ")") @@ -214,7 +216,7 @@ CORD ast_to_sexp(ast_t *ast) const char *ast_to_sexp_str(ast_t *ast) { - return CORD_to_const_char_star(ast_to_sexp(ast)); + return Text$as_c_string(ast_to_sexp(ast)); } const char *ast_source(ast_t *ast) @@ -3,7 +3,6 @@ // Logic defining ASTs (abstract syntax trees) to represent code #include <err.h> -#include <gc/cord.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> @@ -176,7 +175,7 @@ struct ast_s { double n; } Num; struct { - CORD cord; + Text_t text; } TextLiteral; struct { const char *lang; @@ -353,9 +352,9 @@ struct ast_s { const char *ast_source(ast_t *ast); -CORD ast_to_sexp(ast_t *ast); +Text_t ast_to_sexp(ast_t *ast); const char *ast_to_sexp_str(ast_t *ast); -CORD type_ast_to_sexp(type_ast_t *ast); +Text_t type_ast_to_sexp(type_ast_t *ast); PUREFUNC bool is_idempotent(ast_t *ast); void visit_topologically(ast_list_t *ast, Closure_t fn); diff --git a/src/compile.c b/src/compile.c index 2fa9ed43..95ee6e3a 100644 --- a/src/compile.c +++ b/src/compile.c @@ -2,14 +2,12 @@ #include <ctype.h> #include <glob.h> #include <gc.h> -#include <gc/cord.h> #include <gmp.h> #include <stdio.h> #include <uninorm.h> #include "ast.h" #include "compile.h" -#include "cordhelpers.h" #include "enums.h" #include "environment.h" #include "modules.h" @@ -24,60 +22,68 @@ typedef ast_t* (*comprehension_body_t)(ast_t*, ast_t*); -static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref); -static CORD compile_string(env_t *env, ast_t *ast, CORD color); -static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args); -static CORD compile_maybe_incref(env_t *env, ast_t *ast, type_t *t); -static CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target); -static CORD compile_unsigned_type(type_t *t); -static CORD promote_to_optional(type_t *t, CORD code); -static CORD compile_none(type_t *t); -static CORD compile_empty(type_t *t); -static CORD compile_declared_value(env_t *env, ast_t *declaration_ast); -static CORD compile_to_type(env_t *env, ast_t *ast, type_t *t); -static CORD compile_typed_list(env_t *env, ast_t *ast, type_t *list_type); -static CORD compile_typed_set(env_t *env, ast_t *ast, type_t *set_type); -static CORD compile_typed_table(env_t *env, ast_t *ast, type_t *table_type); -static CORD compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type); -static CORD check_none(type_t *t, CORD value); -static CORD optional_into_nonnone(type_t *t, CORD value); -static CORD compile_string_literal(CORD literal); +static Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref); +static Text_t compile_text(env_t *env, ast_t *ast, Text_t color); +static Text_t compile_text_literal(Text_t literal); +static Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args); +static Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t); +static Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target); +static Text_t compile_unsigned_type(type_t *t); +static Text_t promote_to_optional(type_t *t, Text_t code); +static Text_t compile_none(type_t *t); +static Text_t compile_empty(type_t *t); +static Text_t compile_declared_value(env_t *env, ast_t *declaration_ast); +static Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t); +static Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type); +static Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type); +static Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type); +static Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type); +static Text_t check_none(type_t *t, Text_t value); +static Text_t optional_into_nonnone(type_t *t, Text_t value); static ast_t *add_to_list_comprehension(ast_t *item, ast_t *subject); static ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject); static ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject); -static CORD compile_lvalue(env_t *env, ast_t *ast); +static Text_t compile_lvalue(env_t *env, ast_t *ast); -CORD promote_to_optional(type_t *t, CORD code) +static Text_t quoted_str(const char *str) { + return Text$quoted(Text$from_str(str), false, Text("\"")); +} + +static inline Text_t quoted_text(Text_t text) { + return Text$quoted(text, false, Text("\"")); +} + +Text_t promote_to_optional(type_t *t, Text_t code) { if (t == PATH_TYPE || t == PATH_TYPE_TYPE) { return code; } else if (t->tag == IntType) { switch (Match(t, IntType)->bits) { - case TYPE_IBITS8: return CORD_all("((OptionalInt8_t){.value=", code, "})"); - case TYPE_IBITS16: return CORD_all("((OptionalInt16_t){.value=", code, "})"); - case TYPE_IBITS32: return CORD_all("((OptionalInt32_t){.value=", code, "})"); - case TYPE_IBITS64: return CORD_all("((OptionalInt64_t){.value=", code, "})"); + case TYPE_IBITS8: return Texts("((OptionalInt8_t){.value=", code, "})"); + case TYPE_IBITS16: return Texts("((OptionalInt16_t){.value=", code, "})"); + case TYPE_IBITS32: return Texts("((OptionalInt32_t){.value=", code, "})"); + case TYPE_IBITS64: return Texts("((OptionalInt64_t){.value=", code, "})"); default: errx(1, "Unsupported in type: ", type_to_str(t)); } return code; } else if (t->tag == ByteType) { - return CORD_all("((OptionalByte_t){.value=", code, "})"); + return Texts("((OptionalByte_t){.value=", code, "})"); } else if (t->tag == StructType) { - return CORD_all("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_none = false; nonnull; })"); + return Texts("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_none = false; nonnull; })"); } else { return code; } } -static CORD with_source_info(env_t *env, ast_t *ast, CORD code) +static Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) { - if (code == CORD_EMPTY || !ast || !ast->file || !env->do_source_mapping) + if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping) return code; int64_t line = get_line_number(ast->file, ast->start); - return CORD_all("\n#line ", String(line), "\n", code); + return Texts("\n#line ", String(line), "\n", code); } -static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t *needed) +static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed) { if (type_eq(actual, needed)) return true; @@ -86,7 +92,7 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * return false; if (needed->tag == ClosureType && actual->tag == FunctionType) { - *code = CORD_all("((Closure_t){", *code, ", NULL})"); + *code = Texts("((Closure_t){", *code, ", NULL})"); return true; } @@ -103,25 +109,25 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * // Optional -> Bool promotion if (actual->tag == OptionalType && needed->tag == BoolType) { - *code = CORD_all("(!", check_none(actual, *code), ")"); + *code = Texts("(!", check_none(actual, *code), ")"); return true; } - // Lang to Text: + // Lang to Text_t: if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text")) return true; // Automatic optional checking for nums: if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) { int64_t line = get_line_number(ast->file, ast->start); - *code = CORD_all("({ ", compile_declaration(actual, "opt"), " = ", *code, "; ", - "if unlikely (", check_none(actual, "opt"), ")\n", + *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ", + "if unlikely (", check_none(actual, Text("opt")), ")\n", "#line ", String(line), "\n", - "fail_source(", CORD_quoted(ast->file->filename), ", ", + "fail_source(", quoted_str(ast->file->filename), ", ", String((int64_t)(ast->start - ast->file->text)), ", ", String((int64_t)(ast->end - ast->file->text)), ", ", "\"This was expected to be a value, but it's none\");\n", - optional_into_nonnone(actual, "opt"), "; })"); + optional_into_nonnone(actual, Text("opt")), "; })"); return true; } @@ -132,7 +138,7 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * if (constructor) { DeclareMatch(fn, constructor->type, FunctionType); if (fn->args->next == NULL) { - *code = CORD_all(constructor->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + *code = Texts(constructor->code, "(", compile_arguments(env, ast, fn->args, args), ")"); return true; } } @@ -145,20 +151,20 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * // Single-value enum constructor: if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type)) return false; - *code = CORD_all(b->code, "(", *code, ")"); + *code = Texts(b->code, "(", *code, ")"); return true; } - // Text to C String + // Text_t to C String if (actual->tag == TextType && type_eq(actual, TEXT_TYPE) && needed->tag == CStringType) { - *code = CORD_all("Text$as_c_string(", *code, ")"); + *code = Texts("Text$as_c_string(", *code, ")"); return true; } // Automatic dereferencing: if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed)) { - *code = CORD_all("*(", *code, ")"); + *code = Texts("*(", *code, ")"); return promote(env, ast, code, Match(actual, PointerType)->pointed, needed); } @@ -174,27 +180,27 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * return true; if (needed->tag == FunctionType && actual->tag == FunctionType) { - *code = CORD_all("(", compile_type(needed), ")", *code); + *code = Texts("(", compile_type(needed), ")", *code); return true; } // Set -> List promotion: if (needed->tag == ListType && actual->tag == SetType && type_eq(Match(needed, ListType)->item_type, Match(actual, SetType)->item_type)) { - *code = CORD_all("(", *code, ").entries"); + *code = Texts("(", *code, ").entries"); return true; } return false; } -CORD compile_maybe_incref(env_t *env, ast_t *ast, type_t *t) +Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t) { if (is_idempotent(ast) && can_be_mutated(env, ast)) { if (t->tag == ListType) - return CORD_all("LIST_COPY(", compile_to_type(env, ast, t), ")"); + return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")"); else if (t->tag == TableType || t->tag == SetType) - return CORD_all("TABLE_COPY(", compile_to_type(env, ast, t), ")"); + return Texts("TABLE_COPY(", compile_to_type(env, ast, t), ")"); } return compile_to_type(env, ast, t); } @@ -299,7 +305,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t DeclareMatch(lambda, ast, Lambda); env_t *lambda_scope = fresh_scope(env); for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) - set_binding(lambda_scope, arg->name, get_arg_ast_type(env, arg), CORD_all("_$", arg->name)); + set_binding(lambda_scope, arg->name, get_arg_ast_type(env, arg), Texts("_$", arg->name)); add_closed_vars(closed_vars, enclosing_scope, lambda_scope, lambda->body); break; } @@ -348,7 +354,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t type_t *cond_t = get_type(truthy_scope, var); if (cond_t->tag == OptionalType) { set_binding(truthy_scope, Match(var, Var)->name, - Match(cond_t, OptionalType)->type, CORD_EMPTY); + Match(cond_t, OptionalType)->type, EMPTY_TEXT); } add_closed_vars(closed_vars, enclosing_scope, truthy_scope, if_->body); add_closed_vars(closed_vars, enclosing_scope, env, if_->else_body); @@ -359,7 +365,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t if (condition->tag == Var && cond_t->tag == OptionalType) { truthy_scope = fresh_scope(env); set_binding(truthy_scope, Match(condition, Var)->name, - Match(cond_t, OptionalType)->type, CORD_EMPTY); + Match(cond_t, OptionalType)->type, EMPTY_TEXT); } add_closed_vars(closed_vars, enclosing_scope, truthy_scope, if_->body); add_closed_vars(closed_vars, enclosing_scope, env, if_->else_body); @@ -476,7 +482,7 @@ static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block) env_t *body_scope = fresh_scope(env); for (arg_ast_t *arg = args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - set_binding(body_scope, arg->name, arg_type, CORD_cat("_$", arg->name)); + set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name)); } Table_t closed_vars = {}; @@ -484,25 +490,25 @@ static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block) return closed_vars; } -CORD compile_declaration(type_t *t, CORD name) +Text_t compile_declaration(type_t *t, Text_t name) { if (t->tag == FunctionType) { DeclareMatch(fn, t, FunctionType); - CORD code = CORD_all(compile_type(fn->ret), " (*", name, ")("); + Text_t code = Texts(compile_type(fn->ret), " (*", name, ")("); for (arg_t *arg = fn->args; arg; arg = arg->next) { - code = CORD_all(code, compile_type(arg->type)); - if (arg->next) code = CORD_cat(code, ", "); + code = Texts(code, compile_type(arg->type)); + if (arg->next) code = Texts(code, ", "); } - if (!fn->args) code = CORD_all(code, "void"); - return CORD_all(code, ")"); + if (!fn->args) code = Texts(code, "void"); + return Texts(code, ")"); } else if (t->tag != ModuleType) { - return CORD_all(compile_type(t), " ", name); + return Texts(compile_type(t), " ", name); } else { - return CORD_EMPTY; + return EMPTY_TEXT; } } -static CORD compile_update_assignment(env_t *env, ast_t *ast) +static Text_t compile_update_assignment(env_t *env, ast_t *ast) { if (!is_update_assignment(ast)) code_err(ast, "This is not an update assignment"); @@ -512,70 +518,70 @@ static CORD compile_update_assignment(env_t *env, ast_t *ast) type_t *lhs_t = get_type(env, update.lhs); bool needs_idemotency_fix = !is_idempotent(update.lhs); - CORD lhs = needs_idemotency_fix ? "(*lhs)" : compile_lvalue(env, update.lhs); + Text_t lhs = needs_idemotency_fix ? Text("(*lhs)") : compile_lvalue(env, update.lhs); - CORD update_assignment = CORD_EMPTY; + Text_t update_assignment = EMPTY_TEXT; switch (ast->tag) { case PlusUpdate: { if (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType) - update_assignment = CORD_all(lhs, " += ", compile_to_type(env, update.rhs, lhs_t), ";"); + update_assignment = Texts(lhs, " += ", compile_to_type(env, update.rhs, lhs_t), ";"); break; } case MinusUpdate: { if (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType) - update_assignment = CORD_all(lhs, " -= ", compile_to_type(env, update.rhs, lhs_t), ";"); + update_assignment = Texts(lhs, " -= ", compile_to_type(env, update.rhs, lhs_t), ";"); break; } case MultiplyUpdate: { if (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType) - update_assignment = CORD_all(lhs, " *= ", compile_to_type(env, update.rhs, lhs_t), ";"); + update_assignment = Texts(lhs, " *= ", compile_to_type(env, update.rhs, lhs_t), ";"); break; } case DivideUpdate: { if (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType) - update_assignment = CORD_all(lhs, " /= ", compile_to_type(env, update.rhs, lhs_t), ";"); + update_assignment = Texts(lhs, " /= ", compile_to_type(env, update.rhs, lhs_t), ";"); break; } case LeftShiftUpdate: { if (lhs_t->tag == IntType || lhs_t->tag == ByteType) - update_assignment = CORD_all(lhs, " <<= ", compile_to_type(env, update.rhs, lhs_t), ";"); + update_assignment = Texts(lhs, " <<= ", compile_to_type(env, update.rhs, lhs_t), ";"); break; } case RightShiftUpdate: { if (lhs_t->tag == IntType || lhs_t->tag == ByteType) - update_assignment = CORD_all(lhs, " >>= ", compile_to_type(env, update.rhs, lhs_t), ";"); + update_assignment = Texts(lhs, " >>= ", compile_to_type(env, update.rhs, lhs_t), ";"); break; } case AndUpdate: { if (lhs_t->tag == BoolType) - update_assignment = CORD_all("if (", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";"); + update_assignment = Texts("if (", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";"); break; } case OrUpdate: { if (lhs_t->tag == BoolType) - update_assignment = CORD_all("if (!", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";"); + update_assignment = Texts("if (!", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";"); break; } default: break; } - if (update_assignment == CORD_EMPTY) { + if (update_assignment.length == 0) { ast_t *binop = new(ast_t); *binop = *ast; binop->tag = binop_tag(binop->tag); if (needs_idemotency_fix) - binop->__data.Plus.lhs = LiteralCode("*lhs", .type=lhs_t); - update_assignment = CORD_all(lhs, " = ", compile_to_type(env, binop, lhs_t), ";"); + binop->__data.Plus.lhs = LiteralCode(Text("*lhs"), .type=lhs_t); + update_assignment = Texts(lhs, " = ", compile_to_type(env, binop, lhs_t), ";"); } if (needs_idemotency_fix) - return CORD_all("{ ", compile_declaration(Type(PointerType, .pointed=lhs_t), "lhs"), " = &", compile_lvalue(env, update.lhs), "; ", + return Texts("{ ", compile_declaration(Type(PointerType, .pointed=lhs_t), Text("lhs")), " = &", compile_lvalue(env, update.lhs), "; ", update_assignment, "; }"); else return update_assignment; } -static CORD compile_binary_op(env_t *env, ast_t *ast) +static Text_t compile_binary_op(env_t *env, ast_t *ast) { binary_operands_t binop = BINARY_OPERANDS(ast); type_t *lhs_t = get_type(env, binop.lhs); @@ -587,7 +593,7 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) if (b) { arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs)); DeclareMatch(fn, b->type, FunctionType); - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); } if (ast->tag == Multiply && is_numeric_type(lhs_t)) { @@ -597,7 +603,7 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) if (type_eq(fn->ret, rhs_t)) { arg_ast_t *args = new(arg_ast_t, .value=binop.rhs, .next=new(arg_ast_t, .value=binop.lhs)); if (is_valid_call(env, fn->args, args, true)) - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); } } } else if (ast->tag == Multiply && is_numeric_type(rhs_t)) { @@ -607,7 +613,7 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) if (type_eq(fn->ret, lhs_t)) { arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs)); if (is_valid_call(env, fn->args, args, true)) - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); } } } else if (ast->tag == Divide && is_numeric_type(rhs_t)) { @@ -617,7 +623,7 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) if (type_eq(fn->ret, lhs_t)) { arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs)); if (is_valid_call(env, fn->args, args, true)) - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); } } } else if ((ast->tag == Divide || ast->tag == Mod || ast->tag == Mod1) && is_numeric_type(rhs_t)) { @@ -627,16 +633,16 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) if (type_eq(fn->ret, lhs_t)) { arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs)); if (is_valid_call(env, fn->args, args, true)) - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")"); } } } if (ast->tag == Or && lhs_t->tag == OptionalType) { if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) { - return CORD_all("({ ", compile_declaration(lhs_t, "lhs"), " = ", compile(env, binop.lhs), "; ", - "if (", check_none(lhs_t, "lhs"), ") ", compile_statement(env, binop.rhs), " ", - optional_into_nonnone(lhs_t, "lhs"), "; })"); + return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ", + "if (", check_none(lhs_t, Text("lhs")), ") ", compile_statement(env, binop.rhs), " ", + optional_into_nonnone(lhs_t, Text("lhs")), "; })"); } if (is_incomplete_type(rhs_t)) { @@ -647,103 +653,103 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) } if (rhs_t->tag == OptionalType && type_eq(lhs_t, rhs_t)) { - return CORD_all("({ ", compile_declaration(lhs_t, "lhs"), " = ", compile(env, binop.lhs), "; ", - check_none(lhs_t, "lhs"), " ? ", compile(env, binop.rhs), " : lhs; })"); + return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ", + check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : lhs; })"); } else if (rhs_t->tag != OptionalType && type_eq(Match(lhs_t, OptionalType)->type, rhs_t)) { - return CORD_all("({ ", compile_declaration(lhs_t, "lhs"), " = ", compile(env, binop.lhs), "; ", - check_none(lhs_t, "lhs"), " ? ", compile(env, binop.rhs), " : ", - optional_into_nonnone(lhs_t, "lhs"), "; })"); + return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ", + check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : ", + optional_into_nonnone(lhs_t, Text("lhs")), "; })"); } else if (rhs_t->tag == BoolType) { - return CORD_all("((!", check_none(lhs_t, compile(env, binop.lhs)), ") || ", compile(env, binop.rhs), ")"); + return Texts("((!", check_none(lhs_t, compile(env, binop.lhs)), ") || ", compile(env, binop.rhs), ")"); } else { code_err(ast, "I don't know how to do an 'or' operation between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); } } - CORD lhs = compile_to_type(env, binop.lhs, overall_t); - CORD rhs = compile_to_type(env, binop.rhs, overall_t); + Text_t lhs = compile_to_type(env, binop.lhs, overall_t); + Text_t rhs = compile_to_type(env, binop.rhs, overall_t); switch (ast->tag) { case Power: { if (overall_t->tag != NumType) code_err(ast, "Exponentiation is only supported for Num types, not ", type_to_str(overall_t)); if (overall_t->tag == NumType && Match(overall_t, NumType)->bits == TYPE_NBITS32) - return CORD_all("powf(", lhs, ", ", rhs, ")"); + return Texts("powf(", lhs, ", ", rhs, ")"); else - return CORD_all("pow(", lhs, ", ", rhs, ")"); + return Texts("pow(", lhs, ", ", rhs, ")"); } case Multiply: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " * ", rhs, ")"); + return Texts("(", lhs, " * ", rhs, ")"); } case Divide: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " / ", rhs, ")"); + return Texts("(", lhs, " / ", rhs, ")"); } case Mod: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " % ", rhs, ")"); + return Texts("(", lhs, " % ", rhs, ")"); } case Mod1: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("((((", lhs, ")-1) % (", rhs, ")) + 1)"); + return Texts("((((", lhs, ")-1) % (", rhs, ")) + 1)"); } case Plus: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " + ", rhs, ")"); + return Texts("(", lhs, " + ", rhs, ")"); } case Minus: { if (overall_t->tag == SetType) - return CORD_all("Table$without(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); + return Texts("Table$without(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " - ", rhs, ")"); + return Texts("(", lhs, " - ", rhs, ")"); } case LeftShift: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " << ", rhs, ")"); + return Texts("(", lhs, " << ", rhs, ")"); } case RightShift: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", lhs, " >> ", rhs, ")"); + return Texts("(", lhs, " >> ", rhs, ")"); } case UnsignedLeftShift: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")"); + return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")"); } case UnsignedRightShift: { if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType) code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); - return CORD_all("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")"); + return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")"); } case And: { if (overall_t->tag == BoolType) - return CORD_all("(", lhs, " && ", rhs, ")"); + return Texts("(", lhs, " && ", rhs, ")"); else if (overall_t->tag == IntType || overall_t->tag == ByteType) - return CORD_all("(", lhs, " & ", rhs, ")"); + return Texts("(", lhs, " & ", rhs, ")"); else if (overall_t->tag == SetType) - return CORD_all("Table$overlap(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); + return Texts("Table$overlap(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); else code_err(ast, "The 'and' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values"); } case Compare: { - return CORD_all("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")"); + return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")"); } case Or: { if (overall_t->tag == BoolType) { - return CORD_all("(", lhs, " || ", rhs, ")"); + return Texts("(", lhs, " || ", rhs, ")"); } else if (overall_t->tag == IntType || overall_t->tag == ByteType) { - return CORD_all("(", lhs, " | ", rhs, ")"); + return Texts("(", lhs, " | ", rhs, ")"); } else if (overall_t->tag == SetType) { - return CORD_all("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); + return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); } else { code_err(ast, "The 'or' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values"); } @@ -751,21 +757,21 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) case Xor: { // TODO: support optional values in `xor` expressions if (overall_t->tag == BoolType || overall_t->tag == IntType || overall_t->tag == ByteType) - return CORD_all("(", lhs, " ^ ", rhs, ")"); + return Texts("(", lhs, " ^ ", rhs, ")"); else if (overall_t->tag == SetType) - return CORD_all("Table$xor(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); + return Texts("Table$xor(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); else code_err(ast, "The 'xor' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values"); } case Concat: { if (overall_t == PATH_TYPE) - return CORD_all("Path$concat(", lhs, ", ", rhs, ")"); + return Texts("Path$concat(", lhs, ", ", rhs, ")"); switch (overall_t->tag) { case TextType: { - return CORD_all("Text$concat(", lhs, ", ", rhs, ")"); + return Texts("Text$concat(", lhs, ", ", rhs, ")"); } case ListType: { - return CORD_all("List$concat(", lhs, ", ", rhs, ", sizeof(", compile_type(Match(overall_t, ListType)->item_type), "))"); + return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(", compile_type(Match(overall_t, ListType)->item_type), "))"); } default: code_err(ast, "Concatenation isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values"); @@ -773,70 +779,70 @@ static CORD compile_binary_op(env_t *env, ast_t *ast) } default: errx(1, "Not a valid binary operation: ", ast_to_sexp_str(ast)); } - return CORD_EMPTY; + return EMPTY_TEXT; } -PUREFUNC CORD compile_unsigned_type(type_t *t) +PUREFUNC Text_t compile_unsigned_type(type_t *t) { if (t->tag != IntType) errx(1, "Not an int type, so unsigned doesn't make sense!"); switch (Match(t, IntType)->bits) { - case TYPE_IBITS8: return "uint8_t"; - case TYPE_IBITS16: return "uint16_t"; - case TYPE_IBITS32: return "uint32_t"; - case TYPE_IBITS64: return "uint64_t"; + case TYPE_IBITS8: return Text("uint8_t"); + case TYPE_IBITS16: return Text("uint16_t"); + case TYPE_IBITS32: return Text("uint32_t"); + case TYPE_IBITS64: return Text("uint64_t"); default: errx(1, "Invalid integer bit size"); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_type(type_t *t) +Text_t compile_type(type_t *t) { - if (t == PATH_TYPE) return "Path_t"; - else if (t == PATH_TYPE_TYPE) return "PathType_t"; + if (t == PATH_TYPE) return Text("Path_t"); + else if (t == PATH_TYPE_TYPE) return Text("PathType_t"); switch (t->tag) { case ReturnType: errx(1, "Shouldn't be compiling ReturnType to a type"); - case AbortType: return "void"; - case VoidType: return "void"; - case MemoryType: return "void"; - case BoolType: return "Bool_t"; - case ByteType: return "Byte_t"; - case CStringType: return "const char*"; - case BigIntType: return "Int_t"; - case IntType: return CORD_all("Int", String(Match(t, IntType)->bits), "_t"); - case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? "Num_t" : CORD_all("Num", String(Match(t, NumType)->bits), "_t"); + case AbortType: return Text("void"); + case VoidType: return Text("void"); + case MemoryType: return Text("void"); + case BoolType: return Text("Bool_t"); + case ByteType: return Text("Byte_t"); + case CStringType: return Text("const char*"); + case BigIntType: return Text("Int_t"); + case IntType: return Texts("Int", String(Match(t, IntType)->bits), "_t"); + case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? Text("Num_t") : Texts("Num", String(Match(t, NumType)->bits), "_t"); case TextType: { DeclareMatch(text, t, TextType); if (!text->lang || streq(text->lang, "Text")) - return "Text_t"; + return Text("Text_t"); else - return namespace_name(text->env, text->env->namespace, "$type"); + return namespace_name(text->env, text->env->namespace, Text("$type")); } - case ListType: return "List_t"; - case SetType: return "Table_t"; - case TableType: return "Table_t"; + case ListType: return Text("List_t"); + case SetType: return Text("Table_t"); + case TableType: return Text("Table_t"); case FunctionType: { DeclareMatch(fn, t, FunctionType); - CORD code = CORD_all(compile_type(fn->ret), " (*)("); + Text_t code = Texts(compile_type(fn->ret), " (*)("); for (arg_t *arg = fn->args; arg; arg = arg->next) { - code = CORD_all(code, compile_type(arg->type)); - if (arg->next) code = CORD_cat(code, ", "); + code = Texts(code, compile_type(arg->type)); + if (arg->next) code = Texts(code, ", "); } if (!fn->args) - code = CORD_all(code, "void"); - return CORD_all(code, ")"); + code = Texts(code, "void"); + return Texts(code, ")"); } - case ClosureType: return "Closure_t"; - case PointerType: return CORD_cat(compile_type(Match(t, PointerType)->pointed), "*"); + case ClosureType: return Text("Closure_t"); + case PointerType: return Texts(compile_type(Match(t, PointerType)->pointed), "*"); case StructType: { DeclareMatch(s, t, StructType); - if (s->external) return s->name; - return CORD_all("struct ", namespace_name(s->env, s->env->namespace, "$struct")); + if (s->external) return Text$from_str(s->name); + return Texts("struct ", namespace_name(s->env, s->env->namespace, Text("$struct"))); } case EnumType: { DeclareMatch(e, t, EnumType); - return namespace_name(e->env, e->env->namespace, "$type"); + return namespace_name(e->env, e->env->namespace, Text("$type")); } case OptionalType: { type_t *nonnull = Match(t, OptionalType)->type; @@ -845,29 +851,29 @@ CORD compile_type(type_t *t) case PointerType: case EnumType: return compile_type(nonnull); case TextType: - return Match(nonnull, TextType)->lang ? compile_type(nonnull) : "OptionalText_t"; + return Match(nonnull, TextType)->lang ? compile_type(nonnull) : Text("OptionalText_t"); case IntType: case BigIntType: case NumType: case BoolType: case ByteType: case ListType: case TableType: case SetType: - return CORD_all("Optional", compile_type(nonnull)); + return Texts("Optional", compile_type(nonnull)); case StructType: { if (nonnull == PATH_TYPE) - return "OptionalPath_t"; + return Text("OptionalPath_t"); if (nonnull == PATH_TYPE_TYPE) - return "OptionalPathType_t"; + return Text("OptionalPathType_t"); DeclareMatch(s, nonnull, StructType); - return namespace_name(s->env, s->env->namespace->parent, CORD_all("$Optional", s->name, "$$type")); + return namespace_name(s->env, s->env->namespace->parent, Texts("$Optional", s->name, "$$type")); } default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t)); } } - case TypeInfoType: return "TypeInfo_t"; + case TypeInfoType: return Text("TypeInfo_t"); default: compiler_err(NULL, NULL, NULL, "Compiling type is not implemented for type with tag ", t->tag); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_lvalue(env_t *env, ast_t *ast) +Text_t compile_lvalue(env_t *env, ast_t *ast) { if (!can_be_mutated(env, ast)) { if (ast->tag == Index) { @@ -894,17 +900,17 @@ CORD compile_lvalue(env_t *env, ast_t *ast) container_t = value_type(container_t); type_t *index_t = get_type(env, index->index); if (container_t->tag == ListType) { - CORD target_code = compile_to_pointer_depth(env, index->indexed, 1, false); + Text_t target_code = compile_to_pointer_depth(env, index->indexed, 1, false); type_t *item_type = Match(container_t, ListType)->item_type; - CORD index_code = index->index->tag == Int + Text_t index_code = index->index->tag == Int ? compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)) - : (index_t->tag == BigIntType ? CORD_all("Int64$from_int(", compile(env, index->index), ", no)") - : CORD_all("(Int64_t)(", compile(env, index->index), ")")); + : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, index->index), ", no)") + : Texts("(Int64_t)(", compile(env, index->index), ")")); if (index->unchecked) { - return CORD_all("List_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ", + return Texts("List_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ", index_code, ")"); } else { - return CORD_all("List_lvalue(", compile_type(item_type), ", ", target_code, ", ", + return Texts("List_lvalue(", compile_type(item_type), ", ", target_code, ", ", index_code, ", ", String((int)(ast->start - ast->file->text)), ", ", String((int)(ast->end - ast->file->text)), ")"); @@ -913,7 +919,7 @@ CORD compile_lvalue(env_t *env, ast_t *ast) DeclareMatch(table_type, container_t, TableType); if (table_type->default_value) { type_t *value_type = get_type(env, table_type->default_value); - return CORD_all("*Table$get_or_setdefault(", + return Texts("*Table$get_or_setdefault(", compile_to_pointer_depth(env, index->indexed, 1, false), ", ", compile_type(table_type->key_type), ", ", compile_type(value_type), ", ", @@ -923,7 +929,7 @@ CORD compile_lvalue(env_t *env, ast_t *ast) } if (index->unchecked) code_err(ast, "Table indexes cannot be unchecked"); - return CORD_all("*(", compile_type(Type(PointerType, table_type->value_type)), ")Table$reserve(", + return Texts("*(", compile_type(Type(PointerType, table_type->value_type)), ")Table$reserve(", compile_to_pointer_depth(env, index->indexed, 1, false), ", ", compile_to_type(env, index->index, Type(PointerType, table_type->key_type, .is_stack=true)), ", NULL,", compile_type_info(container_t), ")"); @@ -935,109 +941,109 @@ CORD compile_lvalue(env_t *env, ast_t *ast) } else { code_err(ast, "I don't know how to assign to this"); } - return CORD_EMPTY; + return EMPTY_TEXT; } -static CORD compile_assignment(env_t *env, ast_t *target, CORD value) +static Text_t compile_assignment(env_t *env, ast_t *target, Text_t value) { - return CORD_all(compile_lvalue(env, target), " = ", value); + return Texts(compile_lvalue(env, target), " = ", value); } -static CORD compile_inline_block(env_t *env, ast_t *ast) +static Text_t compile_inline_block(env_t *env, ast_t *ast) { if (ast->tag != Block) return compile_statement(env, ast); - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; ast_list_t *stmts = Match(ast, Block)->statements; deferral_t *prev_deferred = env->deferred; env = fresh_scope(env); for (ast_list_t *stmt = stmts; stmt; stmt = stmt->next) prebind_statement(env, stmt->ast); for (ast_list_t *stmt = stmts; stmt; stmt = stmt->next) { - code = CORD_all(code, compile_statement(env, stmt->ast), "\n"); + code = Texts(code, compile_statement(env, stmt->ast), "\n"); bind_statement(env, stmt->ast); } for (deferral_t *deferred = env->deferred; deferred && deferred != prev_deferred; deferred = deferred->next) { - code = CORD_all(code, compile_statement(deferred->defer_env, deferred->block)); + code = Texts(code, compile_statement(deferred->defer_env, deferred->block)); } return code; } -CORD optional_into_nonnone(type_t *t, CORD value) +Text_t optional_into_nonnone(type_t *t, Text_t value) { if (t->tag == OptionalType) t = Match(t, OptionalType)->type; switch (t->tag) { case IntType: case ByteType: - return CORD_all(value, ".value"); + return Texts(value, ".value"); case StructType: if (t == PATH_TYPE || t == PATH_TYPE_TYPE) return value; - return CORD_all(value, ".value"); + return Texts(value, ".value"); default: return value; } } -CORD check_none(type_t *t, CORD value) +Text_t check_none(type_t *t, Text_t value) { t = Match(t, OptionalType)->type; // NOTE: these use statement expressions ({...;}) because some compilers // complain about excessive parens around equality comparisons if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType) - return CORD_all("({", value, " == NULL;})"); + return Texts("({", value, " == NULL;})"); else if (t == PATH_TYPE) - return CORD_all("({(", value, ").type.$tag == PATH_NONE;})"); + return Texts("({(", value, ").type.$tag == PATH_NONE;})"); else if (t == PATH_TYPE_TYPE) - return CORD_all("({(", value, ").$tag == PATH_NONE;})"); + return Texts("({(", value, ").$tag == PATH_NONE;})"); else if (t->tag == BigIntType) - return CORD_all("({(", value, ").small == 0;})"); + return Texts("({(", value, ").small == 0;})"); else if (t->tag == ClosureType) - return CORD_all("({(", value, ").fn == NULL;})"); + return Texts("({(", value, ").fn == NULL;})"); else if (t->tag == NumType) - return CORD_all("isnan(", value, ")"); + return Texts("isnan(", value, ")"); else if (t->tag == ListType) - return CORD_all("({(", value, ").length < 0;})"); + return Texts("({(", value, ").length < 0;})"); else if (t->tag == TableType || t->tag == SetType) - return CORD_all("({(", value, ").entries.length < 0;})"); + return Texts("({(", value, ").entries.length < 0;})"); else if (t->tag == BoolType) - return CORD_all("({(", value, ") == NONE_BOOL;})"); + return Texts("({(", value, ") == NONE_BOOL;})"); else if (t->tag == TextType) - return CORD_all("({(", value, ").length < 0;})"); + return Texts("({(", value, ").length < 0;})"); else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType) - return CORD_all("(", value, ").is_none"); + return Texts("(", value, ").is_none"); else if (t->tag == EnumType) { if (enum_has_fields(t)) - return CORD_all("({(", value, ").$tag == 0;})"); + return Texts("({(", value, ").$tag == 0;})"); else - return CORD_all("((", value, ") == 0)"); + return Texts("((", value, ") == 0)"); } print_err("Optional check not implemented for: ", type_to_str(t)); - return CORD_EMPTY; + return EMPTY_TEXT; } -static CORD compile_condition(env_t *env, ast_t *ast) +static Text_t compile_condition(env_t *env, ast_t *ast) { type_t *t = get_type(env, ast); if (t->tag == BoolType) { return compile(env, ast); } else if (t->tag == TextType) { - return CORD_all("(", compile(env, ast), ").length"); + return Texts("(", compile(env, ast), ").length"); } else if (t->tag == ListType) { - return CORD_all("(", compile(env, ast), ").length"); + return Texts("(", compile(env, ast), ").length"); } else if (t->tag == TableType || t->tag == SetType) { - return CORD_all("(", compile(env, ast), ").entries.length"); + return Texts("(", compile(env, ast), ").entries.length"); } else if (t->tag == OptionalType) { - return CORD_all("!", check_none(t, compile(env, ast))); + return Texts("!", check_none(t, compile(env, ast))); } else if (t->tag == PointerType) { code_err(ast, "This pointer will always be non-none, so it should not be used in a conditional."); } else { code_err(ast, type_to_str(t), " values cannot be used for conditionals"); } - return CORD_EMPTY; + return EMPTY_TEXT; } -static CORD _compile_statement(env_t *env, ast_t *ast) +static Text_t _compile_statement(env_t *env, ast_t *ast) { switch (ast->tag) { case When: { @@ -1049,43 +1055,43 @@ static CORD _compile_statement(env_t *env, ast_t *ast) type_t *subject_t = get_type(env, when->subject); if (subject_t->tag != EnumType) { - CORD prefix = CORD_EMPTY, suffix = CORD_EMPTY; + Text_t prefix = EMPTY_TEXT, suffix = EMPTY_TEXT; ast_t *subject = when->subject; if (!is_idempotent(when->subject)) { - prefix = CORD_all("{\n", compile_declaration(subject_t, "_when_subject"), " = ", compile(env, subject), ";\n"); - suffix = "}\n"; - subject = LiteralCode("_when_subject", .type=subject_t); + prefix = Texts("{\n", compile_declaration(subject_t, Text("_when_subject")), " = ", compile(env, subject), ";\n"); + suffix = Text("}\n"); + subject = LiteralCode(Text("_when_subject"), .type=subject_t); } - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (when_clause_t *clause = when->clauses; clause; clause = clause->next) { ast_t *comparison = WrapAST(clause->pattern, Equals, .lhs=subject, .rhs=clause->pattern); (void)get_type(env, comparison); - if (code != CORD_EMPTY) - code = CORD_all(code, "else "); - code = CORD_all(code, "if (", compile(env, comparison), ")", compile_statement(env, clause->body)); + if (code.length > 0) + code = Texts(code, "else "); + code = Texts(code, "if (", compile(env, comparison), ")", compile_statement(env, clause->body)); } if (when->else_body) - code = CORD_all(code, "else ", compile_statement(env, when->else_body)); - code = CORD_all(prefix, code, suffix); + code = Texts(code, "else ", compile_statement(env, when->else_body)); + code = Texts(prefix, code, suffix); return code; } DeclareMatch(enum_t, subject_t, EnumType); - CORD code; + Text_t code; if (enum_has_fields(subject_t)) - code = CORD_all("WHEN(", compile_type(subject_t), ", ", compile(env, when->subject), ", _when_subject, {\n"); + code = Texts("WHEN(", compile_type(subject_t), ", ", compile(env, when->subject), ", _when_subject, {\n"); else - code = CORD_all("switch(", compile(env, when->subject), ") {\n"); + code = Texts("switch(", compile(env, when->subject), ") {\n"); for (when_clause_t *clause = when->clauses; clause; clause = clause->next) { if (clause->pattern->tag == Var) { const char *clause_tag_name = Match(clause->pattern, Var)->name; type_t *clause_type = clause->body ? get_type(env, clause->body) : Type(VoidType); - code = CORD_all(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, CORD_all("tag$", clause_tag_name)), ": {\n", + code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n", compile_inline_block(env, clause->body), - (clause_type->tag == ReturnType || clause_type->tag == AbortType) ? CORD_EMPTY : "break;\n", + (clause_type->tag == ReturnType || clause_type->tag == AbortType) ? EMPTY_TEXT : Text("break;\n"), "}\n"); continue; } @@ -1094,7 +1100,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum type"); const char *clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name; - code = CORD_all(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, CORD_all("tag$", clause_tag_name)), ": {\n"); + code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n"); type_t *tag_type = NULL; for (tag_t *tag = enum_t->tags; tag; tag = tag->next) { if (streq(tag->name, clause_tag_name)) { @@ -1112,10 +1118,10 @@ static CORD _compile_statement(env_t *env, ast_t *ast) code_err(args->value, "This is not a valid variable to bind to"); const char *var_name = Match(args->value, Var)->name; if (!streq(var_name, "_")) { - CORD var = CORD_all("_$", var_name); - code = CORD_all(code, compile_declaration(tag_type, var), " = _when_subject.", clause_tag_name, ";\n"); + Text_t var = Texts("_$", var_name); + code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.", clause_tag_name, ";\n"); scope = fresh_scope(scope); - set_binding(scope, Match(args->value, Var)->name, tag_type, CORD_EMPTY); + set_binding(scope, Match(args->value, Var)->name, tag_type, EMPTY_TEXT); } } else if (args) { scope = fresh_scope(scope); @@ -1130,8 +1136,8 @@ static CORD _compile_statement(env_t *env, ast_t *ast) const char *var_name = Match(arg->value, Var)->name; if (!streq(var_name, "_")) { - CORD var = CORD_cat("_$", var_name); - code = CORD_all(code, compile_declaration(field->type, var), " = _when_subject.", clause_tag_name, ".", field->name, ";\n"); + Text_t var = Texts("_$", var_name); + code = Texts(code, compile_declaration(field->type, var), " = _when_subject.", clause_tag_name, ".", field->name, ";\n"); set_binding(scope, Match(arg->value, Var)->name, field->type, var); } field = field->next; @@ -1140,27 +1146,27 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (clause->body->tag == Block) { ast_list_t *statements = Match(clause->body, Block)->statements; if (!statements || (statements->ast->tag == Pass && !statements->next)) - code = CORD_all(code, "break;\n}\n"); + code = Texts(code, "break;\n}\n"); else - code = CORD_all(code, compile_inline_block(scope, clause->body), "\nbreak;\n}\n"); + code = Texts(code, compile_inline_block(scope, clause->body), "\nbreak;\n}\n"); } else { - code = CORD_all(code, compile_statement(scope, clause->body), "\nbreak;\n}\n"); + code = Texts(code, compile_statement(scope, clause->body), "\nbreak;\n}\n"); } } if (when->else_body) { if (when->else_body->tag == Block) { ast_list_t *statements = Match(when->else_body, Block)->statements; if (!statements || (statements->ast->tag == Pass && !statements->next)) - code = CORD_all(code, "default: break;"); + code = Texts(code, "default: break;"); else - code = CORD_all(code, "default: {\n", compile_inline_block(env, when->else_body), "\nbreak;\n}\n"); + code = Texts(code, "default: {\n", compile_inline_block(env, when->else_body), "\nbreak;\n}\n"); } else { - code = CORD_all(code, "default: {\n", compile_statement(env, when->else_body), "\nbreak;\n}\n"); + code = Texts(code, "default: {\n", compile_statement(env, when->else_body), "\nbreak;\n}\n"); } } else { - code = CORD_all(code, "default: errx(1, \"Invalid tag!\");\n"); + code = Texts(code, "default: errx(1, \"Invalid tag!\");\n"); } - code = CORD_all(code, "\n}", enum_has_fields(subject_t) ? ")" : CORD_EMPTY, "\n"); + code = Texts(code, "\n}", enum_has_fields(subject_t) ? Text(")") : EMPTY_TEXT, "\n"); return code; } case DocTest: { @@ -1169,16 +1175,16 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (!expr_t) code_err(test->expr, "I couldn't figure out the type of this expression"); - CORD setup = CORD_EMPTY; - CORD test_code; + Text_t setup = EMPTY_TEXT; + Text_t test_code; if (test->expr->tag == Declare) { DeclareMatch(decl, test->expr, Declare); type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == FunctionType) t = Type(ClosureType, t); - CORD var = CORD_all("_$", Match(decl->var, Var)->name); - CORD val_code = compile_declared_value(env, test->expr); - setup = CORD_all(compile_declaration(t, var), ";\n"); - test_code = CORD_all("(", var, " = ", val_code, ")"); + Text_t var = Texts("_$", Match(decl->var, Var)->name); + Text_t val_code = compile_declared_value(env, test->expr); + setup = Texts(compile_declaration(t, var), ";\n"); + test_code = Texts("(", var, " = ", val_code, ")"); expr_t = t; } else if (test->expr->tag == Assign) { DeclareMatch(assign, test->expr, Assign); @@ -1191,15 +1197,15 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (has_stack_memory(lhs_t)) code_err(test->expr, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory."); env_t *val_scope = with_enum_scope(env, lhs_t); - CORD value = compile_to_type(val_scope, assign->values->ast, lhs_t); - test_code = CORD_all("(", compile_assignment(env, assign->targets->ast, value), ")"); + Text_t value = compile_to_type(val_scope, assign->values->ast, lhs_t); + test_code = Texts("(", compile_assignment(env, assign->targets->ast, value), ")"); expr_t = lhs_t; } else { // Multi-assign or assignment to potentially non-idempotent targets if (test->expected && assign->targets->next) code_err(ast, "Sorry, but doctesting with '=' is not supported for multi-assignments"); - test_code = "({ // Assignment\n"; + test_code = Text("({ // Assignment\n"); int64_t i = 1; for (ast_list_t *target = assign->targets, *value = assign->values; target && value; target = target->next, value = value->next) { @@ -1212,17 +1218,17 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (target == assign->targets) expr_t = lhs_t; env_t *val_scope = with_enum_scope(env, lhs_t); - CORD val_code = compile_to_type(val_scope, value->ast, lhs_t); - test_code = CORD_all(test_code, compile_type(lhs_t), " $", String(i), " = ", val_code, ";\n"); + Text_t val_code = compile_to_type(val_scope, value->ast, lhs_t); + test_code = Texts(test_code, compile_type(lhs_t), " $", String(i), " = ", val_code, ";\n"); i += 1; } i = 1; for (ast_list_t *target = assign->targets; target; target = target->next) { - test_code = CORD_all(test_code, compile_assignment(env, target->ast, CORD_all("$", String(i))), ";\n"); + test_code = Texts(test_code, compile_assignment(env, target->ast, Texts("$", String(i))), ";\n"); i += 1; } - test_code = CORD_all(test_code, "$1; })"); + test_code = Texts(test_code, "$1; })"); } } else if (is_update_assignment(test->expr)) { binary_operands_t update = UPDATE_OPERANDS(test->expr); @@ -1235,18 +1241,18 @@ static CORD _compile_statement(env_t *env, ast_t *ast) ast_t *update_var = new(ast_t); *update_var = *test->expr; - update_var->__data.PlusUpdate.lhs = LiteralCode("(*expr)", .type=lhs_t); // UNSAFE - test_code = CORD_all("({", - compile_declaration(Type(PointerType, lhs_t), "expr"), " = &(", compile_lvalue(env, update.lhs), "); ", + update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type=lhs_t); // UNSAFE + test_code = Texts("({", + compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(", compile_lvalue(env, update.lhs), "); ", compile_statement(env, update_var), "; *expr; })"); expr_t = lhs_t; } else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) { - test_code = CORD_all("({", compile_statement(env, test->expr), " NULL;})"); + test_code = Texts("({", compile_statement(env, test->expr), " NULL;})"); } else { test_code = compile(env, test->expr); } if (test->expected) { - return CORD_all( + return Texts( setup, "test(", compile_type(expr_t), ", ", test_code, ", ", compile_to_type(env, test->expected, expr_t), ", ", @@ -1255,13 +1261,13 @@ static CORD _compile_statement(env_t *env, ast_t *ast) String((int64_t)(test->expr->end - test->expr->file->text)), ");"); } else { if (expr_t->tag == VoidType || expr_t->tag == AbortType) { - return CORD_all( + return Texts( setup, "inspect_void(", test_code, ", ", compile_type_info(expr_t), ", ", String((int64_t)(test->expr->start - test->expr->file->text)), ", ", String((int64_t)(test->expr->end - test->expr->file->text)), ");"); } - return CORD_all( + return Texts( setup, "inspect(", compile_type(expr_t), ", ", test_code, ", ", compile_type_info(expr_t), ", ", @@ -1276,7 +1282,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) switch (expr->tag) { case And: { DeclareMatch(and_, ast, And); - return CORD_all( + return Texts( compile_statement(env, WrapAST(ast, Assert, .expr=and_->lhs, .message=message)), compile_statement(env, WrapAST(ast, Assert, .expr=and_->rhs, .message=message))); } @@ -1303,39 +1309,39 @@ static CORD _compile_statement(env_t *env, ast_t *ast) code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); } - ast_t *lhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, "_lhs")), .type=operand_t); - ast_t *rhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, "_rhs")), .type=operand_t); + ast_t *lhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, Text("_lhs"))), .type=operand_t); + ast_t *rhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, Text("_rhs"))), .type=operand_t); ast_t *var_comparison = new(ast_t, .file=expr->file, .start=expr->start, .end=expr->end, .tag=expr->tag, .__data.Equals={.lhs=lhs_var, .rhs=rhs_var}); int64_t line = get_line_number(ast->file, ast->start); - return CORD_all("{ // assertion\n", - compile_declaration(operand_t, "_lhs"), " = ", compile_to_type(env, cmp.lhs, operand_t), ";\n", + return Texts("{ // assertion\n", + compile_declaration(operand_t, Text("_lhs")), " = ", compile_to_type(env, cmp.lhs, operand_t), ";\n", "\n#line ", String(line), "\n", - compile_declaration(operand_t, "_rhs"), " = ", compile_to_type(env, cmp.rhs, operand_t), ";\n", + compile_declaration(operand_t, Text("_rhs")), " = ", compile_to_type(env, cmp.rhs, operand_t), ";\n", "\n#line ", String(line), "\n", "if (!(", compile_condition(env, var_comparison), "))\n", "#line ", String(line), "\n", - CORD_all( - "fail_source(", CORD_quoted(ast->file->filename), ", ", + Texts( + "fail_source(", quoted_str(ast->file->filename), ", ", String((int64_t)(expr->start - expr->file->text)), ", ", String((int64_t)(expr->end - expr->file->text)), ", ", - message ? CORD_all("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")") - : "\"This assertion failed!\"", ", ", - "\" (\", ", expr_as_text("_lhs", operand_t, "no"), ", " - "\" ", failure, " \", ", expr_as_text("_rhs", operand_t, "no"), ", \")\");\n"), + message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")") + : Text("\"This assertion failed!\""), ", ", + "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")), ", " + "\" ", failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"), "}\n"); } default: { int64_t line = get_line_number(ast->file, ast->start); - return CORD_all( + return Texts( "if (!(", compile_condition(env, expr), "))\n", "#line ", String(line), "\n", - "fail_source(", CORD_quoted(ast->file->filename), ", ", + "fail_source(", quoted_str(ast->file->filename), ", ", String((int64_t)(expr->start - expr->file->text)), ", ", String((int64_t)(expr->end - expr->file->text)), ", ", - message ? CORD_all("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")") - : "\"This assertion failed!\"", + message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")") + : Text("\"This assertion failed!\""), ");\n"); } } @@ -1345,17 +1351,17 @@ static CORD _compile_statement(env_t *env, ast_t *ast) const char *name = Match(decl->var, Var)->name; if (streq(name, "_")) { // Explicit discard if (decl->value) - return CORD_all("(void)", compile(env, decl->value), ";"); + return Texts("(void)", compile(env, decl->value), ";"); else - return CORD_EMPTY; + return EMPTY_TEXT; } else { type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == FunctionType) t = Type(ClosureType, t); if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType) code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value"); - CORD val_code = compile_declared_value(env, ast); - return CORD_all(compile_declaration(t, CORD_cat("_$", name)), " = ", val_code, ";"); + Text_t val_code = compile_declared_value(env, ast); + return Texts(compile_declaration(t, Texts("_$", name)), " = ", val_code, ";"); } } case Assign: { @@ -1369,11 +1375,11 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (has_stack_memory(lhs_t)) code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory."); env_t *val_env = with_enum_scope(env, lhs_t); - CORD val = compile_to_type(val_env, assign->values->ast, lhs_t); - return CORD_all(compile_assignment(env, assign->targets->ast, val), ";\n"); + Text_t val = compile_to_type(val_env, assign->values->ast, lhs_t); + return Texts(compile_assignment(env, assign->targets->ast, val), ";\n"); } - CORD code = "{ // Assignment\n"; + Text_t code = Text("{ // Assignment\n"); int64_t i = 1; for (ast_list_t *value = assign->values, *target = assign->targets; value && target; value = value->next, target = target->next) { type_t *lhs_t = get_type(env, target->ast); @@ -1383,50 +1389,50 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (has_stack_memory(lhs_t)) code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory."); env_t *val_env = with_enum_scope(env, lhs_t); - CORD val = compile_to_type(val_env, value->ast, lhs_t); - code = CORD_all(code, compile_type(lhs_t), " $", String(i), " = ", val, ";\n"); + Text_t val = compile_to_type(val_env, value->ast, lhs_t); + code = Texts(code, compile_type(lhs_t), " $", String(i), " = ", val, ";\n"); i += 1; } i = 1; for (ast_list_t *target = assign->targets; target; target = target->next) { - code = CORD_all(code, compile_assignment(env, target->ast, CORD_all("$", String(i))), ";\n"); + code = Texts(code, compile_assignment(env, target->ast, Texts("$", String(i))), ";\n"); i += 1; } - return CORD_cat(code, "\n}"); + return Texts(code, "\n}"); } case PlusUpdate: { DeclareMatch(update, ast, PlusUpdate); type_t *lhs_t = get_type(env, update->lhs); if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType)) - return CORD_all(compile_lvalue(env, update->lhs), " += ", compile_to_type(env, update->rhs, lhs_t), ";"); + return Texts(compile_lvalue(env, update->lhs), " += ", compile_to_type(env, update->rhs, lhs_t), ";"); return compile_update_assignment(env, ast); } case MinusUpdate: { DeclareMatch(update, ast, MinusUpdate); type_t *lhs_t = get_type(env, update->lhs); if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType)) - return CORD_all(compile_lvalue(env, update->lhs), " -= ", compile_to_type(env, update->rhs, lhs_t), ";"); + return Texts(compile_lvalue(env, update->lhs), " -= ", compile_to_type(env, update->rhs, lhs_t), ";"); return compile_update_assignment(env, ast); } case MultiplyUpdate: { DeclareMatch(update, ast, MultiplyUpdate); type_t *lhs_t = get_type(env, update->lhs); if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType)) - return CORD_all(compile_lvalue(env, update->lhs), " *= ", compile_to_type(env, update->rhs, lhs_t), ";"); + return Texts(compile_lvalue(env, update->lhs), " *= ", compile_to_type(env, update->rhs, lhs_t), ";"); return compile_update_assignment(env, ast); } case DivideUpdate: { DeclareMatch(update, ast, DivideUpdate); type_t *lhs_t = get_type(env, update->lhs); if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType)) - return CORD_all(compile_lvalue(env, update->lhs), " /= ", compile_to_type(env, update->rhs, lhs_t), ";"); + return Texts(compile_lvalue(env, update->lhs), " /= ", compile_to_type(env, update->rhs, lhs_t), ";"); return compile_update_assignment(env, ast); } case ModUpdate: { DeclareMatch(update, ast, ModUpdate); type_t *lhs_t = get_type(env, update->lhs); if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType)) - return CORD_all(compile_lvalue(env, update->lhs), " %= ", compile_to_type(env, update->rhs, lhs_t), ";"); + return Texts(compile_lvalue(env, update->lhs), " %= ", compile_to_type(env, update->rhs, lhs_t), ";"); return compile_update_assignment(env, ast); } case PowerUpdate: case Mod1Update: case ConcatUpdate: case LeftShiftUpdate: case UnsignedLeftShiftUpdate: @@ -1434,28 +1440,28 @@ static CORD _compile_statement(env_t *env, ast_t *ast) return compile_update_assignment(env, ast); } case StructDef: case EnumDef: case LangDef: case Extend: case FunctionDef: case ConvertDef: { - return CORD_EMPTY; + return EMPTY_TEXT; } case Skip: { const char *target = Match(ast, Skip)->target; for (loop_ctx_t *ctx = env->loop_ctx; ctx; ctx = ctx->next) { - bool matched = !target || CORD_cmp(target, ctx->loop_name) == 0; + bool matched = !target || strcmp(target, ctx->loop_name) == 0; for (ast_list_t *var = ctx->loop_vars; var && !matched; var = var ? var->next : NULL) - matched = (CORD_cmp(target, Match(var->ast, Var)->name) == 0); + matched = (strcmp(target, Match(var->ast, Var)->name) == 0); if (matched) { - if (!ctx->skip_label) { + if (ctx->skip_label.length == 0) { static int64_t skip_label_count = 1; - ctx->skip_label = CORD_all("skip_", String(skip_label_count)); + ctx->skip_label = Texts("skip_", String(skip_label_count)); ++skip_label_count; } - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred; deferred = deferred->next) - code = CORD_all(code, compile_statement(deferred->defer_env, deferred->block)); - if (code) - return CORD_all("{\n", code, "goto ", ctx->skip_label, ";\n}\n"); + code = Texts(code, compile_statement(deferred->defer_env, deferred->block)); + if (code.length > 0) + return Texts("{\n", code, "goto ", ctx->skip_label, ";\n}\n"); else - return CORD_all("goto ", ctx->skip_label, ";"); + return Texts("goto ", ctx->skip_label, ";"); } } if (env->loop_ctx) @@ -1463,28 +1469,28 @@ static CORD _compile_statement(env_t *env, ast_t *ast) else if (target) code_err(ast, "No loop target named '", target, "' was found"); else - return "continue;"; + return Text("continue;"); } case Stop: { const char *target = Match(ast, Stop)->target; for (loop_ctx_t *ctx = env->loop_ctx; ctx; ctx = ctx->next) { - bool matched = !target || CORD_cmp(target, ctx->loop_name) == 0; + bool matched = !target || strcmp(target, ctx->loop_name) == 0; for (ast_list_t *var = ctx->loop_vars; var && !matched; var = var ? var->next : var) - matched = (CORD_cmp(target, Match(var->ast, Var)->name) == 0); + matched = (strcmp(target, Match(var->ast, Var)->name) == 0); if (matched) { - if (!ctx->stop_label) { + if (ctx->stop_label.length == 0) { static int64_t stop_label_count = 1; - ctx->stop_label = CORD_all("stop_", String(stop_label_count)); + ctx->stop_label = Texts("stop_", String(stop_label_count)); ++stop_label_count; } - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred; deferred = deferred->next) - code = CORD_all(code, compile_statement(deferred->defer_env, deferred->block)); - if (code) - return CORD_all("{\n", code, "goto ", ctx->stop_label, ";\n}\n"); + code = Texts(code, compile_statement(deferred->defer_env, deferred->block)); + if (code.length > 0) + return Texts("{\n", code, "goto ", ctx->stop_label, ";\n}\n"); else - return CORD_all("goto ", ctx->stop_label, ";"); + return Texts("goto ", ctx->stop_label, ";"); } } if (env->loop_ctx) @@ -1492,26 +1498,26 @@ static CORD _compile_statement(env_t *env, ast_t *ast) else if (target) code_err(ast, "No loop target named '", target, "' was found"); else - return "break;"; + return Text("break;"); } - case Pass: return ";"; + case Pass: return Text(";"); case Defer: { ast_t *body = Match(ast, Defer)->body; Table_t closed_vars = get_closed_vars(env, NULL, body); static int defer_id = 0; env_t *defer_env = fresh_scope(env); - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (int64_t i = 0; i < closed_vars.entries.length; i++) { struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i; if (entry->b->type->tag == ModuleType) continue; - if (CORD_ncmp(entry->b->code, 0, "userdata->", 0, strlen("userdata->")) == 0) { + if (Text$starts_with(entry->b->code, Text("userdata->"))) { Table$str_set(defer_env->locals, entry->name, entry->b); } else { - CORD defer_name = CORD_all("defer$", String(++defer_id), "$", entry->name); + Text_t defer_name = Texts("defer$", String(++defer_id), "$", entry->name); defer_id += 1; - code = CORD_all( + code = Texts( code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n"); set_binding(defer_env, entry->name, entry->b->type, defer_name); } @@ -1523,9 +1529,9 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (!env->fn_ret) code_err(ast, "This return statement is not inside any function"); ast_t *ret = Match(ast, Return)->value; - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (deferral_t *deferred = env->deferred; deferred; deferred = deferred->next) { - code = CORD_all(code, compile_statement(deferred->defer_env, deferred->block)); + code = Texts(code, compile_statement(deferred->defer_env, deferred->block)); } if (ret) { @@ -1533,17 +1539,17 @@ static CORD _compile_statement(env_t *env, ast_t *ast) code_err(ast, "This function is not supposed to return any values, according to its type signature"); env = with_enum_scope(env, env->fn_ret); - CORD value = compile_to_type(env, ret, env->fn_ret); + Text_t value = compile_to_type(env, ret, env->fn_ret); if (env->deferred) { - code = CORD_all(compile_declaration(env->fn_ret, "ret"), " = ", value, ";\n", code); - value = "ret"; + code = Texts(compile_declaration(env->fn_ret, Text("ret")), " = ", value, ";\n", code); + value = Text("ret"); } - return CORD_all(code, "return ", value, ";"); + return Texts(code, "return ", value, ";"); } else { if (env->fn_ret->tag != VoidType) code_err(ast, "This function expects you to return a ", type_to_str(env->fn_ret), " value"); - return CORD_all(code, "return;"); + return Texts(code, "return;"); } } case While: { @@ -1555,12 +1561,12 @@ static CORD _compile_statement(env_t *env, ast_t *ast) .next=env->loop_ctx, }; scope->loop_ctx = &loop_ctx; - CORD body = compile_statement(scope, while_->body); - if (loop_ctx.skip_label) - body = CORD_all(body, "\n", loop_ctx.skip_label, ": continue;"); - CORD loop = CORD_all("while (", while_->condition ? compile(scope, while_->condition) : "yes", ") {\n\t", body, "\n}"); - if (loop_ctx.stop_label) - loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;"); + Text_t body = compile_statement(scope, while_->body); + if (loop_ctx.skip_label.length > 0) + body = Texts(body, "\n", loop_ctx.skip_label, ": continue;"); + Text_t loop = Texts("while (", while_->condition ? compile(scope, while_->condition) : Text("yes"), ") {\n\t", body, "\n}"); + if (loop_ctx.stop_label.length > 0) + loop = Texts(loop, "\n", loop_ctx.stop_label, ":;"); return loop; } case Repeat: { @@ -1572,12 +1578,12 @@ static CORD _compile_statement(env_t *env, ast_t *ast) .next=env->loop_ctx, }; scope->loop_ctx = &loop_ctx; - CORD body_code = compile_statement(scope, body); - if (loop_ctx.skip_label) - body_code = CORD_all(body_code, "\n", loop_ctx.skip_label, ": continue;"); - CORD loop = CORD_all("for (;;) {\n\t", body_code, "\n}"); - if (loop_ctx.stop_label) - loop = CORD_all(loop, "\n", loop_ctx.stop_label, ":;"); + Text_t body_code = compile_statement(scope, body); + if (loop_ctx.skip_label.length > 0) + body_code = Texts(body_code, "\n", loop_ctx.skip_label, ": continue;"); + Text_t loop = Texts("for (;;) {\n\t", body_code, "\n}"); + if (loop_ctx.stop_label.length > 0) + loop = Texts(loop, "\n", loop_ctx.stop_label, ":;"); return loop; } case For: { @@ -1615,10 +1621,10 @@ static CORD _compile_statement(env_t *env, ast_t *ast) }; body_scope->loop_ctx = &loop_ctx; // Naked means no enclosing braces: - CORD naked_body = compile_inline_block(body_scope, for_->body); - if (loop_ctx.skip_label) - naked_body = CORD_all(naked_body, "\n", loop_ctx.skip_label, ": continue;"); - CORD stop = loop_ctx.stop_label ? CORD_all("\n", loop_ctx.stop_label, ":;") : CORD_EMPTY; + Text_t naked_body = compile_inline_block(body_scope, for_->body); + if (loop_ctx.skip_label.length > 0) + naked_body = Texts(naked_body, "\n", loop_ctx.skip_label, ": continue;"); + Text_t stop = loop_ctx.stop_label.length > 0 ? Texts("\n", loop_ctx.stop_label, ":;") : EMPTY_TEXT; // Special case for improving performance for numeric iteration: if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "to") && @@ -1630,7 +1636,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) type_t *int_type = get_type(env, Match(for_->iter, MethodCall)->self); type_t *step_type = int_type->tag == ByteType ? Type(IntType, .bits=TYPE_IBITS8) : int_type; - CORD last = CORD_EMPTY, step = CORD_EMPTY, optional_step = CORD_EMPTY; + Text_t last = EMPTY_TEXT, step = EMPTY_TEXT, optional_step = EMPTY_TEXT; if (!args->name || streq(args->name, "last")) { last = compile_to_type(env, args->value, int_type); if (args->next) { @@ -1653,17 +1659,17 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } } - if (!last) + if (last.length == 0) code_err(for_->iter, "No `last` argument was given"); - CORD type_code = compile_type(int_type); - CORD value = for_->vars ? compile(body_scope, for_->vars->ast) : "i"; + Text_t type_code = compile_type(int_type); + Text_t value = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i"); if (int_type->tag == BigIntType) { - if (optional_step) - step = CORD_all("({ OptionalInt_t maybe_step = ", optional_step, "; maybe_step->small == 0 ? (Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)) : (Int_t)maybe_step; })"); - else if (!step) - step = "Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)"; - return CORD_all( + if (optional_step.length > 0) + step = Texts("({ OptionalInt_t maybe_step = ", optional_step, "; maybe_step->small == 0 ? (Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)) : (Int_t)maybe_step; })"); + else if (step.length == 0) + step = Text("Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)"); + return Texts( "for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ", value, " = first, last = ", last, ", step = ", step, "; " "Int$compare_value(", value, ", last) != Int$compare_value(step, I_small(0)); ", @@ -1672,12 +1678,12 @@ static CORD _compile_statement(env_t *env, ast_t *ast) "}", stop); } else { - if (optional_step) - step = CORD_all("({ ", compile_type(Type(OptionalType, step_type)), " maybe_step = ", optional_step, "; " + if (optional_step.length > 0) + step = Texts("({ ", compile_type(Type(OptionalType, step_type)), " maybe_step = ", optional_step, "; " "maybe_step.is_none ? (", type_code, ")(last >= first ? 1 : -1) : maybe_step.value; })"); - else if (!step) - step = CORD_all("(", type_code, ")(last >= first ? 1 : -1)"); - return CORD_all( + else if (step.length == 0) + step = Texts("(", type_code, ")(last >= first ? 1 : -1)"); + return Texts( "for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ", value, " = first, last = ", last, ", step = ", step, "; " "step > 0 ? ", value, " <= last : ", value, " >= last; ", @@ -1691,9 +1697,9 @@ static CORD _compile_statement(env_t *env, ast_t *ast) // Special case for Int.onward() arg_ast_t *args = Match(for_->iter, MethodCall)->args; arg_t *arg_spec = new(arg_t, .name="step", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1"), .next=NULL); - CORD step = compile_arguments(env, for_->iter, arg_spec, args); - CORD value = for_->vars ? compile(body_scope, for_->vars->ast) : "i"; - return CORD_all( + Text_t step = compile_arguments(env, for_->iter, arg_spec, args); + Text_t value = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i"); + return Texts( "for (Int_t ", value, " = ", compile(env, Match(for_->iter, MethodCall)->self), ", ", "step = ", step, "; ; ", value, " = Int$plus(", value, ", step)) {\n" "\t", naked_body, @@ -1707,8 +1713,8 @@ static CORD _compile_statement(env_t *env, ast_t *ast) switch (iter_value_t->tag) { case ListType: { type_t *item_t = Match(iter_value_t, ListType)->item_type; - CORD index = CORD_EMPTY; - CORD value = CORD_EMPTY; + Text_t index = EMPTY_TEXT; + Text_t value = EMPTY_TEXT; if (for_->vars) { if (for_->vars->next) { if (for_->vars->next->next) @@ -1721,26 +1727,26 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } } - CORD loop = CORD_EMPTY; - loop = CORD_all(loop, "for (int64_t i = 1; i <= iterating.length; ++i)"); + Text_t loop = EMPTY_TEXT; + loop = Texts(loop, "for (int64_t i = 1; i <= iterating.length; ++i)"); - if (index != CORD_EMPTY) - naked_body = CORD_all("Int_t ", index, " = I(i);\n", naked_body); + if (index.length > 0) + naked_body = Texts("Int_t ", index, " = I(i);\n", naked_body); - if (value != CORD_EMPTY) { - loop = CORD_all(loop, "{\n", + if (value.length > 0) { + loop = Texts(loop, "{\n", compile_declaration(item_t, value), " = *(", compile_type(item_t), "*)(iterating.data + (i-1)*iterating.stride);\n", naked_body, "\n}"); } else { - loop = CORD_all(loop, "{\n", naked_body, "\n}"); + loop = Texts(loop, "{\n", naked_body, "\n}"); } if (for_->empty) - loop = CORD_all("if (iterating.length > 0) {\n", loop, "\n} else ", compile_statement(env, for_->empty)); + loop = Texts("if (iterating.length > 0) {\n", loop, "\n} else ", compile_statement(env, for_->empty)); if (iter_t->tag == PointerType) { - loop = CORD_all("{\n" + loop = Texts("{\n" "List_t *ptr = ", compile_to_pointer_depth(env, for_->iter, 1, false), ";\n" "\nLIST_INCREF(*ptr);\n" "List_t iterating = *ptr;\n", @@ -1750,7 +1756,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) "}\n"); } else { - loop = CORD_all("{\n" + loop = Texts("{\n" "List_t iterating = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n", loop, stop, @@ -1759,19 +1765,19 @@ static CORD _compile_statement(env_t *env, ast_t *ast) return loop; } case SetType: case TableType: { - CORD loop = "for (int64_t i = 0; i < iterating.length; ++i) {\n"; + Text_t loop = Text("for (int64_t i = 0; i < iterating.length; ++i) {\n"); if (for_->vars) { if (iter_value_t->tag == SetType) { if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop"); - CORD item = compile(body_scope, for_->vars->ast); + Text_t item = compile(body_scope, for_->vars->ast); type_t *item_type = Match(iter_value_t, SetType)->item_type; - loop = CORD_all(loop, compile_declaration(item_type, item), " = *(", compile_type(item_type), "*)(", + loop = Texts(loop, compile_declaration(item_type, item), " = *(", compile_type(item_type), "*)(", "iterating.data + i*iterating.stride);\n"); } else { - CORD key = compile(body_scope, for_->vars->ast); + Text_t key = compile(body_scope, for_->vars->ast); type_t *key_t = Match(iter_value_t, TableType)->key_type; - loop = CORD_all(loop, compile_declaration(key_t, key), " = *(", compile_type(key_t), "*)(", + loop = Texts(loop, compile_declaration(key_t, key), " = *(", compile_type(key_t), "*)(", "iterating.data + i*iterating.stride);\n"); if (for_->vars->next) { @@ -1779,22 +1785,22 @@ static CORD _compile_statement(env_t *env, ast_t *ast) code_err(for_->vars->next->next->ast, "This is too many variables for this loop"); type_t *value_t = Match(iter_value_t, TableType)->value_type; - CORD value = compile(body_scope, for_->vars->next->ast); - CORD value_offset = CORD_all("offsetof(struct { ", compile_declaration(key_t, "k"), "; ", compile_declaration(value_t, "v"), "; }, v)"); - loop = CORD_all(loop, compile_declaration(value_t, value), " = *(", compile_type(value_t), "*)(", + Text_t value = compile(body_scope, for_->vars->next->ast); + Text_t value_offset = Texts("offsetof(struct { ", compile_declaration(key_t, Text("k")), "; ", compile_declaration(value_t, Text("v")), "; }, v)"); + loop = Texts(loop, compile_declaration(value_t, value), " = *(", compile_type(value_t), "*)(", "iterating.data + i*iterating.stride + ", value_offset, ");\n"); } } } - loop = CORD_all(loop, naked_body, "\n}"); + loop = Texts(loop, naked_body, "\n}"); if (for_->empty) { - loop = CORD_all("if (iterating.length > 0) {\n", loop, "\n} else ", compile_statement(env, for_->empty)); + loop = Texts("if (iterating.length > 0) {\n", loop, "\n} else ", compile_statement(env, for_->empty)); } if (iter_t->tag == PointerType) { - loop = CORD_all( + loop = Texts( "{\n", "Table_t *t = ", compile_to_pointer_depth(env, for_->iter, 1, false), ";\n" "LIST_INCREF(t->entries);\n" @@ -1803,7 +1809,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) "LIST_DECREF(t->entries);\n" "}\n"); } else { - loop = CORD_all( + loop = Texts( "{\n", "List_t iterating = (", compile_to_pointer_depth(env, for_->iter, 0, false), ").entries;\n", loop, @@ -1812,7 +1818,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) return loop; } case BigIntType: { - CORD n; + Text_t n; if (for_->iter->tag == Int) { const char *str = Match(for_->iter, Int)->str; Int_t int_val = Int$from_str(str); @@ -1821,7 +1827,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) mpz_t i; mpz_init_set_int(i, int_val); if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) - n = mpz_get_str(NULL, 10, i); + n = Text$from_str(mpz_get_str(NULL, 10, i)); else goto big_n; @@ -1829,9 +1835,9 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (for_->empty && mpz_cmp_si(i, 0) <= 0) { return compile_statement(env, for_->empty); } else { - return CORD_all( + return Texts( "for (int64_t i = 1; i <= ", n, "; ++i) {\n", - for_->vars ? CORD_all("\tInt_t ", compile(body_scope, for_->vars->ast), " = I_small(i);\n") : CORD_EMPTY, + for_->vars ? Texts("\tInt_t ", compile(body_scope, for_->vars->ast), " = I_small(i);\n") : EMPTY_TEXT, "\t", naked_body, "}\n", stop, "\n"); @@ -1840,10 +1846,10 @@ static CORD _compile_statement(env_t *env, ast_t *ast) big_n: n = compile_to_pointer_depth(env, for_->iter, 0, false); - CORD i = for_->vars ? compile(body_scope, for_->vars->ast) : "i"; - CORD n_var = for_->vars ? CORD_all("max", i) : "n"; + Text_t i = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i"); + Text_t n_var = for_->vars ? Texts("max", i) : Text("n"); if (for_->empty) { - return CORD_all( + return Texts( "{\n" "Int_t ", n_var, " = ", n, ";\n" "if (Int$compare_value(", n_var, ", I(0)) > 0) {\n" @@ -1854,7 +1860,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) stop, "\n" "}\n"); } else { - return CORD_all( + return Texts( "for (Int_t ", i, " = I(1), ", n_var, " = ", n, "; Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n", "\t", naked_body, "}\n", @@ -1863,19 +1869,19 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } case FunctionType: case ClosureType: { // Iterator function: - CORD code = "{\n"; + Text_t code = Text("{\n"); - CORD next_fn; + Text_t next_fn; if (is_idempotent(for_->iter)) { next_fn = compile_to_pointer_depth(env, for_->iter, 0, false); } else { - code = CORD_all(code, compile_declaration(iter_value_t, "next"), " = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n"); - next_fn = "next"; + code = Texts(code, compile_declaration(iter_value_t, Text("next")), " = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n"); + next_fn = Text("next"); } __typeof(iter_value_t->__data.FunctionType) *fn = iter_value_t->tag == ClosureType ? Match(Match(iter_value_t, ClosureType)->fn, FunctionType) : Match(iter_value_t, FunctionType); - CORD get_next; + Text_t get_next; if (iter_value_t->tag == ClosureType) { type_t *fn_t = Match(iter_value_t, ClosureType)->fn; arg_t *closure_fn_args = NULL; @@ -1883,40 +1889,40 @@ static CORD _compile_statement(env_t *env, ast_t *ast) closure_fn_args = new(arg_t, .name=arg->name, .type=arg->type, .default_val=arg->default_val, .next=closure_fn_args); closure_fn_args = new(arg_t, .name="userdata", .type=Type(PointerType, .pointed=Type(MemoryType)), .next=closure_fn_args); REVERSE_LIST(closure_fn_args); - CORD fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret)); - get_next = CORD_all("((", fn_type_code, ")", next_fn, ".fn)(", next_fn, ".userdata)"); + Text_t fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret)); + get_next = Texts("((", fn_type_code, ")", next_fn, ".fn)(", next_fn, ".userdata)"); } else { - get_next = CORD_all(next_fn, "()"); + get_next = Texts(next_fn, "()"); } if (fn->ret->tag == OptionalType) { // Use an optional variable `cur` for each iteration step, which will be checked for none - code = CORD_all(code, compile_declaration(fn->ret, "cur"), ";\n"); - get_next = CORD_all("(cur=", get_next, ", !", check_none(fn->ret, "cur"), ")"); + code = Texts(code, compile_declaration(fn->ret, Text("cur")), ";\n"); + get_next = Texts("(cur=", get_next, ", !", check_none(fn->ret, Text("cur")), ")"); if (for_->vars) { - naked_body = CORD_all( - compile_declaration(Match(fn->ret, OptionalType)->type, CORD_all("_$", Match(for_->vars->ast, Var)->name)), - " = ", optional_into_nonnone(fn->ret, "cur"), ";\n", + naked_body = Texts( + compile_declaration(Match(fn->ret, OptionalType)->type, Texts("_$", Match(for_->vars->ast, Var)->name)), + " = ", optional_into_nonnone(fn->ret, Text("cur")), ";\n", naked_body); } if (for_->empty) { - code = CORD_all(code, "if (", get_next, ") {\n" + code = Texts(code, "if (", get_next, ") {\n" "\tdo{\n\t\t", naked_body, "\t} while(", get_next, ");\n" "} else {\n\t", compile_statement(env, for_->empty), "}", stop, "\n}\n"); } else { - code = CORD_all(code, "while(", get_next, ") {\n\t", naked_body, "}\n", stop, "\n}\n"); + code = Texts(code, "while(", get_next, ") {\n\t", naked_body, "}\n", stop, "\n}\n"); } } else { if (for_->vars) { - naked_body = CORD_all( - compile_declaration(fn->ret, CORD_all("_$", Match(for_->vars->ast, Var)->name)), + naked_body = Texts( + compile_declaration(fn->ret, Texts("_$", Match(for_->vars->ast, Var)->name)), " = ", get_next, ";\n", naked_body); } else { - naked_body = CORD_all(get_next, ";\n", naked_body); + naked_body = Texts(get_next, ";\n", naked_body); } if (for_->empty) code_err(for_->empty, "This iteration loop will always have values, so this block will never run"); - code = CORD_all(code, "for (;;) {\n\t", naked_body, "}\n", stop, "\n}\n"); + code = Texts(code, "for (;;) {\n\t", naked_body, "}\n", stop, "\n}\n"); } return code; @@ -1931,22 +1937,22 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (Match(condition, Declare)->value == NULL) code_err(condition, "This declaration must have a value"); env_t *truthy_scope = fresh_scope(env); - CORD code = CORD_all("IF_DECLARE(", compile_statement(truthy_scope, condition), ", "); + Text_t code = Texts("IF_DECLARE(", compile_statement(truthy_scope, condition), ", "); bind_statement(truthy_scope, condition); ast_t *var = Match(condition, Declare)->var; - code = CORD_all(code, compile_condition(truthy_scope, var), ", "); + code = Texts(code, compile_condition(truthy_scope, var), ", "); type_t *cond_t = get_type(truthy_scope, var); if (cond_t->tag == OptionalType) { set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type, optional_into_nonnone(cond_t, compile(truthy_scope, var))); } - code = CORD_all(code, compile_statement(truthy_scope, if_->body), ")"); + code = Texts(code, compile_statement(truthy_scope, if_->body), ")"); if (if_->else_body) - code = CORD_all(code, "\nelse ", compile_statement(env, if_->else_body)); + code = Texts(code, "\nelse ", compile_statement(env, if_->else_body)); return code; } else { - CORD code = CORD_all("if (", compile_condition(env, condition), ")"); + Text_t code = Texts("if (", compile_condition(env, condition), ")"); env_t *truthy_scope = env; type_t *cond_t = get_type(env, condition); if (condition->tag == Var && cond_t->tag == OptionalType) { @@ -1955,14 +1961,14 @@ static CORD _compile_statement(env_t *env, ast_t *ast) Match(cond_t, OptionalType)->type, optional_into_nonnone(cond_t, compile(truthy_scope, condition))); } - code = CORD_all(code, compile_statement(truthy_scope, if_->body)); + code = Texts(code, compile_statement(truthy_scope, if_->body)); if (if_->else_body) - code = CORD_all(code, "\nelse ", compile_statement(env, if_->else_body)); + code = Texts(code, "\nelse ", compile_statement(env, if_->else_body)); return code; } } case Block: { - return CORD_all("{\n", compile_inline_block(env, ast), "}\n"); + return Texts("{\n", compile_inline_block(env, ast), "}\n"); } case Comprehension: { if (!env->comprehension_action) @@ -1982,15 +1988,15 @@ static CORD _compile_statement(env_t *env, ast_t *ast) ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body); return compile_statement(env, loop); } - case Extern: return CORD_EMPTY; + case Extern: return EMPTY_TEXT; case InlineCCode: { DeclareMatch(inline_code, ast, InlineCCode); - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (ast_list_t *chunk = inline_code->chunks; chunk; chunk = chunk->next) { if (chunk->ast->tag == TextLiteral) { - code = CORD_all(code, Match(chunk->ast, TextLiteral)->cord); + code = Texts(code, Match(chunk->ast, TextLiteral)->text); } else { - code = CORD_all(code, compile(env, chunk->ast)); + code = Texts(code, compile(env, chunk->ast)); } } return code; @@ -2001,8 +2007,8 @@ static CORD _compile_statement(env_t *env, ast_t *ast) Path_t path = Path$from_str(Match(ast, Use)->path); Path_t in_file = Path$from_str(ast->file->filename); path = Path$resolved(path, Path$parent(in_file)); - CORD suffix = get_id_suffix(Path$as_c_string(path)); - return with_source_info(env, ast, CORD_all("$initialize", suffix, "();\n")); + Text_t suffix = get_id_suffix(Path$as_c_string(path)); + return with_source_info(env, ast, Texts("$initialize", suffix, "();\n")); } else if (use->what == USE_MODULE) { module_info_t mod = get_module_info(ast); glob_t tm_files; @@ -2012,69 +2018,69 @@ static CORD _compile_statement(env_t *env, ast_t *ast) code_err(ast, "Could not find library"); } - CORD initialization = CORD_EMPTY; + Text_t initialization = EMPTY_TEXT; for (size_t i = 0; i < tm_files.gl_pathc; i++) { const char *filename = tm_files.gl_pathv[i]; - initialization = CORD_all( + initialization = Texts( initialization, - with_source_info(env, ast, CORD_all("$initialize", get_id_suffix(filename), "();\n"))); + with_source_info(env, ast, Texts("$initialize", get_id_suffix(filename), "();\n"))); } globfree(&tm_files); return initialization; } else { - return CORD_EMPTY; + return EMPTY_TEXT; } } default: // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ", is_discardable(env, ast)); if (!is_discardable(env, ast)) code_err(ast, "The ", type_to_str(get_type(env, ast)), " result of this statement cannot be discarded"); - return CORD_all("(void)", compile(env, ast), ";"); + return Texts("(void)", compile(env, ast), ";"); } } -CORD compile_statement(env_t *env, ast_t *ast) { - CORD stmt = _compile_statement(env, ast); +Text_t compile_statement(env_t *env, ast_t *ast) { + Text_t stmt = _compile_statement(env, ast); return with_source_info(env, ast, stmt); } -CORD expr_as_text(CORD expr, type_t *t, CORD color) +Text_t expr_as_text(Text_t expr, type_t *t, Text_t color) { switch (t->tag) { - case MemoryType: return CORD_all("Memory$as_text(stack(", expr, "), ", color, ", &Memory$info)"); + case MemoryType: return Texts("Memory$as_text(stack(", expr, "), ", color, ", &Memory$info)"); case BoolType: // NOTE: this cannot use stack(), since bools may actually be bit fields: - return CORD_all("Bool$as_text((Bool_t[1]){", expr, "}, ", color, ", &Bool$info)"); - case CStringType: return CORD_all("CString$as_text(stack(", expr, "), ", color, ", &CString$info)"); + return Texts("Bool$as_text((Bool_t[1]){", expr, "}, ", color, ", &Bool$info)"); + case CStringType: return Texts("CString$as_text(stack(", expr, "), ", color, ", &CString$info)"); case BigIntType: case IntType: case ByteType: case NumType: { - CORD name = type_to_cord(t); - return CORD_all(name, "$as_text(stack(", expr, "), ", color, ", &", name, "$info)"); - } - case TextType: return CORD_all("Text$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - case ListType: return CORD_all("List$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - case SetType: return CORD_all("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - case TableType: return CORD_all("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - case FunctionType: case ClosureType: return CORD_all("Func$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - case PointerType: return CORD_all("Pointer$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - case OptionalType: return CORD_all("Optional$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + Text_t name = type_to_text(t); + return Texts(name, "$as_text(stack(", expr, "), ", color, ", &", name, "$info)"); + } + case TextType: return Texts("Text$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + case ListType: return Texts("List$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + case SetType: return Texts("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + case TableType: return Texts("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + case FunctionType: case ClosureType: return Texts("Func$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + case PointerType: return Texts("Pointer$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + case OptionalType: return Texts("Optional$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); case StructType: case EnumType: - return CORD_all("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); + return Texts("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_str(t)); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_string(env_t *env, ast_t *ast, CORD color) +Text_t compile_text(env_t *env, ast_t *ast, Text_t color) { type_t *t = get_type(env, ast); - CORD expr = compile(env, ast); + Text_t expr = compile(env, ast); return expr_as_text(expr, t, color); } -CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) +Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) { - CORD val = compile(env, ast); + Text_t val = compile(env, ast); type_t *t = get_type(env, ast); int64_t depth = 0; for (type_t *tt = t; tt->tag == PointerType; tt = Match(tt, PointerType)->pointed) @@ -2088,14 +2094,14 @@ CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool while (depth != target_depth) { if (depth < target_depth) { if (ast->tag == Var && target_depth == 1) - val = CORD_all("(&", val, ")"); + val = Texts("(&", val, ")"); else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast))); t = Type(PointerType, .pointed=t, .is_stack=true); ++depth; } else { DeclareMatch(ptr, t, PointerType); - val = CORD_all("*(", val, ")"); + val = Texts("*(", val, ")"); t = ptr->pointed; --depth; } @@ -2107,22 +2113,22 @@ CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool } if (needs_incref && t->tag == ListType) - val = CORD_all("LIST_COPY(", val, ")"); + val = Texts("LIST_COPY(", val, ")"); else if (needs_incref && (t->tag == TableType || t->tag == SetType)) - val = CORD_all("TABLE_COPY(", val, ")"); + val = Texts("TABLE_COPY(", val, ")"); return val; } -CORD compile_to_type(env_t *env, ast_t *ast, type_t *t) +Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) { if (ast->tag == Int && is_numeric_type(non_optional(t))) { return compile_int_to_type(env, ast, t); } else if (ast->tag == Num && t->tag == NumType) { double n = Match(ast, Num)->n; switch (Match(t, NumType)->bits) { - case TYPE_NBITS64: return String(hex_double(n)); - case TYPE_NBITS32: return String(hex_double(n), "f"); + case TYPE_NBITS64: return Text$from_str(String(hex_double(n))); + case TYPE_NBITS32: return Text$from_str(String(hex_double(n), "f")); default: code_err(ast, "This is not a valid number bit width"); } } else if (ast->tag == None) { @@ -2171,19 +2177,19 @@ CORD compile_to_type(env_t *env, ast_t *ast, type_t *t) // Promote values to views-of-values if needed: if (t->tag == PointerType && Match(t, PointerType)->is_stack && actual->tag != PointerType) - return CORD_all("stack(", compile_to_type(env, ast, Match(t, PointerType)->pointed), ")"); + return Texts("stack(", compile_to_type(env, ast, Match(t, PointerType)->pointed), ")"); - CORD code = compile(env, ast); + Text_t code = compile(env, ast); if (!promote(env, ast, &code, actual, t)) code_err(ast, "I expected a ", type_to_str(t), " here, but this is a ", type_to_str(actual)); return code; } -CORD compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) +Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) { DeclareMatch(list, ast, List); if (!list->items) - return "(List_t){.length=0}"; + return Text("(List_t){.length=0}"); type_t *item_type = Match(list_type, ListType)->item_type; @@ -2198,11 +2204,11 @@ CORD compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env; if (is_incomplete_type(item_type)) code_err(ast, "This list's type can't be inferred!"); - CORD code = CORD_all("TypedListN(", compile_type(item_type), ", ", String(n)); + Text_t code = Texts("TypedListN(", compile_type(item_type), ", ", String(n)); for (ast_list_t *item = list->items; item; item = item->next) { - code = CORD_all(code, ", ", compile_to_type(scope, item->ast, item_type)); + code = Texts(code, ", ", compile_to_type(scope, item->ast, item_type)); } - return CORD_cat(code, ")"); + return Texts(code, ")"); } list_comprehension: @@ -2210,28 +2216,28 @@ CORD compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env); static int64_t comp_num = 1; const char *comprehension_name = String("list$", comp_num++); - ast_t *comprehension_var = LiteralCode(CORD_all("&", comprehension_name), + ast_t *comprehension_var = 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; - CORD code = CORD_all("({ List_t ", comprehension_name, " = {};"); + Text_t code = Texts("({ List_t ", comprehension_name, " = {};"); // 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 = CORD_all(code, "\n", compile_statement(scope, item->ast)); + code = Texts(code, "\n", compile_statement(scope, item->ast)); else - code = CORD_all(code, compile_statement(env, add_to_list_comprehension(item->ast, comprehension_var))); + code = Texts(code, compile_statement(env, add_to_list_comprehension(item->ast, comprehension_var))); } - code = CORD_all(code, " ", comprehension_name, "; })"); + code = Texts(code, " ", comprehension_name, "; })"); return code; } } -CORD compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) +Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) { DeclareMatch(set, ast, Set); if (!set->items) - return "((Table_t){})"; + return Text("((Table_t){})"); type_t *item_type = Match(set_type, SetType)->item_type; @@ -2243,15 +2249,15 @@ CORD compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) } { // No comprehension: - CORD code = CORD_all("Set(", + Text_t code = Texts("Set(", compile_type(item_type), ", ", compile_type_info(item_type), ", ", String(n)); env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env; for (ast_list_t *item = set->items; item; item = item->next) { - code = CORD_all(code, ", ", compile_to_type(scope, item->ast, item_type)); + code = Texts(code, ", ", compile_to_type(scope, item->ast, item_type)); } - return CORD_cat(code, ")"); + return Texts(code, ")"); } set_comprehension: @@ -2259,30 +2265,30 @@ CORD compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) static int64_t comp_num = 1; env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env); const char *comprehension_name = String("set$", comp_num++); - ast_t *comprehension_var = LiteralCode(CORD_all("&", comprehension_name), + ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name), .type=Type(PointerType, .pointed=set_type, .is_stack=true)); - CORD code = CORD_all("({ Table_t ", comprehension_name, " = {};"); + Text_t code = Texts("({ Table_t ", comprehension_name, " = {};"); Closure_t comp_action = {.fn=add_to_set_comprehension, .userdata=comprehension_var}; scope->comprehension_action = &comp_action; for (ast_list_t *item = set->items; item; item = item->next) { if (item->ast->tag == Comprehension) - code = CORD_all(code, "\n", compile_statement(scope, item->ast)); + code = Texts(code, "\n", compile_statement(scope, item->ast)); else - code = CORD_all(code, compile_statement(env, add_to_set_comprehension(item->ast, comprehension_var))); + code = Texts(code, compile_statement(env, add_to_set_comprehension(item->ast, comprehension_var))); } - code = CORD_all(code, " ", comprehension_name, "; })"); + code = Texts(code, " ", comprehension_name, "; })"); return code; } } -CORD compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) +Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) { DeclareMatch(table, ast, Table); if (!table->entries) { - CORD code = "((Table_t){"; + Text_t code = Text("((Table_t){"); if (table->fallback) - code = CORD_all(code, ".fallback=heap(", compile(env, table->fallback),")"); - return CORD_cat(code, "})"); + code = Texts(code, ".fallback=heap(", compile(env, table->fallback),")"); + return Texts(code, "})"); } type_t *key_t = Match(table_type, TableType)->key_type; @@ -2299,27 +2305,27 @@ CORD compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) { // No comprehension: env_t *key_scope = key_t->tag == EnumType ? with_enum_scope(env, key_t) : env; env_t *value_scope = value_t->tag == EnumType ? with_enum_scope(env, value_t) : env; - CORD code = CORD_all("Table(", + Text_t code = Texts("Table(", compile_type(key_t), ", ", compile_type(value_t), ", ", compile_type_info(key_t), ", ", compile_type_info(value_t)); if (table->fallback) - code = CORD_all(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")"); + code = Texts(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")"); else - code = CORD_all(code, ", /*fallback:*/ NULL"); + code = Texts(code, ", /*fallback:*/ NULL"); size_t n = 0; for (ast_list_t *entry = table->entries; entry; entry = entry->next) ++n; - code = CORD_all(code, ", ", String((int64_t)n)); + code = Texts(code, ", ", String((int64_t)n)); for (ast_list_t *entry = table->entries; entry; entry = entry->next) { DeclareMatch(e, entry->ast, TableEntry); - code = CORD_all(code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ", + code = Texts(code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ", compile_to_type(value_scope, e->value, value_t), "}"); } - return CORD_cat(code, ")"); + return Texts(code, ")"); } table_comprehension: @@ -2327,52 +2333,52 @@ CORD compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) static int64_t comp_num = 1; env_t *scope = fresh_scope(env); const char *comprehension_name = String("table$", comp_num++); - ast_t *comprehension_var = LiteralCode(CORD_all("&", comprehension_name), + ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name), .type=Type(PointerType, .pointed=table_type, .is_stack=true)); - CORD code = CORD_all("({ Table_t ", comprehension_name, " = {"); + Text_t code = Texts("({ Table_t ", comprehension_name, " = {"); if (table->fallback) - code = CORD_all(code, ".fallback=heap(", compile(env, table->fallback), "), "); + code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), "); - code = CORD_cat(code, "};"); + code = Texts(code, "};"); Closure_t comp_action = {.fn=add_to_table_comprehension, .userdata=comprehension_var}; scope->comprehension_action = &comp_action; for (ast_list_t *entry = table->entries; entry; entry = entry->next) { if (entry->ast->tag == Comprehension) - code = CORD_all(code, "\n", compile_statement(scope, entry->ast)); + code = Texts(code, "\n", compile_statement(scope, entry->ast)); else - code = CORD_all(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var))); + code = Texts(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var))); } - code = CORD_all(code, " ", comprehension_name, "; })"); + code = Texts(code, " ", comprehension_name, "; })"); return code; } } -CORD compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type) +Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type) { // TODO: for constructors, do new(T, ...) instead of heap((T){...}) type_t *pointed = Match(pointer_type, PointerType)->pointed; switch (ast->tag) { case HeapAllocate: { - return CORD_all("heap(", compile_to_type(env, Match(ast, HeapAllocate)->value, pointed), ")"); + return Texts("heap(", compile_to_type(env, Match(ast, HeapAllocate)->value, pointed), ")"); } case StackReference: { ast_t *subject = Match(ast, StackReference)->value; if (can_be_mutated(env, subject) && type_eq(pointed, get_type(env, subject))) - return CORD_all("(&", compile_lvalue(env, subject), ")"); + return Texts("(&", compile_lvalue(env, subject), ")"); else - return CORD_all("stack(", compile_to_type(env, subject, pointed), ")"); + return Texts("stack(", compile_to_type(env, subject, pointed), ")"); } default: code_err(ast, "Not an allocation!"); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target) +Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { if (ast->tag != Int) { - CORD code = compile(env, ast); + Text_t code = compile(env, ast); type_t *actual_type = get_type(env, ast); if (!promote(env, ast, &code, actual_type, target)) code_err(ast, "I couldn't promote this ", type_to_str(actual_type), " to a ", type_to_str(target)); @@ -2404,34 +2410,34 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target) if (target->tag == ByteType) { if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0) - return CORD_all("(Byte_t)(", c_literal, ")"); + return Texts("(Byte_t)(", c_literal, ")"); code_err(ast, "This integer cannot fit in a byte"); } else if (target->tag == NumType) { if (Match(target, NumType)->bits == TYPE_NBITS64) { - return CORD_all("N64(", c_literal, ")"); + return Texts("N64(", c_literal, ")"); } else { - return CORD_all("N32(", c_literal, ")"); + return Texts("N32(", c_literal, ")"); } } else if (target->tag == IntType) { int64_t target_bits = (int64_t)Match(target, IntType)->bits; switch (target_bits) { case TYPE_IBITS64: if (mpz_cmp_si(i, INT64_MIN) == 0) - return "I64(INT64_MIN)"; + return Text("I64(INT64_MIN)"); if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) - return CORD_all("I64(", c_literal, "L)"); + return Texts("I64(", c_literal, "L)"); break; case TYPE_IBITS32: if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0) - return CORD_all("I32(", c_literal, ")"); + return Texts("I32(", c_literal, ")"); break; case TYPE_IBITS16: if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0) - return CORD_all("I16(", c_literal, ")"); + return Texts("I16(", c_literal, ")"); break; case TYPE_IBITS8: if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0) - return CORD_all("I8(", c_literal, ")"); + return Texts("I8(", c_literal, ")"); break; default: break; } @@ -2439,13 +2445,13 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target) } else { code_err(ast, "I don't know how to compile this to a ", type_to_str(target)); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) +Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) { Table_t used_args = {}; - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; env_t *default_scope = new(env_t); *default_scope = *env; default_scope->locals = new(Table_t, .fallback=env->namespace_bindings ? env->namespace_bindings : env->globals); @@ -2455,7 +2461,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t if (spec_arg->name) { for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) { if (call_arg->name && streq(call_arg->name, spec_arg->name)) { - CORD value; + Text_t value; if (spec_arg->type->tag == IntType && call_arg->value->tag == Int) { value = compile_int_to_type(env, call_arg->value, spec_arg->type); } else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) { @@ -2463,16 +2469,16 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer"); if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64) - value = String(hex_double(Num$from_int(int_val, false))); + value = Text$from_str(String(hex_double(Num$from_int(int_val, false)))); else - value = String(hex_double((double)Num32$from_int(int_val, false)), "f"); + value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f")); } else { env_t *arg_env = with_enum_scope(env, spec_arg->type); value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type); } Table$str_set(&used_args, call_arg->name, call_arg); - if (code) code = CORD_cat(code, ", "); - code = CORD_cat(code, value); + if (code.length > 0) code = Texts(code, ", "); + code = Texts(code, value); goto found_it; } } @@ -2482,7 +2488,7 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t if (call_arg->name) continue; const char *pseudoname = String(i++); if (!Table$str_get(used_args, pseudoname)) { - CORD value; + Text_t value; if (spec_arg->type->tag == IntType && call_arg->value->tag == Int) { value = compile_int_to_type(env, call_arg->value, spec_arg->type); } else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) { @@ -2490,24 +2496,24 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer"); if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64) - value = String(hex_double(Num$from_int(int_val, false))); + value = Text$from_str(String(hex_double(Num$from_int(int_val, false)))); else - value = String(hex_double((double)Num32$from_int(int_val, false)), "f"); + value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f")); } else { env_t *arg_env = with_enum_scope(env, spec_arg->type); value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type); } Table$str_set(&used_args, pseudoname, call_arg); - if (code) code = CORD_cat(code, ", "); - code = CORD_cat(code, value); + if (code.length > 0) code = Texts(code, ", "); + code = Texts(code, value); goto found_it; } } if (spec_arg->default_val) { - if (code) code = CORD_cat(code, ", "); - code = CORD_cat(code, compile_maybe_incref(default_scope, spec_arg->default_val, get_arg_type(env, spec_arg))); + if (code.length > 0) code = Texts(code, ", "); + code = Texts(code, compile_maybe_incref(default_scope, spec_arg->default_val, get_arg_type(env, spec_arg))); goto found_it; } @@ -2530,58 +2536,46 @@ CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t return code; } -CORD compile_string_literal(CORD literal) +Text_t compile_text_literal(Text_t literal) { - CORD code = "\""; - CORD_pos i; -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - CORD_FOR(i, literal) { -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - uint8_t c = (uint8_t)CORD_pos_fetch(i); - switch (c) { - case '\\': code = CORD_cat(code, "\\\\"); break; - case '"': code = CORD_cat(code, "\\\""); break; - case '\a': code = CORD_cat(code, "\\a"); break; - case '\b': code = CORD_cat(code, "\\b"); break; - case '\n': code = CORD_cat(code, "\\n"); break; - case '\r': code = CORD_cat(code, "\\r"); break; - case '\t': code = CORD_cat(code, "\\t"); break; - case '\v': code = CORD_cat(code, "\\v"); break; + Text_t code = Text("\""); + const char *utf8 = Text$as_c_string(literal); + for (const char *p = utf8; *p; p++) { + switch (*p) { + case '\\': code = Texts(code, "\\\\"); break; + case '"': code = Texts(code, "\\\""); break; + case '\a': code = Texts(code, "\\a"); break; + case '\b': code = Texts(code, "\\b"); break; + case '\n': code = Texts(code, "\\n"); break; + case '\r': code = Texts(code, "\\r"); break; + case '\t': code = Texts(code, "\\t"); break; + case '\v': code = Texts(code, "\\v"); break; default: { - if (isprint(c)) - code = CORD_cat_char(code, (char)c); - else - code = CORD_all(code, "\\x", String(hex((uint64_t)c, .no_prefix=true, .uppercase=true, .digits=2)), "\"\""); + if (isprint(*p)) { + code = Texts(code, Text$from_strn(p, 1)); + } else { + uint8_t byte = *(uint8_t*)p; + code = Texts(code, "\\x", String(hex(byte, .no_prefix=true, .uppercase=true, .digits=2)), "\"\""); + } break; } } } - return CORD_cat(code, "\""); + return Texts(code, "\""); } -static bool string_literal_is_all_ascii(CORD literal) +PUREFUNC static bool string_literal_is_all_ascii(Text_t literal) { - CORD_pos i; -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - CORD_FOR(i, literal) { -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - if (!isascii(CORD_pos_fetch(i))) + TextIter_t state = NEW_TEXT_ITER_STATE(literal); + for (int64_t i = 0; i < literal.length; i++) { + int32_t g = Text$get_grapheme_fast(&state, i); + if (g < 0 || g > 127 || !isascii(g)) return false; } return true; } -CORD compile_none(type_t *t) +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"); @@ -2592,42 +2586,42 @@ CORD 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 "NONE_PATH"; - else if (t == PATH_TYPE_TYPE) return "((OptionalPathType_t){})"; + if (t == PATH_TYPE) return Text("NONE_PATH"); + else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})"); switch (t->tag) { - case BigIntType: return "NONE_INT"; + case BigIntType: return Text("NONE_INT"); case IntType: { switch (Match(t, IntType)->bits) { - case TYPE_IBITS8: return "NONE_INT8"; - case TYPE_IBITS16: return "NONE_INT16"; - case TYPE_IBITS32: return "NONE_INT32"; - case TYPE_IBITS64: return "NONE_INT64"; + case TYPE_IBITS8: return Text("NONE_INT8"); + case TYPE_IBITS16: return Text("NONE_INT16"); + case TYPE_IBITS32: return Text("NONE_INT32"); + case TYPE_IBITS64: return Text("NONE_INT64"); default: errx(1, "Invalid integer bit size"); } break; } - case BoolType: return "NONE_BOOL"; - case ByteType: return "NONE_BYTE"; - case ListType: return "NONE_LIST"; - case TableType: return "NONE_TABLE"; - case SetType: return "NONE_TABLE"; - case TextType: return "NONE_TEXT"; - case CStringType: return "NULL"; - case PointerType: return CORD_all("((", compile_type(t), ")NULL)"); - case ClosureType: return "NONE_CLOSURE"; - case NumType: return "nan(\"none\")"; - case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_none=true})"); + case BoolType: return Text("NONE_BOOL"); + case ByteType: return Text("NONE_BYTE"); + case ListType: return Text("NONE_LIST"); + case TableType: return Text("NONE_TABLE"); + case SetType: return Text("NONE_TABLE"); + case TextType: return Text("NONE_TEXT"); + case CStringType: return Text("NULL"); + case PointerType: return Texts("((", compile_type(t), ")NULL)"); + case ClosureType: return Text("NONE_CLOSURE"); + case NumType: return Text("nan(\"none\")"); + case StructType: return Texts("((", compile_type(Type(OptionalType, .type=t)), "){.is_none=true})"); case EnumType: { env_t *enum_env = Match(t, EnumType)->env; - return CORD_all("((", compile_type(t), "){", namespace_name(enum_env, enum_env->namespace, "none"), "})"); + return Texts("((", compile_type(t), "){", namespace_name(enum_env, enum_env->namespace, Text("none")), "})"); } default: compiler_err(NULL, NULL, NULL, "none isn't implemented for this type: ", type_to_str(t)); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_empty(type_t *t) +Text_t compile_empty(type_t *t) { if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a value with no type"); @@ -2635,50 +2629,50 @@ CORD compile_empty(type_t *t) if (t->tag == OptionalType) return compile_none(t); - if (t == PATH_TYPE) return "NONE_PATH"; - else if (t == PATH_TYPE_TYPE) return "((OptionalPathType_t){})"; + if (t == PATH_TYPE) return Text("NONE_PATH"); + else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})"); switch (t->tag) { - case BigIntType: return "I(0)"; + case BigIntType: return Text("I(0)"); case IntType: { switch (Match(t, IntType)->bits) { - case TYPE_IBITS8: return "I8(0)"; - case TYPE_IBITS16: return "I16(0)"; - case TYPE_IBITS32: return "I32(0)"; - case TYPE_IBITS64: return "I64(0)"; + case TYPE_IBITS8: return Text("I8(0)"); + case TYPE_IBITS16: return Text("I16(0)"); + case TYPE_IBITS32: return Text("I32(0)"); + case TYPE_IBITS64: return Text("I64(0)"); default: errx(1, "Invalid integer bit size"); } break; } - case ByteType: return "((Byte_t)0)"; - case BoolType: return "((Bool_t)no)"; - case ListType: return "((List_t){})"; - case TableType: case SetType: return "((Table_t){})"; - case TextType: return "Text(\"\")"; - case CStringType: return "\"\""; + case ByteType: return Text("((Byte_t)0)"); + case BoolType: return Text("((Bool_t)no)"); + case ListType: return Text("((List_t){})"); + case TableType: case SetType: return Text("((Table_t){})"); + case TextType: return Text("Text(\"\")"); + case CStringType: return Text("\"\""); case PointerType: { DeclareMatch(ptr, t, PointerType); - CORD empty_pointed = compile_empty(ptr->pointed); - return empty_pointed == CORD_EMPTY ? CORD_EMPTY : CORD_all(ptr->is_stack ? "stack(" : "heap(", empty_pointed, ")"); + Text_t empty_pointed = compile_empty(ptr->pointed); + return empty_pointed.length == 0 ? EMPTY_TEXT : Texts(ptr->is_stack ? Text("stack(") : Text("heap("), empty_pointed, ")"); } case NumType: { - return Match(t, NumType)->bits == TYPE_NBITS32 ? "N32(0.0f)" : "N64(0.0)" ; + return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("N32(0.0f)") : Text("N64(0.0)"); } case StructType: { DeclareMatch(struct_, t, StructType); - CORD code = CORD_all("((", compile_type(t), "){"); + Text_t code = Texts("((", compile_type(t), "){"); for (arg_t *field = struct_->fields; field; field = field->next) { - CORD empty_field = field->default_val + Text_t empty_field = field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type); - if (empty_field == CORD_EMPTY) - return CORD_EMPTY; + if (empty_field.length == 0) + return EMPTY_TEXT; - code = CORD_all(code, empty_field); + code = Texts(code, empty_field); if (field->next) - code = CORD_all(code, ", "); + code = Texts(code, ", "); } - return CORD_all(code, "})"); + return Texts(code, "})"); } case EnumType: { DeclareMatch(enum_, t, EnumType); @@ -2686,18 +2680,18 @@ CORD compile_empty(type_t *t) assert(tag); assert(tag->type); if (Match(tag->type, StructType)->fields) - return CORD_all("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", compile_empty(tag->type), "})"); + return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", compile_empty(tag->type), "})"); else if (enum_has_fields(t)) - return CORD_all("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})"); + return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})"); else - return CORD_all("((", compile_type(t), ")", String(tag->tag_value), ")"); + return Texts("((", compile_type(t), ")", String(tag->tag_value), ")"); } - default: return CORD_EMPTY; + default: return EMPTY_TEXT; } - return CORD_EMPTY; + return EMPTY_TEXT; } -static CORD compile_declared_value(env_t *env, ast_t *declare_ast) +static Text_t compile_declared_value(env_t *env, ast_t *declare_ast) { DeclareMatch(decl, declare_ast, Declare); type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); @@ -2706,15 +2700,15 @@ static CORD compile_declared_value(env_t *env, ast_t *declare_ast) code_err(declare_ast, "You can't declare a variable with a ", type_to_str(t), " value"); if (decl->value) { - CORD val_code = compile_maybe_incref(env, decl->value, t); + Text_t val_code = compile_maybe_incref(env, decl->value, t); if (t->tag == FunctionType) { assert(promote(env, decl->value, &val_code, t, Type(ClosureType, t))); t = Type(ClosureType, t); } return val_code; } else { - CORD val_code = compile_empty(t); - if (val_code == CORD_EMPTY) + Text_t val_code = compile_empty(t); + if (val_code.length == 0) code_err(declare_ast, "This type (", type_to_str(t), ") cannot be uninitialized. You must provide a value."); return val_code; } @@ -2737,18 +2731,18 @@ ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject) return WrapAST(item, MethodCall, .name="add", .self=subject, .args=new(arg_ast_t, .value=item)); } -CORD compile(env_t *env, ast_t *ast) +Text_t compile(env_t *env, ast_t *ast) { switch (ast->tag) { case None: { code_err(ast, "I can't figure out what this `none`'s type is!"); } - case Bool: return Match(ast, Bool)->b ? "yes" : "no"; + case Bool: return Match(ast, Bool)->b ? Text("yes") : Text("no"); case Var: { binding_t *b = get_binding(env, Match(ast, Var)->name); if (b) - return b->code ? b->code : CORD_cat("_$", Match(ast, Var)->name); - // return CORD_cat("_$", Match(ast, Var)->name); + return b->code.length > 0 ? b->code : Texts("_$", Match(ast, Var)->name); + // return Texts("_$", Match(ast, Var)->name); code_err(ast, "I don't know of any variable by this name"); } case Int: { @@ -2759,15 +2753,15 @@ CORD compile(env_t *env, ast_t *ast) mpz_t i; mpz_init_set_int(i, int_val); if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) { - return CORD_all("I_small(", str, ")"); + return Texts("I_small(", str, ")"); } else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) { - return CORD_all("Int$from_int64(", str, ")"); + return Texts("Int$from_int64(", str, ")"); } else { - return CORD_all("Int$from_str(\"", str, "\")"); + return Texts("Int$from_str(\"", str, "\")"); } } case Num: { - return String(hex_double(Match(ast, Num)->n)); + return Text$from_str(String(hex_double(Match(ast, Num)->n))); } case Not: { ast_t *value = Match(ast, Not)->value; @@ -2777,19 +2771,19 @@ CORD compile(env_t *env, ast_t *ast) if (b && b->type->tag == FunctionType) { DeclareMatch(fn, b->type, FunctionType); if (fn->args && can_promote(t, get_arg_type(env, fn->args))) - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")"); } if (t->tag == BoolType) - return CORD_all("!(", compile(env, value), ")"); + return Texts("!(", compile(env, value), ")"); else if (t->tag == IntType || t->tag == ByteType) - return CORD_all("~(", compile(env, value), ")"); + return Texts("~(", compile(env, value), ")"); else if (t->tag == ListType) - return CORD_all("((", compile(env, value), ").length == 0)"); + return Texts("((", compile(env, value), ").length == 0)"); else if (t->tag == SetType || t->tag == TableType) - return CORD_all("((", compile(env, value), ").entries.length == 0)"); + return Texts("((", compile(env, value), ").entries.length == 0)"); else if (t->tag == TextType) - return CORD_all("(", compile(env, value), " == CORD_EMPTY)"); + return Texts("(", compile(env, value), ".length == 0)"); else if (t->tag == OptionalType) return check_none(t, compile(env, value)); @@ -2802,11 +2796,11 @@ CORD compile(env_t *env, ast_t *ast) if (b && b->type->tag == FunctionType) { DeclareMatch(fn, b->type, FunctionType); if (fn->args && can_promote(t, get_arg_type(env, fn->args))) - return CORD_all(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")"); } if (t->tag == IntType || t->tag == NumType) - return CORD_all("-(", compile(env, value), ")"); + return Texts("-(", compile(env, value), ")"); code_err(ast, "I don't know how to get the negative value of type ", type_to_str(t)); @@ -2816,22 +2810,22 @@ CORD compile(env_t *env, ast_t *ast) } case Optional: { ast_t *value = Match(ast, Optional)->value; - CORD value_code = compile(env, value); + Text_t value_code = compile(env, value); return promote_to_optional(get_type(env, value), value_code); } case NonOptional: { ast_t *value = Match(ast, NonOptional)->value; type_t *t = get_type(env, value); - CORD value_code = compile(env, value); + Text_t value_code = compile(env, value); int64_t line = get_line_number(ast->file, ast->start); - return CORD_all("({ ", compile_declaration(t, "opt"), " = ", value_code, "; ", - "if unlikely (", check_none(t, "opt"), ")\n", + return Texts("({ ", compile_declaration(t, Text("opt")), " = ", value_code, "; ", + "if unlikely (", check_none(t, Text("opt")), ")\n", "#line ", String(line), "\n", - "fail_source(", CORD_quoted(ast->file->filename), ", ", + "fail_source(", quoted_str(ast->file->filename), ", ", String((int64_t)(value->start - value->file->text)), ", ", String((int64_t)(value->end - value->file->text)), ", ", "\"This was expected to be a value, but it's none\");\n", - optional_into_nonnone(t, "opt"), "; })"); + optional_into_nonnone(t, Text("opt")), "; })"); } case Power: case Multiply: case Divide: case Mod: case Mod1: case Plus: case Minus: case Concat: case LeftShift: case UnsignedLeftShift: case RightShift: case UnsignedRightShift: case And: case Or: case Xor: { @@ -2855,17 +2849,17 @@ CORD compile(env_t *env, ast_t *ast) code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); } - CORD lhs, rhs; + Text_t lhs, rhs; lhs = compile_to_type(env, binop.lhs, operand_t); rhs = compile_to_type(env, binop.rhs, operand_t); switch (operand_t->tag) { case BigIntType: - return CORD_all(ast->tag == Equals ? CORD_EMPTY : "!", "Int$equal_value(", lhs, ", ", rhs, ")"); + return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"), "Int$equal_value(", lhs, ", ", rhs, ")"); case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType: - return CORD_all("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")"); + return Texts("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")"); default: - return CORD_all(ast->tag == Equals ? CORD_EMPTY : "!", + return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"), "generic_equal(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")"); } } @@ -2887,60 +2881,60 @@ CORD compile(env_t *env, ast_t *ast) code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); } - CORD lhs = compile_to_type(env, cmp.lhs, operand_t); - CORD rhs = compile_to_type(env, cmp.rhs, operand_t); + Text_t lhs = compile_to_type(env, cmp.lhs, operand_t); + Text_t rhs = compile_to_type(env, cmp.rhs, operand_t); if (ast->tag == Compare) - return CORD_all("generic_compare(stack(", lhs, "), stack(", rhs, "), ", + return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")"); const char *op = binop_operator(ast->tag); switch (operand_t->tag) { case BigIntType: - return CORD_all("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)"); + return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)"); case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType: - return CORD_all("(", lhs, " ", op, " ", rhs, ")"); + return Texts("(", lhs, " ", op, " ", rhs, ")"); default: - return CORD_all("(generic_compare(stack(", lhs, "), stack(", rhs, "), ", + return Texts("(generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ") ", op, " 0)"); } } case TextLiteral: { - CORD literal = Match(ast, TextLiteral)->cord; - if (literal == CORD_EMPTY) - return "EMPTY_TEXT"; + Text_t literal = Match(ast, TextLiteral)->text; + if (literal.length == 0) + return Text("EMPTY_TEXT"); if (string_literal_is_all_ascii(literal)) - return CORD_all("Text(", compile_string_literal(literal), ")"); + return Texts("Text(", compile_text_literal(literal), ")"); else - return CORD_all("Text$from_str(", compile_string_literal(literal), ")"); + return Texts("Text$from_str(", compile_text_literal(literal), ")"); } case TextJoin: { const char *lang = Match(ast, TextJoin)->lang; - const char *colorize = Match(ast, TextJoin)->colorize ? "yes" : "no"; + Text_t colorize = Match(ast, TextJoin)->colorize ? Text("yes") : Text("no"); type_t *text_t = lang ? Table$str_get(*env->types, lang) : TEXT_TYPE; if (!text_t || text_t->tag != TextType) code_err(ast, quoted(lang), " is not a valid text language name"); - CORD lang_constructor; + Text_t lang_constructor; if (!lang || streq(lang, "Text")) - lang_constructor = "Text"; + lang_constructor = Text("Text"); else - lang_constructor = namespace_name(Match(text_t, TextType)->env, Match(text_t, TextType)->env->namespace->parent, lang); + lang_constructor = namespace_name(Match(text_t, TextType)->env, Match(text_t, TextType)->env->namespace->parent, Text$from_str(lang)); ast_list_t *chunks = Match(ast, TextJoin)->children; if (!chunks) { - return CORD_all(lang_constructor, "(\"\")"); + return Texts(lang_constructor, "(\"\")"); } else if (!chunks->next && chunks->ast->tag == TextLiteral) { - CORD literal = Match(chunks->ast, TextLiteral)->cord; + Text_t literal = Match(chunks->ast, TextLiteral)->text; if (string_literal_is_all_ascii(literal)) - return CORD_all(lang_constructor, "(", compile_string_literal(literal), ")"); - return CORD_all("((", compile_type(text_t), ")", compile(env, chunks->ast), ")"); + return Texts(lang_constructor, "(", compile_text_literal(literal), ")"); + return Texts("((", compile_type(text_t), ")", compile(env, chunks->ast), ")"); } else { - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (ast_list_t *chunk = chunks; chunk; chunk = chunk->next) { - CORD chunk_code; + Text_t chunk_code; type_t *chunk_t = get_type(env, chunk->ast); if (chunk->ast->tag == TextLiteral || type_eq(chunk_t, text_t)) { chunk_code = compile(env, chunk->ast); @@ -2949,52 +2943,52 @@ CORD compile(env_t *env, ast_t *ast) if (constructor) { arg_t *arg_spec = Match(constructor->type, FunctionType)->args; arg_ast_t *args = new(arg_ast_t, .value=chunk->ast); - chunk_code = CORD_all(constructor->code, "(", compile_arguments(env, ast, arg_spec, args), ")"); + chunk_code = Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, args), ")"); } else if (type_eq(text_t, TEXT_TYPE)) { if (chunk_t->tag == TextType) chunk_code = compile(env, chunk->ast); else - chunk_code = compile_string(env, chunk->ast, colorize); + chunk_code = compile_text(env, chunk->ast, colorize); } else { code_err(chunk->ast, "I don't know how to convert ", type_to_str(chunk_t), " to ", type_to_str(text_t)); } } - code = CORD_cat(code, chunk_code); - if (chunk->next) code = CORD_cat(code, ", "); + code = Texts(code, chunk_code); + if (chunk->next) code = Texts(code, ", "); } if (chunks->next) - return CORD_all(lang_constructor, "s(", code, ")"); + return Texts(lang_constructor, "s(", code, ")"); else return code; } } case Path: { - return CORD_all("Path(", compile_string_literal(Match(ast, Path)->path), ")"); + return Texts("Path(", compile_text_literal(Text$from_str(Match(ast, Path)->path)), ")"); } case Block: { ast_list_t *stmts = Match(ast, Block)->statements; if (stmts && !stmts->next) return compile(env, stmts->ast); - CORD code = "({\n"; + Text_t code = Text("({\n"); deferral_t *prev_deferred = env->deferred; env = fresh_scope(env); for (ast_list_t *stmt = stmts; stmt; stmt = stmt->next) prebind_statement(env, stmt->ast); for (ast_list_t *stmt = stmts; stmt; stmt = stmt->next) { if (stmt->next) { - code = CORD_all(code, compile_statement(env, stmt->ast), "\n"); + code = Texts(code, compile_statement(env, stmt->ast), "\n"); } else { // TODO: put defer after evaluating block expression for (deferral_t *deferred = env->deferred; deferred && deferred != prev_deferred; deferred = deferred->next) { - code = CORD_all(code, compile_statement(deferred->defer_env, deferred->block)); + code = Texts(code, compile_statement(deferred->defer_env, deferred->block)); } - code = CORD_all(code, compile(env, stmt->ast), ";\n"); + code = Texts(code, compile(env, stmt->ast), ";\n"); } bind_statement(env, stmt->ast); } - return CORD_cat(code, "})"); + return Texts(code, "})"); } case Min: case Max: { type_t *t = get_type(env, ast); @@ -3005,23 +2999,23 @@ CORD compile(env_t *env, ast_t *ast) if (key == NULL) key = FakeAST(Var, key_name); env_t *expr_env = fresh_scope(env); - set_binding(expr_env, key_name, t, "ternary$lhs"); - CORD lhs_key = compile(expr_env, key); + set_binding(expr_env, key_name, t, Text("ternary$lhs")); + Text_t lhs_key = compile(expr_env, key); - set_binding(expr_env, key_name, t, "ternary$rhs"); - CORD rhs_key = compile(expr_env, key); + set_binding(expr_env, key_name, t, Text("ternary$rhs")); + Text_t rhs_key = compile(expr_env, key); type_t *key_t = get_type(expr_env, key); - CORD comparison; + Text_t comparison; if (key_t->tag == BigIntType) - comparison = CORD_all("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)"); + comparison = Texts("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)"); else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType || key_t->tag == ByteType) - comparison = CORD_all("((", lhs_key, ")", (ast->tag == Min ? "<=" : ">="), "(", rhs_key, "))"); + comparison = Texts("((", lhs_key, ")", (ast->tag == Min ? "<=" : ">="), "(", rhs_key, "))"); else - comparison = CORD_all("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t), ")", + comparison = Texts("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t), ")", (ast->tag == Min ? "<=" : ">="), "0"); - return CORD_all( + return Texts( "({\n", compile_type(t), " ternary$lhs = ", compile(env, lhs), ", ternary$rhs = ", compile(env, rhs), ";\n", comparison, " ? ternary$lhs : ternary$rhs;\n" @@ -3030,7 +3024,7 @@ CORD compile(env_t *env, ast_t *ast) case List: { DeclareMatch(list, ast, List); if (!list->items) - return "(List_t){.length=0}"; + return Text("(List_t){.length=0}"); type_t *list_type = get_type(env, ast); return compile_typed_list(env, ast, list_type); @@ -3038,10 +3032,10 @@ CORD compile(env_t *env, ast_t *ast) case Table: { DeclareMatch(table, ast, Table); if (!table->entries) { - CORD code = "((Table_t){"; + Text_t code = Text("((Table_t){"); if (table->fallback) - code = CORD_all(code, ".fallback=heap(", compile(env, table->fallback),")"); - return CORD_cat(code, "})"); + code = Texts(code, ".fallback=heap(", compile(env, table->fallback),")"); + return Texts(code, "})"); } type_t *table_type = get_type(env, ast); @@ -3050,7 +3044,7 @@ CORD compile(env_t *env, ast_t *ast) case Set: { DeclareMatch(set, ast, Set); if (!set->items) - return "((Table_t){})"; + return Text("((Table_t){})"); type_t *set_type = get_type(env, ast); return compile_typed_set(env, ast, set_type); @@ -3066,13 +3060,13 @@ CORD compile(env_t *env, ast_t *ast) } case Lambda: { DeclareMatch(lambda, ast, Lambda); - CORD name = namespace_name(env, env->namespace, CORD_all("lambda$", String(lambda->id))); + Text_t name = namespace_name(env, env->namespace, Texts("lambda$", String(lambda->id))); env_t *body_scope = fresh_scope(env); body_scope->deferred = NULL; for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - set_binding(body_scope, arg->name, arg_type, CORD_all("_$", arg->name)); + set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name)); } type_t *ret_t = get_type(body_scope, lambda->body); @@ -3092,7 +3086,7 @@ CORD compile(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 - CORD def = "typedef struct {"; + Text_t def = Text("typedef struct {"); for (int64_t i = 0; i < closed_vars.entries.length; i++) { struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i; if (has_stack_memory(entry->b->type)) @@ -3100,56 +3094,56 @@ CORD compile(env_t *env, ast_t *ast) " stack memory in the variable `", entry->name, "`, but the function may outlive the stack memory"); if (entry->b->type->tag == ModuleType) continue; - set_binding(body_scope, entry->name, entry->b->type, CORD_cat("userdata->", entry->name)); - def = CORD_all(def, compile_declaration(entry->b->type, entry->name), "; "); + set_binding(body_scope, entry->name, entry->b->type, Texts("userdata->", entry->name)); + def = Texts(def, compile_declaration(entry->b->type, Text$from_str(entry->name)), "; "); } - def = CORD_all(def, "} ", name, "$userdata_t;"); - env->code->local_typedefs = CORD_all(env->code->local_typedefs, def); + def = Texts(def, "} ", name, "$userdata_t;"); + env->code->local_typedefs = Texts(env->code->local_typedefs, def); } - CORD code = CORD_all("static ", compile_type(ret_t), " ", name, "("); + Text_t code = Texts("static ", compile_type(ret_t), " ", name, "("); for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - code = CORD_all(code, compile_type(arg_type), " _$", arg->name, ", "); + code = Texts(code, compile_type(arg_type), " _$", arg->name, ", "); } - CORD userdata; + Text_t userdata; if (Table$length(closed_vars) == 0) { - code = CORD_cat(code, "void *_)"); - userdata = "NULL"; + code = Texts(code, "void *_)"); + userdata = Text("NULL"); } else { - userdata = CORD_all("new(", name, "$userdata_t"); + userdata = Texts("new(", name, "$userdata_t"); for (int64_t i = 0; i < closed_vars.entries.length; i++) { struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i; if (entry->b->type->tag == ModuleType) continue; binding_t *b = get_binding(env, entry->name); assert(b); - CORD binding_code = b->code; + Text_t binding_code = b->code; if (entry->b->type->tag == ListType) - userdata = CORD_all(userdata, ", LIST_COPY(", binding_code, ")"); + userdata = Texts(userdata, ", LIST_COPY(", binding_code, ")"); else if (entry->b->type->tag == TableType || entry->b->type->tag == SetType) - userdata = CORD_all(userdata, ", TABLE_COPY(", binding_code, ")"); + userdata = Texts(userdata, ", TABLE_COPY(", binding_code, ")"); else - userdata = CORD_all(userdata, ", ", binding_code); + userdata = Texts(userdata, ", ", binding_code); } - userdata = CORD_all(userdata, ")"); - code = CORD_all(code, name, "$userdata_t *userdata)"); + userdata = Texts(userdata, ")"); + code = Texts(code, name, "$userdata_t *userdata)"); } - CORD body = CORD_EMPTY; + Text_t body = EMPTY_TEXT; for (ast_list_t *stmt = Match(lambda->body, Block)->statements; stmt; stmt = stmt->next) { if (stmt->next || ret_t->tag == VoidType || ret_t->tag == AbortType || get_type(body_scope, stmt->ast)->tag == ReturnType) - body = CORD_all(body, compile_statement(body_scope, stmt->ast), "\n"); + body = Texts(body, compile_statement(body_scope, stmt->ast), "\n"); else - body = CORD_all(body, compile_statement(body_scope, FakeAST(Return, stmt->ast)), "\n"); + body = Texts(body, compile_statement(body_scope, FakeAST(Return, stmt->ast)), "\n"); bind_statement(body_scope, stmt->ast); } if ((ret_t->tag == VoidType || ret_t->tag == AbortType) && body_scope->deferred) - body = CORD_all(body, compile_statement(body_scope, FakeAST(Return)), "\n"); + body = Texts(body, compile_statement(body_scope, FakeAST(Return)), "\n"); - env->code->lambdas = CORD_all(env->code->lambdas, code, " {\n", body, "\n}\n"); - return CORD_all("((Closure_t){", name, ", ", userdata, "})"); + env->code->lambdas = Texts(env->code->lambdas, code, " {\n", body, "\n}\n"); + return Texts("((Closure_t){", name, ", ", userdata, "})"); } case MethodCall: { DeclareMatch(call, ast, MethodCall); @@ -3158,7 +3152,7 @@ CORD compile(env_t *env, ast_t *ast) if (streq(call->name, "serialized")) { if (call->args) code_err(ast, ".serialized() doesn't take any arguments"); - return CORD_all("generic_serialize((", compile_declaration(self_t, "[1]"), "){", + return Texts("generic_serialize((", compile_declaration(self_t, Text("[1]")), "){", compile(env, call->self), "}, ", compile_type_info(self_t), ")"); } @@ -3179,7 +3173,7 @@ CORD compile(env_t *env, ast_t *ast) return compile(env, WrapAST(ast, FunctionCall, .fn=WrapAST(call->self, FieldAccess, .fielded=call->self, .field=call->name), .args=call->args)); - CORD self = compile(env, call->self); + Text_t self = compile(env, call->self); #define EXPECT_POINTER(article, name) do { \ if (pointer_depth < 1) code_err(call->self, "I expected "article" "name" pointer here, not "article" "name" value"); \ @@ -3188,36 +3182,36 @@ CORD compile(env_t *env, ast_t *ast) switch (self_value_t->tag) { case ListType: { type_t *item_t = Match(self_value_t, ListType)->item_type; - CORD padded_item_size = CORD_all("sizeof(", compile_type(item_t), ")"); + Text_t padded_item_size = Texts("sizeof(", compile_type(item_t), ")"); if (streq(call->name, "insert")) { EXPECT_POINTER("a", "list"); arg_t *arg_spec = new(arg_t, .name="item", .type=item_t, .next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0"))); - return CORD_all("List$insert_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("List$insert_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "insert_all")) { EXPECT_POINTER("a", "list"); arg_t *arg_spec = new(arg_t, .name="items", .type=self_value_t, .next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0"))); - return CORD_all("List$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("List$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "remove_at")) { EXPECT_POINTER("a", "list"); arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1"), .next=new(arg_t, .name="count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1"))); - return CORD_all("List$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("List$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "remove_item")) { EXPECT_POINTER("a", "list"); arg_t *arg_spec = new(arg_t, .name="item", .type=item_t, .next=new(arg_t, .name="max_count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1"))); - return CORD_all("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "has")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="item", .type=item_t); - return CORD_all("List$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("List$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "sample")) { type_t *random_num_type = parse_type_string(env, "func(->Num)?"); @@ -3226,92 +3220,92 @@ CORD compile(env_t *env, ast_t *ast) .next=new(arg_t, .name="weights", .type=Type(ListType, .item_type=Type(NumType, .bits=TYPE_NBITS64)), .default_val=FakeAST(None), .next=new(arg_t, .name="random", .type=random_num_type, .default_val=FakeAST(None)))); - return CORD_all("List$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("List$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "shuffle")) { type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?"); EXPECT_POINTER("a", "list"); arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None)); - return CORD_all("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); + return Texts("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "shuffled")) { type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?"); self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None)); - return CORD_all("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); + return Texts("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "random")) { type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?"); self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None)); - return CORD_all("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type(item_t), ")"); + return Texts("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type(item_t), ")"); } else if (streq(call->name, "sort") || streq(call->name, "sorted")) { if (streq(call->name, "sort")) EXPECT_POINTER("a", "list"); else self = compile_to_pointer_depth(env, call->self, 0, false); - CORD comparison; + Text_t comparison; if (call->args) { type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true); type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr}); arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t)); comparison = compile_arguments(env, ast, arg_spec, call->args); } else { - comparison = CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"); + comparison = Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"); } - return CORD_all("List$", call->name, "(", self, ", ", comparison, ", ", padded_item_size, ")"); + return Texts("List$", call->name, "(", self, ", ", comparison, ", ", padded_item_size, ")"); } else if (streq(call->name, "heapify")) { EXPECT_POINTER("a", "list"); - CORD comparison; + Text_t comparison; if (call->args) { type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true); type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr}); arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t)); comparison = compile_arguments(env, ast, arg_spec, call->args); } else { - comparison = CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"); + comparison = Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"); } - return CORD_all("List$heapify(", self, ", ", comparison, ", ", padded_item_size, ")"); + return Texts("List$heapify(", self, ", ", comparison, ", ", padded_item_size, ")"); } else if (streq(call->name, "heap_push")) { EXPECT_POINTER("a", "list"); type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true); type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr}); - ast_t *default_cmp = LiteralCode(CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)", + ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"), .type=Type(ClosureType, .fn=fn_t)); arg_t *arg_spec = new(arg_t, .name="item", .type=item_t, .next=new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp)); - CORD arg_code = compile_arguments(env, ast, arg_spec, call->args); - return CORD_all("List$heap_push_value(", self, ", ", arg_code, ", ", padded_item_size, ")"); + Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args); + return Texts("List$heap_push_value(", self, ", ", arg_code, ", ", padded_item_size, ")"); } else if (streq(call->name, "heap_pop")) { EXPECT_POINTER("a", "list"); type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true); type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr}); - ast_t *default_cmp = LiteralCode(CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)", + ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"), .type=Type(ClosureType, .fn=fn_t)); arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp); - CORD arg_code = compile_arguments(env, ast, arg_spec, call->args); - return CORD_all("List$heap_pop_value(", self, ", ", arg_code, ", ", compile_type(item_t), ", _, ", - promote_to_optional(item_t, "_"), ", ", compile_none(item_t), ")"); + Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args); + return Texts("List$heap_pop_value(", self, ", ", arg_code, ", ", compile_type(item_t), ", _, ", + promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")"); } else if (streq(call->name, "binary_search")) { self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL); type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true); type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr}); ast_t *default_cmp = LiteralCode( - CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)", + Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})"), .type=Type(ClosureType, .fn=fn_t)); arg_t *arg_spec = new(arg_t, .name="target", .type=item_t, .next=new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp)); - CORD arg_code = compile_arguments(env, ast, arg_spec, call->args); - return CORD_all("List$binary_search_value(", self, ", ", arg_code, ")"); + Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args); + return Texts("List$binary_search_value(", self, ", ", arg_code, ")"); } else if (streq(call->name, "clear")) { EXPECT_POINTER("a", "list"); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("List$clear(", self, ")"); + return Texts("List$clear(", self, ")"); } else if (streq(call->name, "find")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="item", .type=item_t); - return CORD_all("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), + return Texts("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "where")) { self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL); @@ -3319,37 +3313,37 @@ CORD compile(env_t *env, ast_t *ast) type_t *predicate_type = Type( ClosureType, .fn=NewFunctionType(Type(BoolType), {.name="item", .type=item_ptr})); arg_t *arg_spec = new(arg_t, .name="predicate", .type=predicate_type); - return CORD_all("List$first(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); + return Texts("List$first(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); } else if (streq(call->name, "from")) { self = compile_to_pointer_depth(env, call->self, 0, true); arg_t *arg_spec = new(arg_t, .name="first", .type=INT_TYPE); - return CORD_all("List$from(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); + return Texts("List$from(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); } else if (streq(call->name, "to")) { self = compile_to_pointer_depth(env, call->self, 0, true); arg_t *arg_spec = new(arg_t, .name="last", .type=INT_TYPE); - return CORD_all("List$to(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); + return Texts("List$to(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); } else if (streq(call->name, "by")) { self = compile_to_pointer_depth(env, call->self, 0, true); arg_t *arg_spec = new(arg_t, .name="stride", .type=INT_TYPE); - return CORD_all("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); + return Texts("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")"); } else if (streq(call->name, "reversed")) { self = compile_to_pointer_depth(env, call->self, 0, true); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("List$reversed(", self, ", ", padded_item_size, ")"); + return Texts("List$reversed(", self, ", ", padded_item_size, ")"); } else if (streq(call->name, "unique")) { self = compile_to_pointer_depth(env, call->self, 0, false); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("Table$from_entries(", self, ", Set$info(", compile_type_info(item_t), "))"); + return Texts("Table$from_entries(", self, ", Set$info(", compile_type_info(item_t), "))"); } else if (streq(call->name, "pop")) { EXPECT_POINTER("a", "list"); arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, "-1")); - CORD index = compile_arguments(env, ast, arg_spec, call->args); - return CORD_all("List$pop(", self, ", ", index, ", ", compile_type(item_t), ", _, ", - promote_to_optional(item_t, "_"), ", ", compile_none(item_t), ")"); + Text_t index = compile_arguments(env, ast, arg_spec, call->args); + return Texts("List$pop(", self, ", ", index, ", ", compile_type(item_t), ", _, ", + promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")"); } else if (streq(call->name, "counts")) { self = compile_to_pointer_depth(env, call->self, 0, false); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("List$counts(", self, ", ", compile_type_info(self_value_t), ")"); + return Texts("List$counts(", self, ", ", compile_type_info(self_value_t), ")"); } else code_err(ast, "There is no '", call->name, "' method for lists"); } case SetType: { @@ -3357,17 +3351,17 @@ CORD compile(env_t *env, ast_t *ast) if (streq(call->name, "has")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="key", .type=set->item_type); - return CORD_all("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "add")) { EXPECT_POINTER("a", "set"); arg_t *arg_spec = new(arg_t, .name="item", .type=set->item_type); - return CORD_all("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", NULL, ", + return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", NULL, ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "add_all")) { EXPECT_POINTER("a", "set"); arg_t *arg_spec = new(arg_t, .name="items", .type=Type(ListType, .item_type=Match(self_value_t, SetType)->item_type)); - return CORD_all("({ Table_t *set = ", self, "; ", + return Texts("({ Table_t *set = ", self, "; ", "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ", "for (int64_t i = 0; i < to_add.length; i++)\n" "Table$set(set, to_add.data + i*to_add.stride, NULL, ", compile_type_info(self_value_t), ");\n", @@ -3375,12 +3369,12 @@ CORD compile(env_t *env, ast_t *ast) } else if (streq(call->name, "remove")) { EXPECT_POINTER("a", "set"); arg_t *arg_spec = new(arg_t, .name="item", .type=set->item_type); - return CORD_all("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "remove_all")) { EXPECT_POINTER("a", "set"); arg_t *arg_spec = new(arg_t, .name="items", .type=Type(ListType, .item_type=Match(self_value_t, SetType)->item_type)); - return CORD_all("({ Table_t *set = ", self, "; ", + return Texts("({ Table_t *set = ", self, "; ", "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ", "for (int64_t i = 0; i < to_add.length; i++)\n" "Table$remove(set, to_add.data + i*to_add.stride, ", compile_type_info(self_value_t), ");\n", @@ -3388,33 +3382,33 @@ CORD compile(env_t *env, ast_t *ast) } else if (streq(call->name, "clear")) { EXPECT_POINTER("a", "set"); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("Table$clear(", self, ")"); + return Texts("Table$clear(", self, ")"); } else if (streq(call->name, "with")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t); - return CORD_all("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), + return Texts("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "overlap")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t); - return CORD_all("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), + return Texts("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "without")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t); - return CORD_all("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), + return Texts("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "is_subset_of")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t, .next=new(arg_t, .name="strict", .type=Type(BoolType), .default_val=FakeAST(Bool, false))); - return CORD_all("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), + return Texts("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "is_superset_of")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t, .next=new(arg_t, .name="strict", .type=Type(BoolType), .default_val=FakeAST(Bool, false))); - return CORD_all("Table$is_superset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), + return Texts("Table$is_superset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else code_err(ast, "There is no '", call->name, "' method for tables"); } @@ -3423,16 +3417,16 @@ CORD compile(env_t *env, ast_t *ast) if (streq(call->name, "get")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type); - return CORD_all( + return Texts( "Table$get_optional(", self, ", ", compile_type(table->key_type), ", ", compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", - "_, ", optional_into_nonnone(table->value_type, "(*_)"), ", ", compile_none(table->value_type), ", ", + "_, ", optional_into_nonnone(table->value_type, Text("(*_)")), ", ", compile_none(table->value_type), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "get_or_set")) { self = compile_to_pointer_depth(env, call->self, 1, false); arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type, .next=new(arg_t, .name="default", .type=table->value_type, .default_val=table->default_value)); - return CORD_all("*Table$get_or_setdefault(", + return Texts("*Table$get_or_setdefault(", self, ", ", compile_type(table->key_type), ", ", compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", @@ -3440,31 +3434,31 @@ CORD compile(env_t *env, ast_t *ast) } else if (streq(call->name, "has")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type); - return CORD_all("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "set")) { EXPECT_POINTER("a", "table"); arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type, .next=new(arg_t, .name="value", .type=table->value_type)); - return CORD_all("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "remove")) { EXPECT_POINTER("a", "table"); arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type); - return CORD_all("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", + return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "clear")) { EXPECT_POINTER("a", "table"); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("Table$clear(", self, ")"); + return Texts("Table$clear(", self, ")"); } else if (streq(call->name, "sorted")) { self = compile_to_pointer_depth(env, call->self, 0, false); (void)compile_arguments(env, ast, NULL, call->args); - return CORD_all("Table$sorted(", self, ", ", compile_type_info(self_value_t), ")"); + return Texts("Table$sorted(", self, ", ", compile_type_info(self_value_t), ")"); } else if (streq(call->name, "with_fallback")) { self = compile_to_pointer_depth(env, call->self, 0, false); arg_t *arg_spec = new(arg_t, .name="fallback", .type=Type(OptionalType, self_value_t)); - return CORD_all("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); + return Texts("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")"); } else code_err(ast, "There is no '", call->name, "' method for tables"); } default: { @@ -3473,7 +3467,7 @@ CORD compile(env_t *env, ast_t *ast) arg_ast_t *args = new(arg_ast_t, .value=methodcall->self, .next=methodcall->args); binding_t *b = get_namespace_binding(env, methodcall->self, methodcall->name); if (!b) code_err(ast, "No such method"); - return CORD_all(b->code, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, args), ")"); + return Texts(b->code, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, args), ")"); } } #undef EXPECT_POINTER @@ -3482,8 +3476,8 @@ CORD compile(env_t *env, ast_t *ast) DeclareMatch(call, ast, FunctionCall); type_t *fn_t = get_type(env, call->fn); if (fn_t->tag == FunctionType) { - CORD fn = compile(env, call->fn); - return CORD_all(fn, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), ")"); + Text_t fn = compile(env, call->fn); + return Texts(fn, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), ")"); } else if (fn_t->tag == TypeInfoType) { type_t *t = Match(fn_t, TypeInfoType)->type; @@ -3496,7 +3490,7 @@ CORD compile(env_t *env, ast_t *ast) binding_t *constructor = get_constructor(env, t, call->args); if (constructor) { arg_t *arg_spec = Match(constructor->type, FunctionType)->args; - return CORD_all(constructor->code, "(", compile_arguments(env, ast, arg_spec, call->args), ")"); + return Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, call->args), ")"); } type_t *actual = call->args ? get_type(env, call->args->value) : NULL; @@ -3509,22 +3503,22 @@ CORD compile(env_t *env, ast_t *ast) code_err(call->fn, "This constructor takes exactly 1 argument"); if (type_eq(actual, t)) return compile(env, call->args->value); - return expr_as_text(compile(env, call->args->value), actual, "no"); + return expr_as_text(compile(env, call->args->value), actual, Text("no")); } else if (t->tag == CStringType) { // C String constructor: if (!call->args || call->args->next) code_err(call->fn, "This constructor takes exactly 1 argument"); if (call->args->value->tag == TextLiteral) - return compile_string_literal(Match(call->args->value, TextLiteral)->cord); + return compile_text_literal(Match(call->args->value, TextLiteral)->text); else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children == NULL) - return "\"\""; + return Text("\"\""); else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children->next == NULL) - return compile_string_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->cord); - return CORD_all("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, "no"), ")"); + return compile_text_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->text); + return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")), ")"); } else if (t->tag == StructType) { DeclareMatch(struct_, t, StructType); if (!struct_->opaque && is_valid_call(env, struct_->fields, call->args, true)) { - return CORD_all("((", compile_type(t), "){", + return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, call->args), "})"); } } @@ -3538,15 +3532,15 @@ CORD compile(env_t *env, ast_t *ast) closure_fn_args = new(arg_t, .name=arg->name, .type=arg->type, .default_val=arg->default_val, .next=closure_fn_args); closure_fn_args = new(arg_t, .name="userdata", .type=Type(PointerType, .pointed=Type(MemoryType)), .next=closure_fn_args); REVERSE_LIST(closure_fn_args); - CORD fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret)); + Text_t fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret)); - CORD closure = compile(env, call->fn); - CORD arg_code = compile_arguments(env, ast, type_args, call->args); - if (arg_code) arg_code = CORD_cat(arg_code, ", "); + Text_t closure = compile(env, call->fn); + Text_t arg_code = compile_arguments(env, ast, type_args, call->args); + if (arg_code.length > 0) arg_code = Texts(arg_code, ", "); if (call->fn->tag == Var) { - return CORD_all("((", fn_type_code, ")", closure, ".fn)(", arg_code, closure, ".userdata)"); + return Texts("((", fn_type_code, ")", closure, ".fn)(", arg_code, closure, ".userdata)"); } else { - return CORD_all("({ Closure_t closure = ", closure, "; ((", fn_type_code, ")closure.fn)(", + return Texts("({ Closure_t closure = ", closure, "; ((", fn_type_code, ")closure.fn)(", arg_code, "closure.userdata); })"); } } else { @@ -3559,7 +3553,7 @@ CORD compile(env_t *env, ast_t *ast) if (!type_eq(value_type, Type(ListType, Type(ByteType)))) code_err(value, "This value should be a list of bytes, not a ", type_to_str(value_type)); type_t *t = parse_type_ast(env, Match(ast, Deserialize)->type); - return CORD_all("({ ", compile_declaration(t, "deserialized"), ";\n" + return Texts("({ ", compile_declaration(t, Text("deserialized")), ";\n" "generic_deserialize(", compile(env, value), ", &deserialized, ", compile_type_info(t), ");\n" "deserialized; })"); } @@ -3595,19 +3589,19 @@ CORD compile(env_t *env, ast_t *ast) type_t *t = get_type(env, ast); env_t *when_env = fresh_scope(env); - set_binding(when_env, "when", t, "when"); - return CORD_all( - "({ ", compile_declaration(t, "when"), ";\n", + set_binding(when_env, "when", t, Text("when")); + return Texts( + "({ ", compile_declaration(t, Text("when")), ";\n", compile_statement(when_env, WrapAST(ast, When, .subject=original->subject, .clauses=new_clauses, .else_body=else_body)), "when; })"); } case If: { DeclareMatch(if_, ast, If); ast_t *condition = if_->condition; - CORD decl_code = CORD_EMPTY; + Text_t decl_code = EMPTY_TEXT; env_t *truthy_scope = env, *falsey_scope = env; - CORD condition_code; + Text_t condition_code; if (condition->tag == Declare) { DeclareMatch(decl, condition, Declare); if (decl->value == NULL) @@ -3645,16 +3639,16 @@ CORD compile(env_t *env, ast_t *ast) type_t *true_type = get_type(truthy_scope, if_->body); type_t *false_type = get_type(falsey_scope, if_->else_body); if (true_type->tag == AbortType || true_type->tag == ReturnType) - return CORD_all("({ ", decl_code, "if (", condition_code, ") ", compile_statement(truthy_scope, if_->body), + return Texts("({ ", decl_code, "if (", condition_code, ") ", compile_statement(truthy_scope, if_->body), "\n", compile(falsey_scope, if_->else_body), "; })"); else if (false_type->tag == AbortType || false_type->tag == ReturnType) - return CORD_all("({ ", decl_code, "if (!(", condition_code, ")) ", compile_statement(falsey_scope, if_->else_body), + return Texts("({ ", decl_code, "if (!(", condition_code, ")) ", compile_statement(falsey_scope, if_->else_body), "\n", compile(truthy_scope, if_->body), "; })"); - else if (decl_code != CORD_EMPTY) - return CORD_all("({ ", decl_code, "(", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ", + else if (decl_code.length > 0) + return Texts("({ ", decl_code, "(", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ", compile(falsey_scope, if_->else_body), ";})"); else - return CORD_all("((", condition_code, ") ? ", + return Texts("((", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ", compile(falsey_scope, if_->else_body), ")"); } case Reduction: { @@ -3667,7 +3661,7 @@ CORD compile(env_t *env, ast_t *ast) static int64_t next_id = 1; ast_t *item = FakeAST(Var, String("$it", next_id++)); - ast_t *body = LiteralCode("{}"); // placeholder + ast_t *body = LiteralCode(Text("{}")); // placeholder ast_t *loop = FakeAST(For, .vars=new(ast_list_t, .ast=item), .iter=reduction->iter, .body=body); env_t *body_scope = for_scope(env, loop); if (op == Equals || op == NotEquals || op == LessThan || op == LessThanOrEquals || op == GreaterThan || op == GreaterThanOrEquals) { @@ -3680,15 +3674,15 @@ CORD compile(env_t *env, ast_t *ast) item_value_type = get_type(body_scope, reduction->key); } - CORD code = CORD_all( + Text_t code = Texts( "({ // Reduction:\n", - compile_declaration(item_value_type, "prev"), ";\n" + compile_declaration(item_value_type, Text("prev")), ";\n" "OptionalBool_t result = NONE_BOOL;\n" ); ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end, - .tag=op, .__data.Plus.lhs=LiteralCode("prev", .type=item_value_type), .__data.Plus.rhs=item_value); - body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, CORD_all( + .tag=op, .__data.Plus.lhs=LiteralCode(Text("prev"), .type=item_value_type), .__data.Plus.rhs=item_value); + body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts( "if (result == NONE_BOOL) {\n" " prev = ", compile(body_scope, item_value), ";\n" " result = yes;\n" @@ -3700,32 +3694,32 @@ CORD compile(env_t *env, ast_t *ast) " break;\n", " }\n", "}\n"))); - code = CORD_all(code, compile_statement(env, loop), "\nresult;})"); + code = Texts(code, compile_statement(env, loop), "\nresult;})"); return code; } else if (op == Min || op == Max) { // Min/max: - const char *superlative = op == Min ? "min" : "max"; - CORD code = CORD_all( + Text_t superlative = op == Min ? Text("min") : Text("max"); + Text_t code = Texts( "({ // Reduction:\n", compile_declaration(item_t, superlative), ";\n" "Bool_t has_value = no;\n" ); - CORD item_code = compile(body_scope, item); + Text_t item_code = compile(body_scope, item); ast_e cmp_op = op == Min ? LessThan : GreaterThan; if (reduction->key) { env_t *key_scope = fresh_scope(env); set_binding(key_scope, "$", item_t, item_code); type_t *key_type = get_type(key_scope, reduction->key); - const char *superlative_key = op == Min ? "min_key" : "max_key"; - code = CORD_all(code, compile_declaration(key_type, superlative_key), ";\n"); + Text_t superlative_key = op == Min ? Text("min_key") : Text("max_key"); + code = Texts(code, compile_declaration(key_type, superlative_key), ";\n"); ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end, - .tag=cmp_op, .__data.Plus.lhs=LiteralCode("key", .type=key_type), + .tag=cmp_op, .__data.Plus.lhs=LiteralCode(Text("key"), .type=key_type), .__data.Plus.rhs=LiteralCode(superlative_key, .type=key_type)); - body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, CORD_all( - compile_declaration(key_type, "key"), " = ", compile(key_scope, reduction->key), ";\n", + body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts( + compile_declaration(key_type, Text("key")), " = ", compile(key_scope, reduction->key), ";\n", "if (!has_value || ", compile(body_scope, comparison), ") {\n" " ", superlative, " = ", compile(body_scope, item), ";\n" " ", superlative_key, " = key;\n" @@ -3735,7 +3729,7 @@ CORD compile(env_t *env, ast_t *ast) ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end, .tag=cmp_op, .__data.Plus.lhs=item, .__data.Plus.rhs=LiteralCode(superlative, .type=item_t)); - body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, CORD_all( + body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts( "if (!has_value || ", compile(body_scope, comparison), ") {\n" " ", superlative, " = ", compile(body_scope, item), ";\n" " has_value = yes;\n" @@ -3743,7 +3737,7 @@ CORD compile(env_t *env, ast_t *ast) } - code = CORD_all(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(item_t, superlative), + code = Texts(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(item_t, superlative), " : ", compile_none(item_t), ";})"); return code; } else { @@ -3755,33 +3749,33 @@ CORD compile(env_t *env, ast_t *ast) item_value = reduction->key; } - CORD code = CORD_all( + Text_t code = Texts( "({ // Reduction:\n", - compile_declaration(reduction_type, "reduction"), ";\n" + compile_declaration(reduction_type, Text("reduction")), ";\n" "Bool_t has_value = no;\n" ); // For the special case of (or)/(and), we need to early out if we can: - CORD early_out = CORD_EMPTY; + Text_t early_out = EMPTY_TEXT; if (op == Compare) { if (reduction_type->tag != IntType || Match(reduction_type, IntType)->bits != TYPE_IBITS32) code_err(ast, "<> reductions are only supported for Int32 values"); } else if (op == And) { if (reduction_type->tag == BoolType) - early_out = "if (!reduction) break;"; + early_out = Text("if (!reduction) break;"); else if (reduction_type->tag == OptionalType) - early_out = CORD_all("if (", check_none(reduction_type, "reduction"), ") break;"); + early_out = Texts("if (", check_none(reduction_type, Text("reduction")), ") break;"); } else if (op == Or) { if (reduction_type->tag == BoolType) - early_out = "if (reduction) break;"; + early_out = Text("if (reduction) break;"); else if (reduction_type->tag == OptionalType) - early_out = CORD_all("if (!", check_none(reduction_type, "reduction"), ") break;"); + early_out = Texts("if (!", check_none(reduction_type, Text("reduction")), ") break;"); } ast_t *combination = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end, - .tag=op, .__data.Plus.lhs=LiteralCode("reduction", .type=reduction_type), + .tag=op, .__data.Plus.lhs=LiteralCode(Text("reduction"), .type=reduction_type), .__data.Plus.rhs=item_value); - body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, CORD_all( + body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts( "if (!has_value) {\n" " reduction = ", compile(body_scope, item_value), ";\n" " has_value = yes;\n" @@ -3790,7 +3784,7 @@ CORD compile(env_t *env, ast_t *ast) early_out, "}\n"))); - code = CORD_all(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(reduction_type, "reduction"), + code = Texts(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(reduction_type, Text("reduction")), " : ", compile_none(reduction_type), ";})"); return code; } @@ -3812,16 +3806,16 @@ CORD compile(env_t *env, ast_t *ast) } binding_t *b = get_binding(info->env, f->field); if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type"); - if (!b->code) code_err(ast, "I couldn't figure out how to compile this field"); + if (b->code.length == 0) code_err(ast, "I couldn't figure out how to compile this field"); return b->code; } case TextType: { const char *lang = Match(value_t, TextType)->lang; if (lang && streq(f->field, "text")) { - CORD text = compile_to_pointer_depth(env, f->fielded, 0, false); - return CORD_all("((Text_t)", text, ")"); + Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false); + return Texts("((Text_t)", text, ")"); } else if (streq(f->field, "length")) { - return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); } code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values"); } @@ -3829,11 +3823,11 @@ CORD compile(env_t *env, ast_t *ast) for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) { if (streq(field->name, f->field)) { if (fielded_t->tag == PointerType) { - CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false); - return CORD_all("(", fielded, ")->", f->field); + Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false); + return Texts("(", fielded, ")->", f->field); } else { - CORD fielded = compile(env, f->fielded); - return CORD_all("(", fielded, ").", f->field); + Text_t fielded = compile(env, f->fielded); + return Texts("(", fielded, ").", f->field); } } } @@ -3843,16 +3837,16 @@ CORD compile(env_t *env, ast_t *ast) DeclareMatch(e, value_t, EnumType); for (tag_t *tag = e->tags; tag; tag = tag->next) { if (streq(f->field, tag->name)) { - CORD tag_name = namespace_name(e->env, e->env->namespace, CORD_all("tag$", tag->name)); + Text_t tag_name = namespace_name(e->env, e->env->namespace, Texts("tag$", tag->name)); if (fielded_t->tag == PointerType) { - CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false); - return CORD_all("((", fielded, ")->$tag == ", tag_name, ")"); + Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false); + return Texts("((", fielded, ")->$tag == ", tag_name, ")"); } else if (enum_has_fields(value_t)) { - CORD fielded = compile(env, f->fielded); - return CORD_all("((", fielded, ").$tag == ", tag_name, ")"); + Text_t fielded = compile(env, f->fielded); + return Texts("((", fielded, ").$tag == ", tag_name, ")"); } else { - CORD fielded = compile(env, f->fielded); - return CORD_all("((", fielded, ") == ", tag_name, ")"); + Text_t fielded = compile(env, f->fielded); + return Texts("((", fielded, ") == ", tag_name, ")"); } } } @@ -3860,31 +3854,31 @@ CORD compile(env_t *env, ast_t *ast) } case ListType: { if (streq(f->field, "length")) - return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); code_err(ast, "There is no ", f->field, " field on lists"); } case SetType: { if (streq(f->field, "items")) - return CORD_all("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); + return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); else if (streq(f->field, "length")) - return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); code_err(ast, "There is no '", f->field, "' field on sets"); } case TableType: { if (streq(f->field, "length")) { - return CORD_all("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); + return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)"); } else if (streq(f->field, "keys")) { - return CORD_all("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); + return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)"); } else if (streq(f->field, "values")) { DeclareMatch(table, value_t, TableType); - CORD offset = CORD_all("offsetof(struct { ", compile_declaration(table->key_type, "k"), "; ", compile_declaration(table->value_type, "v"), "; }, v)"); - return CORD_all("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries;\n" + Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ", compile_declaration(table->value_type, Text("v")), "; }, v)"); + return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries;\n" "LIST_INCREF(*entries);\n" "List_t values = *entries;\n" "values.data += ", offset, ";\n" "values; })"); } else if (streq(f->field, "fallback")) { - return CORD_all("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false), ").fallback; _fallback ? *_fallback : NONE_TABLE; })"); + return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false), ").fallback; _fallback ? *_fallback : NONE_TABLE; })"); } code_err(ast, "There is no '", f->field, "' field on tables"); } @@ -3905,11 +3899,11 @@ CORD compile(env_t *env, ast_t *ast) code_err(ast, "Only pointers can use the '[]' operator to dereference the entire value."); DeclareMatch(ptr, indexed_type, PointerType); if (ptr->pointed->tag == ListType) { - return CORD_all("*({ List_t *list = ", compile(env, indexing->indexed), "; LIST_INCREF(*list); list; })"); + return Texts("*({ List_t *list = ", compile(env, indexing->indexed), "; LIST_INCREF(*list); list; })"); } else if (ptr->pointed->tag == TableType || ptr->pointed->tag == SetType) { - return CORD_all("*({ Table_t *t = ", compile(env, indexing->indexed), "; TABLE_INCREF(*t); t; })"); + return Texts("*({ Table_t *t = ", compile(env, indexing->indexed), "; TABLE_INCREF(*t); t; })"); } else { - return CORD_all("*(", compile(env, indexing->indexed), ")"); + return Texts("*(", compile(env, indexing->indexed), ")"); } } @@ -3919,16 +3913,16 @@ CORD compile(env_t *env, ast_t *ast) if (index_t->tag != IntType && index_t->tag != BigIntType && index_t->tag != ByteType) code_err(indexing->index, "Lists can only be indexed by integers, not ", type_to_str(index_t)); type_t *item_type = Match(container_t, ListType)->item_type; - CORD list = compile_to_pointer_depth(env, indexing->indexed, 0, false); + Text_t list = compile_to_pointer_depth(env, indexing->indexed, 0, false); file_t *f = indexing->index->file; - CORD index_code = indexing->index->tag == Int + Text_t index_code = indexing->index->tag == Int ? compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)) - : (index_t->tag == BigIntType ? CORD_all("Int64$from_int(", compile(env, indexing->index), ", no)") - : CORD_all("(Int64_t)(", compile(env, indexing->index), ")")); + : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)") + : Texts("(Int64_t)(", compile(env, indexing->index), ")")); if (indexing->unchecked) - return CORD_all("List_get_unchecked(", compile_type(item_type), ", ", list, ", ", index_code, ")"); + return Texts("List_get_unchecked(", compile_type(item_type), ", ", list, ", ", index_code, ")"); else - return CORD_all("List_get(", compile_type(item_type), ", ", list, ", ", index_code, ", ", + return Texts("List_get(", compile_type(item_type), ", ", list, ", ", index_code, ", ", String((int64_t)(indexing->index->start - f->text)), ", ", String((int64_t)(indexing->index->end - f->text)), ")"); @@ -3937,7 +3931,7 @@ CORD compile(env_t *env, ast_t *ast) if (indexing->unchecked) code_err(ast, "Table indexes cannot be unchecked"); if (table_type->default_value) { - return CORD_all("Table$get_or_default(", + return Texts("Table$get_or_default(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ", compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ", @@ -3945,17 +3939,17 @@ CORD compile(env_t *env, ast_t *ast) compile_to_type(env, table_type->default_value, table_type->value_type), ", ", compile_type_info(container_t), ")"); } else { - return CORD_all("Table$get_optional(", + return Texts("Table$get_optional(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ", compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ", compile(env, indexing->index), ", " - "_, ", promote_to_optional(table_type->value_type, "(*_)"), ", ", + "_, ", promote_to_optional(table_type->value_type, Text("(*_)")), ", ", compile_none(table_type->value_type), ", ", compile_type_info(container_t), ")"); } } else if (container_t->tag == TextType) { - return CORD_all("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ", compile_to_type(env, indexing->index, Type(BigIntType)), ")"); + return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ", compile_to_type(env, indexing->index, Type(BigIntType)), ")"); } else { code_err(ast, "Indexing is not supported for type: ", type_to_str(container_t)); } @@ -3963,7 +3957,7 @@ CORD compile(env_t *env, ast_t *ast) case InlineCCode: { type_t *t = get_type(env, ast); if (t->tag == VoidType) - return CORD_all("{\n", compile_statement(env, ast), "\n}"); + return Texts("{\n", compile_statement(env, ast), "\n}"); else return compile_statement(env, ast); } @@ -3976,100 +3970,100 @@ CORD compile(env_t *env, ast_t *ast) code_err(ast, "This is not a valid expression"); default: case Unknown: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast)); } - return CORD_EMPTY; + return EMPTY_TEXT; } -CORD compile_type_info(type_t *t) +Text_t compile_type_info(type_t *t) { if (t == NULL) compiler_err(NULL, NULL, NULL, "Attempt to compile a NULL type"); - if (t == PATH_TYPE) return "&Path$info"; - else if (t == PATH_TYPE_TYPE) return "&PathType$info"; + if (t == PATH_TYPE) return Text("&Path$info"); + else if (t == PATH_TYPE_TYPE) return Text("&PathType$info"); switch (t->tag) { case BoolType: case ByteType: case IntType: case BigIntType: case NumType: case CStringType: - return CORD_all("&", type_to_cord(t), "$info"); + return Texts("&", type_to_text(t), "$info"); case TextType: { DeclareMatch(text, t, TextType); if (!text->lang || streq(text->lang, "Text")) - return "&Text$info"; - return CORD_all("(&", namespace_name(text->env, text->env->namespace, "$info"), ")"); + return Text("&Text$info"); + return Texts("(&", namespace_name(text->env, text->env->namespace, Text("$info")), ")"); } case StructType: { DeclareMatch(s, t, StructType); - return CORD_all("(&", namespace_name(s->env, s->env->namespace, "$info"), ")"); + return Texts("(&", namespace_name(s->env, s->env->namespace, Text("$info")), ")"); } case EnumType: { DeclareMatch(e, t, EnumType); - return CORD_all("(&", namespace_name(e->env, e->env->namespace, "$info"), ")"); + return Texts("(&", namespace_name(e->env, e->env->namespace, Text("$info")), ")"); } case ListType: { type_t *item_t = Match(t, ListType)->item_type; - return CORD_all("List$info(", compile_type_info(item_t), ")"); + return Texts("List$info(", compile_type_info(item_t), ")"); } case SetType: { type_t *item_type = Match(t, SetType)->item_type; - return CORD_all("Set$info(", compile_type_info(item_type), ")"); + return Texts("Set$info(", compile_type_info(item_type), ")"); } case TableType: { DeclareMatch(table, t, TableType); type_t *key_type = table->key_type; type_t *value_type = table->value_type; - return CORD_all("Table$info(", compile_type_info(key_type), ", ", compile_type_info(value_type), ")"); + return Texts("Table$info(", compile_type_info(key_type), ", ", compile_type_info(value_type), ")"); } case PointerType: { DeclareMatch(ptr, t, PointerType); - CORD sigil = ptr->is_stack ? "&" : "@"; - return CORD_all("Pointer$info(", CORD_quoted(sigil), ", ", compile_type_info(ptr->pointed), ")"); + const char *sigil = ptr->is_stack ? "&" : "@"; + return Texts("Pointer$info(", quoted_str(sigil), ", ", compile_type_info(ptr->pointed), ")"); } case FunctionType: { - return CORD_all("Function$info(", CORD_quoted(type_to_cord(t)), ")"); + return Texts("Function$info(", quoted_text(type_to_text(t)), ")"); } case ClosureType: { - return CORD_all("Closure$info(", CORD_quoted(type_to_cord(t)), ")"); + return Texts("Closure$info(", quoted_text(type_to_text(t)), ")"); } case OptionalType: { type_t *non_optional = Match(t, OptionalType)->type; - return CORD_all("Optional$info(sizeof(", compile_type(non_optional), + return Texts("Optional$info(sizeof(", compile_type(non_optional), "), __alignof__(", compile_type(non_optional), "), ", compile_type_info(non_optional), ")"); } - case TypeInfoType: return CORD_all("Type$info(", CORD_quoted(type_to_cord(Match(t, TypeInfoType)->type)), ")"); - case MemoryType: return "&Memory$info"; - case VoidType: return "&Void$info"; + case TypeInfoType: return Texts("Type$info(", quoted_text(type_to_text(Match(t, TypeInfoType)->type)), ")"); + case MemoryType: return Text("&Memory$info"); + case VoidType: return Text("&Void$info"); default: compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_str(t)); } - return CORD_EMPTY; + return EMPTY_TEXT; } -static CORD get_flag_options(type_t *t, CORD separator) +static Text_t get_flag_options(type_t *t, const char *separator) { if (t->tag == BoolType) { - return "yes|no"; + return Text("yes|no"); } else if (t->tag == EnumType) { - CORD options = CORD_EMPTY; + Text_t options = EMPTY_TEXT; for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) { - options = CORD_all(options, tag->name); - if (tag->next) options = CORD_all(options, separator); + options = Texts(options, tag->name); + if (tag->next) options = Texts(options, separator); } return options; } else if (t->tag == IntType || t->tag == NumType || t->tag == BigIntType) { - return "N"; + return Text("N"); } else { - return "..."; + return Text("..."); } } -CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type, const char *version) +Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version) { DeclareMatch(fn_info, fn_type, FunctionType); env_t *main_env = fresh_scope(env); - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; binding_t *usage_binding = get_binding(env, "_USAGE"); - CORD usage_code = usage_binding ? usage_binding->code : "usage"; + Text_t usage_code = usage_binding ? usage_binding->code : Text("usage"); binding_t *help_binding = get_binding(env, "_HELP"); - CORD help_code = help_binding ? help_binding->code : usage_code; + Text_t help_code = help_binding ? help_binding->code : usage_code; if (!usage_binding) { bool explicit_help_flag = false; for (arg_t *arg = fn_info->args; arg; arg = arg->next) { @@ -4079,79 +4073,79 @@ CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type, const char } } - CORD usage = explicit_help_flag ? CORD_EMPTY : " [--help]"; + Text_t usage = explicit_help_flag ? EMPTY_TEXT : Text(" [--help]"); for (arg_t *arg = fn_info->args; arg; arg = arg->next) { - usage = CORD_cat(usage, " "); + usage = Texts(usage, " "); type_t *t = get_arg_type(main_env, arg); - CORD flag = CORD_replace(arg->name, "_", "-"); + Text_t flag = Text$replace(Text$from_str(arg->name), Text("_"), Text("-")); if (arg->default_val || arg->type->tag == OptionalType) { if (strlen(arg->name) == 1) { if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType)) - usage = CORD_all(usage, "[-", flag, "]"); + usage = Texts(usage, "[-", flag, "]"); else - usage = CORD_all(usage, "[-", flag, " ", get_flag_options(t, "|"), "]"); + usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]"); } else { if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType)) - usage = CORD_all(usage, "[--", flag, "]"); + usage = Texts(usage, "[--", flag, "]"); else if (t->tag == ListType) - usage = CORD_all(usage, "[--", flag, " ", get_flag_options(t, "|"), "]"); + usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]"); else - usage = CORD_all(usage, "[--", flag, "=", get_flag_options(t, "|"), "]"); + usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]"); } } else { if (t->tag == BoolType) - usage = CORD_all(usage, "<--", flag, "|--no-", flag, ">"); + usage = Texts(usage, "<--", flag, "|--no-", flag, ">"); else if (t->tag == EnumType) - usage = CORD_all(usage, get_flag_options(t, "|")); + usage = Texts(usage, get_flag_options(t, "|")); else if (t->tag == ListType) - usage = CORD_all(usage, "[", flag, "...]"); + usage = Texts(usage, "[", flag, "...]"); else - usage = CORD_all(usage, "<", flag, ">"); + usage = Texts(usage, "<", flag, ">"); } } - code = CORD_all(code, "Text_t usage = Texts(Text(\"Usage: \"), Text$from_str(argv[0])", - usage == CORD_EMPTY ? CORD_EMPTY : CORD_all(", Text(", CORD_quoted(usage), ")"), ");\n"); + code = Texts(code, "Text_t usage = Texts(Text(\"Usage: \"), Text$from_str(argv[0])", + usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n"); } for (arg_t *arg = fn_info->args; arg; arg = arg->next) { type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type=arg->type); - code = CORD_all(code, compile_declaration(opt_type, CORD_all("_$", arg->name))); + code = Texts(code, compile_declaration(opt_type, Texts("_$", arg->name))); if (arg->default_val) { - CORD default_val = compile(env, arg->default_val); + Text_t default_val = compile(env, arg->default_val); if (arg->type->tag != OptionalType) default_val = promote_to_optional(arg->type, default_val); - code = CORD_all(code, " = ", default_val); + code = Texts(code, " = ", default_val); } else { - code = CORD_all(code, " = ", compile_none(arg->type)); + code = Texts(code, " = ", compile_none(arg->type)); } - code = CORD_all(code, ";\n"); + code = Texts(code, ";\n"); } - CORD version_code = CORD_quoted(version); - code = CORD_all(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code); + Text_t version_code = quoted_str(version); + code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code); for (arg_t *arg = fn_info->args; arg; arg = arg->next) { - code = CORD_all(code, ",\n{", CORD_quoted(CORD_replace(arg->name, "_", "-")), ", ", + code = Texts(code, ",\n{", quoted_text(Text$replace(Text$from_str(arg->name), Text("_"), Text("-"))), ", ", (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ", compile_type_info(arg->type), - ", &", CORD_all("_$", arg->name), "}"); + ", &", Texts("_$", arg->name), "}"); } - code = CORD_all(code, ");\n"); + code = Texts(code, ");\n"); - code = CORD_all(code, fn_name, "("); + code = Texts(code, fn_name, "("); for (arg_t *arg = fn_info->args; arg; arg = arg->next) { - CORD arg_code = CORD_all("_$", arg->name); + Text_t arg_code = Texts("_$", arg->name); if (arg->type->tag != OptionalType) arg_code = optional_into_nonnone(arg->type, arg_code); - code = CORD_all(code, arg_code); - if (arg->next) code = CORD_all(code, ", "); + code = Texts(code, arg_code); + if (arg->next) code = Texts(code, ", "); } - code = CORD_all(code, ");\n"); + code = Texts(code, ");\n"); return code; } -CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) +Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *staticdefs) { bool is_private = false; const char *function_name; @@ -4181,34 +4175,34 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) is_inline = convertdef->is_inline; } - CORD arg_signature = "("; + Text_t arg_signature = Text("("); Table_t used_names = {}; for (arg_ast_t *arg = args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - arg_signature = CORD_cat(arg_signature, compile_declaration(arg_type, CORD_cat("_$", arg->name))); - if (arg->next) arg_signature = CORD_cat(arg_signature, ", "); + arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name))); + if (arg->next) arg_signature = Texts(arg_signature, ", "); if (Table$str_get(used_names, arg->name)) code_err(ast, "The argument name '", arg->name, "' is used more than once"); Table$str_set(&used_names, arg->name, arg->name); } - arg_signature = CORD_cat(arg_signature, ")"); + arg_signature = Texts(arg_signature, ")"); - CORD ret_type_code = compile_type(ret_t); + Text_t ret_type_code = compile_type(ret_t); if (ret_t->tag == AbortType) - ret_type_code = CORD_all("__attribute__((noreturn)) _Noreturn ", ret_type_code); + ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code); if (is_private) - *staticdefs = CORD_all(*staticdefs, "static ", ret_type_code, " ", name_code, arg_signature, ";\n"); + *staticdefs = Texts(*staticdefs, "static ", ret_type_code, " ", name_code, arg_signature, ";\n"); - CORD code; + Text_t code; if (cache) { - code = CORD_all("static ", ret_type_code, " ", name_code, "$uncached", arg_signature); + code = Texts("static ", ret_type_code, " ", name_code, "$uncached", arg_signature); } else { - code = CORD_all(ret_type_code, " ", name_code, arg_signature); + code = Texts(ret_type_code, " ", name_code, arg_signature); if (is_inline) - code = CORD_cat("INLINE ", code); + code = Texts("INLINE ", code); if (!is_private) - code = CORD_cat("public ", code); + code = Texts("public ", code); } env_t *body_scope = fresh_scope(env); @@ -4220,7 +4214,7 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) body_scope->deferred = NULL; for (arg_ast_t *arg = args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - set_binding(body_scope, arg->name, arg_type, CORD_cat("_$", arg->name)); + set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name)); } body_scope->fn_ret = ret_t; @@ -4238,13 +4232,13 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) "If this is not the case, please add a call to `fail(\"Unreachable\")` at the end of the function to help the compiler out."); } - CORD body_code = CORD_all("{\n", compile_inline_block(body_scope, body), "}\n"); - CORD definition = with_source_info(env, ast, CORD_all(code, " ", body_code, "\n")); + Text_t body_code = Texts("{\n", compile_inline_block(body_scope, body), "}\n"); + Text_t definition = with_source_info(env, ast, Texts(code, " ", body_code, "\n")); if (cache && args == NULL) { // no-args cache just uses a static var - CORD wrapper = CORD_all( - is_private ? CORD_EMPTY : "public ", ret_type_code, " ", name_code, "(void) {\n" - "static ", compile_declaration(ret_t, "cached_result"), ";\n", + Text_t wrapper = Texts( + is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, "(void) {\n" + "static ", compile_declaration(ret_t, Text("cached_result")), ";\n", "static bool initialized = false;\n", "if (!initialized) {\n" "\tcached_result = ", name_code, "$uncached();\n", @@ -4252,33 +4246,33 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) "}\n", "return cached_result;\n" "}\n"); - definition = CORD_cat(definition, wrapper); + definition = Texts(definition, wrapper); } else if (cache && cache->tag == Int) { assert(args); OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str)); - CORD pop_code = CORD_EMPTY; + Text_t pop_code = EMPTY_TEXT; if (cache->tag == Int && !cache_size.is_none && cache_size.value > 0) { // FIXME: this currently just deletes the first entry, but this should be more like a // least-recently-used cache eviction policy or least-frequently-used - pop_code = CORD_all("if (cache.entries.length > ", String(cache_size.value), + pop_code = Texts("if (cache.entries.length > ", String(cache_size.value), ") Table$remove(&cache, cache.entries.data + cache.entries.stride*0, table_type);\n"); } if (!args->next) { // Single-argument functions have simplified caching logic type_t *arg_type = get_arg_ast_type(env, args); - CORD wrapper = CORD_all( - is_private ? CORD_EMPTY : "public ", ret_type_code, " ", name_code, arg_signature, "{\n" + Text_t wrapper = Texts( + is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n" "static Table_t cache = {};\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), "cached"), " = Table$get_raw(cache, &_$", args->name, ", table_type);\n" + compile_declaration(Type(PointerType, .pointed=ret_t), Text("cached")), " = Table$get_raw(cache, &_$", args->name, ", table_type);\n" "if (cached) return *cached;\n", - compile_declaration(ret_t, "ret"), " = ", name_code, "$uncached(_$", args->name, ");\n", + compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(_$", args->name, ");\n", pop_code, "Table$set(&cache, &_$", args->name, ", &ret, table_type);\n" "return ret;\n" "}\n"); - definition = CORD_cat(definition, wrapper); + definition = Texts(definition, wrapper); } else { // Multi-argument functions use a custom struct type (only defined internally) as a cache key: arg_t *fields = NULL; @@ -4289,93 +4283,93 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) int64_t num_fields = used_names.entries.length; const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods"; - CORD args_typeinfo = CORD_all("((TypeInfo_t[1]){{.size=sizeof(args), .align=__alignof__(args), .metamethods=", metamethods, + Text_t args_typeinfo = Texts("((TypeInfo_t[1]){{.size=sizeof(args), .align=__alignof__(args), .metamethods=", metamethods, ", .tag=StructInfo, .StructInfo.name=\"FunctionArguments\", " ".StructInfo.num_fields=", String(num_fields), ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){"); - CORD args_type = "struct { "; + Text_t args_type = Text("struct { "); for (arg_t *f = fields; f; f = f->next) { - args_typeinfo = CORD_all(args_typeinfo, "{\"", f->name, "\", ", compile_type_info(f->type), "}"); - args_type = CORD_all(args_type, compile_declaration(f->type, f->name), "; "); - if (f->next) args_typeinfo = CORD_all(args_typeinfo, ", "); + args_typeinfo = Texts(args_typeinfo, "{\"", f->name, "\", ", compile_type_info(f->type), "}"); + args_type = Texts(args_type, compile_declaration(f->type, Text$from_str(f->name)), "; "); + if (f->next) args_typeinfo = Texts(args_typeinfo, ", "); } - args_type = CORD_all(args_type, "}"); - args_typeinfo = CORD_all(args_typeinfo, "}}})"); + args_type = Texts(args_type, "}"); + args_typeinfo = Texts(args_typeinfo, "}}})"); - CORD all_args = CORD_EMPTY; + Text_t all_args = EMPTY_TEXT; for (arg_ast_t *arg = args; arg; arg = arg->next) - all_args = CORD_all(all_args, "_$", arg->name, arg->next ? ", " : CORD_EMPTY); + all_args = Texts(all_args, "_$", arg->name, arg->next ? Text(", ") : EMPTY_TEXT); - CORD wrapper = CORD_all( - is_private ? CORD_EMPTY : "public ", ret_type_code, " ", name_code, arg_signature, "{\n" + Text_t wrapper = Texts( + is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n" "static Table_t cache = {};\n", args_type, " args = {", all_args, "};\n" "const TypeInfo_t *table_type = Table$info(", args_typeinfo, ", ", compile_type_info(ret_t), ");\n", - compile_declaration(Type(PointerType, .pointed=ret_t), "cached"), " = Table$get_raw(cache, &args, table_type);\n" + compile_declaration(Type(PointerType, .pointed=ret_t), Text("cached")), " = Table$get_raw(cache, &args, table_type);\n" "if (cached) return *cached;\n", - compile_declaration(ret_t, "ret"), " = ", name_code, "$uncached(", all_args, ");\n", + compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(", all_args, ");\n", pop_code, "Table$set(&cache, &args, &ret, table_type);\n" "return ret;\n" "}\n"); - definition = CORD_cat(definition, wrapper); + definition = Texts(definition, wrapper); } } - CORD qualified_name = function_name; + Text_t qualified_name = Text$from_str(function_name); if (env->namespace && env->namespace->parent && env->namespace->name) - qualified_name = CORD_all(env->namespace->name, ".", qualified_name); - CORD text = CORD_all("func ", qualified_name, "("); + qualified_name = Texts(env->namespace->name, ".", qualified_name); + Text_t text = Texts("func ", qualified_name, "("); for (arg_ast_t *arg = args; arg; arg = arg->next) { - text = CORD_cat(text, type_to_cord(get_arg_ast_type(env, arg))); - if (arg->next) text = CORD_cat(text, ", "); + text = Texts(text, type_to_text(get_arg_ast_type(env, arg))); + if (arg->next) text = Texts(text, ", "); } if (ret_t && ret_t->tag != VoidType) - text = CORD_all(text, "->", type_to_cord(ret_t)); - text = CORD_all(text, ")"); + text = Texts(text, "->", type_to_text(ret_t)); + text = Texts(text, ")"); return definition; } -CORD compile_top_level_code(env_t *env, ast_t *ast) +Text_t compile_top_level_code(env_t *env, ast_t *ast) { - if (!ast) return CORD_EMPTY; + if (!ast) return EMPTY_TEXT; switch (ast->tag) { case Use: { // DeclareMatch(use, ast, Use); // if (use->what == USE_C_CODE) { // Path_t path = Path$relative_to(Path$from_str(use->path), Path(".build")); - // return CORD_all("#include \"", Path$as_c_string(path), "\"\n"); + // return Texts("#include \"", Path$as_c_string(path), "\"\n"); // } - return CORD_EMPTY; + return EMPTY_TEXT; } case Declare: { DeclareMatch(decl, ast, Declare); const char *decl_name = Match(decl->var, Var)->name; - CORD full_name = namespace_name(env, env->namespace, decl_name); + Text_t full_name = namespace_name(env, env->namespace, Text$from_str(decl_name)); type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == FunctionType) t = Type(ClosureType, t); - CORD val_code = compile_declared_value(env, ast); + Text_t val_code = compile_declared_value(env, ast); bool is_private = decl_name[0] == '_'; if ((decl->value && is_constant(env, decl->value)) || (!decl->value && !has_heap_memory(t))) { set_binding(env, decl_name, t, full_name); - return CORD_all( + return Texts( is_private ? "static " : "public ", compile_declaration(t, full_name), " = ", val_code, ";\n"); } else { - CORD init_var = namespace_name(env, env->namespace, CORD_all(decl_name, "$$initialized")); - CORD checked_access = CORD_all("check_initialized(", full_name, ", ", init_var, ", \"", decl_name, "\")"); + Text_t init_var = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized")); + Text_t checked_access = Texts("check_initialized(", full_name, ", ", init_var, ", \"", decl_name, "\")"); set_binding(env, decl_name, t, checked_access); - CORD initialized_name = namespace_name(env, env->namespace, CORD_all(decl_name, "$$initialized")); - return CORD_all( + Text_t initialized_name = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized")); + return Texts( "static bool ", initialized_name, " = false;\n", is_private ? "static " : "public ", compile_declaration(t, full_name), ";\n"); } } case FunctionDef: { - CORD name_code = namespace_name(env, env->namespace, Match(Match(ast, FunctionDef)->name, Var)->name); + Text_t name_code = namespace_name(env, env->namespace, Text$from_str(Match(Match(ast, FunctionDef)->name, Var)->name)); return compile_function(env, name_code, ast, &env->code->staticdefs); } case ConvertDef: { @@ -4383,31 +4377,31 @@ CORD compile_top_level_code(env_t *env, ast_t *ast) const char *name = get_type_name(Match(type, FunctionType)->ret); if (!name) code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(Match(type, FunctionType)->ret)); - CORD name_code = namespace_name(env, env->namespace, CORD_all(name, "$", String(get_line_number(ast->file, ast->start)))); + Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start)))); return compile_function(env, name_code, ast, &env->code->staticdefs); } case StructDef: { DeclareMatch(def, ast, StructDef); type_t *t = Table$str_get(*env->types, def->name); assert(t && t->tag == StructType); - CORD code = compile_struct_typeinfo(env, t, def->name, def->fields, def->secret, def->opaque); + Text_t code = compile_struct_typeinfo(env, t, def->name, def->fields, def->secret, def->opaque); env_t *ns_env = namespace_env(env, def->name); - return CORD_all(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : CORD_EMPTY); + return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT); } case EnumDef: { DeclareMatch(def, ast, EnumDef); - CORD code = compile_enum_typeinfo(env, ast); - code = CORD_all(code, compile_enum_constructors(env, ast)); + Text_t code = compile_enum_typeinfo(env, ast); + code = Texts(code, compile_enum_constructors(env, ast)); env_t *ns_env = namespace_env(env, def->name); - return CORD_all(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : CORD_EMPTY); + return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT); } case LangDef: { DeclareMatch(def, ast, LangDef); - CORD code = CORD_all("public const TypeInfo_t ", namespace_name(env, env->namespace, CORD_all(def->name, "$$info")), + Text_t code = Texts("public const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, "$$info")), " = {", String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)), - ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", CORD_quoted(def->name), "}};\n"); + ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", quoted_str(def->name), "}};\n"); env_t *ns_env = namespace_env(env, def->name); - return CORD_all(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : CORD_EMPTY); + return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT); } case Extend: { DeclareMatch(extend, ast, Extend); @@ -4422,15 +4416,15 @@ CORD compile_top_level_code(env_t *env, ast_t *ast) extended->id_suffix = env->id_suffix; return compile_top_level_code(extended, extend->body); } - case Extern: return CORD_EMPTY; + case Extern: return EMPTY_TEXT; case Block: { - CORD code = CORD_EMPTY; + Text_t code = EMPTY_TEXT; for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { - code = CORD_all(code, compile_top_level_code(env, stmt->ast)); + code = Texts(code, compile_top_level_code(env, stmt->ast)); } return code; } - default: return CORD_EMPTY; + default: return EMPTY_TEXT; } } @@ -4440,22 +4434,22 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast) for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { if (stmt->ast->tag == InlineCCode) { - CORD code = compile_statement(env, stmt->ast); - env->code->staticdefs = CORD_all(env->code->staticdefs, code, "\n"); + Text_t code = compile_statement(env, stmt->ast); + env->code->staticdefs = Texts(env->code->staticdefs, code, "\n"); } else if (stmt->ast->tag == Declare) { DeclareMatch(decl, stmt->ast, Declare); const char *decl_name = Match(decl->var, Var)->name; - CORD full_name = namespace_name(env, env->namespace, decl_name); + Text_t full_name = namespace_name(env, env->namespace, Text$from_str(decl_name)); type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == FunctionType) t = Type(ClosureType, t); - CORD val_code = compile_declared_value(env, stmt->ast); + Text_t val_code = compile_declared_value(env, stmt->ast); if ((decl->value && !is_constant(env, decl->value)) || (!decl->value && has_heap_memory(t))) { - CORD initialized_name = namespace_name(env, env->namespace, CORD_all(decl_name, "$$initialized")); - env->code->variable_initializers = CORD_all( + Text_t initialized_name = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized")); + env->code->variable_initializers = Texts( env->code->variable_initializers, with_source_info( env, stmt->ast, - CORD_all( + Texts( full_name, " = ", val_code, ",\n", initialized_name, " = true;\n"))); } @@ -4474,28 +4468,27 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast) } else if (stmt->ast->tag == Use) { continue; } else { - CORD code = compile_statement(env, stmt->ast); - if (code) code_err(stmt->ast, "I did not expect this to generate code"); - assert(!code); + Text_t code = compile_statement(env, stmt->ast); + if (code.length > 0) code_err(stmt->ast, "I did not expect this to generate code"); } } } -CORD compile_file(env_t *env, ast_t *ast) +Text_t compile_file(env_t *env, ast_t *ast) { - CORD top_level_code = compile_top_level_code(env, ast); - CORD includes = CORD_EMPTY; - CORD use_imports = CORD_EMPTY; + Text_t top_level_code = compile_top_level_code(env, ast); + Text_t includes = EMPTY_TEXT; + Text_t use_imports = EMPTY_TEXT; // First prepare variable initializers to prevent unitialized access: for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { if (stmt->ast->tag == Use) { - use_imports = CORD_all(use_imports, compile_statement(env, stmt->ast)); + use_imports = Texts(use_imports, compile_statement(env, stmt->ast)); DeclareMatch(use, stmt->ast, Use); if (use->what == USE_C_CODE) { Path_t path = Path$relative_to(Path$from_str(use->path), Path(".build")); - includes = CORD_all(includes, "#include \"", Path$as_c_string(path), "\"\n"); + includes = Texts(includes, "#include \"", Path$as_c_string(path), "\"\n"); } } } @@ -4503,9 +4496,9 @@ CORD compile_file(env_t *env, ast_t *ast) initialize_vars_and_statics(env, ast); const char *name = file_base_name(ast->file->filename); - return CORD_all( - env->do_source_mapping ? CORD_all("#line 1 ", CORD_quoted(ast->file->filename), "\n") : CORD_EMPTY, - "#define __SOURCE_FILE__ ", CORD_quoted(ast->file->filename), "\n", + return Texts( + env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT, + "#define __SOURCE_FILE__ ", quoted_str(ast->file->filename), "\n", "#include <tomo_"TOMO_VERSION"/tomo.h>\n" "#include \"", name, ".tm.h\"\n\n", includes, @@ -4513,7 +4506,7 @@ CORD compile_file(env_t *env, ast_t *ast) env->code->lambdas, "\n", env->code->staticdefs, "\n", top_level_code, - "public void ", namespace_name(env, env->namespace, "$initialize"), "(void) {\n", + "public void ", namespace_name(env, env->namespace, Text("$initialize")), "(void) {\n", "static bool initialized = false;\n", "if (initialized) return;\n", "initialized = true;\n", @@ -4522,7 +4515,7 @@ CORD compile_file(env_t *env, ast_t *ast) "}\n"); } -CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) +Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) { switch (ast->tag) { case Use: { @@ -4540,13 +4533,13 @@ CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) code_err(ast, "Could not find library"); } - CORD includes = CORD_EMPTY; + Text_t includes = EMPTY_TEXT; for (size_t i = 0; i < tm_files.gl_pathc; i++) { const char *filename = tm_files.gl_pathv[i]; Path_t tm_file = Path$from_str(filename); Path_t lib_build_dir = Path$sibling(tm_file, Text(".build")); Path_t header = Path$child(lib_build_dir, Texts(Path$base_name(tm_file), Text(".h"))); - includes = CORD_all(includes, "#include \"", Path$as_c_string(header), "\"\n"); + includes = Texts(includes, "#include \"", Path$as_c_string(header), "\"\n"); } globfree(&tm_files); return with_source_info(env, ast, includes); @@ -4555,17 +4548,17 @@ CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir); Path_t used_build_dir = Path$sibling(used_path, Text(".build")); Path_t used_header_path = Path$child(used_build_dir, Texts(Path$base_name(used_path), Text(".h"))); - return CORD_all("#include \"", Path$as_c_string(Path$relative_to(used_header_path, build_dir)), "\"\n"); + return Texts("#include \"", Path$as_c_string(Path$relative_to(used_header_path, build_dir)), "\"\n"); } case USE_HEADER: if (use->path[0] == '<') { - return CORD_all("#include ", use->path, "\n"); + return Texts("#include ", use->path, "\n"); } else { Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir); - return CORD_all("#include \"", Path$as_c_string(Path$relative_to(used_path, build_dir)), "\"\n"); + return Texts("#include \"", Path$as_c_string(Path$relative_to(used_path, build_dir)), "\"\n"); } default: - return CORD_EMPTY; + return EMPTY_TEXT; } } case StructDef: { @@ -4576,24 +4569,24 @@ CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) } case LangDef: { DeclareMatch(def, ast, LangDef); - return CORD_all( + return Texts( // Constructor macro: - "#define ", namespace_name(env, env->namespace, def->name), - "(text) ((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n" - "#define ", namespace_name(env, env->namespace, def->name), - "s(...) ((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), ")Texts(__VA_ARGS__))\n" - "extern const TypeInfo_t ", namespace_name(env, env->namespace, CORD_all(def->name, "$$info")), ";\n" + "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)), + "(text) ((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n" + "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)), + "s(...) ((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), ")Texts(__VA_ARGS__))\n" + "extern const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n" ); } case Extend: { - return CORD_EMPTY; + return EMPTY_TEXT; } default: - return CORD_EMPTY; + return EMPTY_TEXT; } } -CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) +Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) { env_t *ns_env = NULL; ast_t *block = NULL; @@ -4633,27 +4626,27 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a case Extern: { DeclareMatch(ext, ast, Extern); type_t *t = parse_type_ast(env, ext->type); - CORD decl; + Text_t decl; if (t->tag == ClosureType) { t = Match(t, ClosureType)->fn; DeclareMatch(fn, t, FunctionType); - decl = CORD_all(compile_type(fn->ret), " ", ext->name, "("); + decl = Texts(compile_type(fn->ret), " ", ext->name, "("); for (arg_t *arg = fn->args; arg; arg = arg->next) { - decl = CORD_all(decl, compile_type(arg->type)); - if (arg->next) decl = CORD_cat(decl, ", "); + decl = Texts(decl, compile_type(arg->type)); + if (arg->next) decl = Texts(decl, ", "); } - decl = CORD_cat(decl, ")"); + decl = Texts(decl, ")"); } else { - decl = compile_declaration(t, ext->name); + decl = compile_declaration(t, Text$from_str(ext->name)); } - return CORD_all("extern ", decl, ";\n"); + return Texts("extern ", decl, ";\n"); } case Declare: { DeclareMatch(decl, ast, Declare); const char *decl_name = Match(decl->var, Var)->name; bool is_private = (decl_name[0] == '_'); if (is_private) - return CORD_EMPTY; + return EMPTY_TEXT; type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == FunctionType) @@ -4662,64 +4655,64 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType) code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value"); - return CORD_all( - decl->value ? compile_statement_type_header(env, header_path, decl->value) : CORD_EMPTY, - "extern ", compile_declaration(t, namespace_name(env, env->namespace, decl_name)), ";\n"); + return Texts( + decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT, + "extern ", compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n"); } case FunctionDef: { DeclareMatch(fndef, ast, FunctionDef); const char *decl_name = Match(fndef->name, Var)->name; bool is_private = decl_name[0] == '_'; - if (is_private) return CORD_EMPTY; - CORD arg_signature = "("; + if (is_private) return EMPTY_TEXT; + Text_t arg_signature = Text("("); for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - arg_signature = CORD_cat(arg_signature, compile_declaration(arg_type, CORD_cat("_$", arg->name))); - if (arg->next) arg_signature = CORD_cat(arg_signature, ", "); + arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name))); + if (arg->next) arg_signature = Texts(arg_signature, ", "); } - arg_signature = CORD_cat(arg_signature, ")"); + arg_signature = Texts(arg_signature, ")"); type_t *ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType); - CORD ret_type_code = compile_type(ret_t); + Text_t ret_type_code = compile_type(ret_t); if (ret_t->tag == AbortType) - ret_type_code = CORD_all("__attribute__((noreturn)) _Noreturn ", ret_type_code); - CORD name = namespace_name(env, env->namespace, decl_name); + ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code); + Text_t name = namespace_name(env, env->namespace, Text$from_str(decl_name)); if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name)) - name = namespace_name(env, env->namespace, String(get_line_number(ast->file, ast->start))); - return CORD_all(ret_type_code, " ", name, arg_signature, ";\n"); + name = namespace_name(env, env->namespace, Text$from_str(String(get_line_number(ast->file, ast->start)))); + return Texts(ret_type_code, " ", name, arg_signature, ";\n"); } case ConvertDef: { DeclareMatch(def, ast, ConvertDef); - CORD arg_signature = "("; + Text_t arg_signature = Text("("); for (arg_ast_t *arg = def->args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); - arg_signature = CORD_cat(arg_signature, compile_declaration(arg_type, CORD_cat("_$", arg->name))); - if (arg->next) arg_signature = CORD_cat(arg_signature, ", "); + arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name))); + if (arg->next) arg_signature = Texts(arg_signature, ", "); } - arg_signature = CORD_cat(arg_signature, ")"); + arg_signature = Texts(arg_signature, ")"); type_t *ret_t = def->ret_type ? parse_type_ast(env, def->ret_type) : Type(VoidType); - CORD ret_type_code = compile_type(ret_t); - CORD name = get_type_name(ret_t); - if (!name) + Text_t ret_type_code = compile_type(ret_t); + Text_t name = Text$from_str(get_type_name(ret_t)); + if (name.length == 0) code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t)); - CORD name_code = namespace_name(env, env->namespace, CORD_all(name, "$", String(get_line_number(ast->file, ast->start)))); - return CORD_all(ret_type_code, " ", name_code, arg_signature, ";\n"); + Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start)))); + return Texts(ret_type_code, " ", name_code, arg_signature, ";\n"); } - default: return CORD_EMPTY; + default: return EMPTY_TEXT; } assert(ns_env); - CORD header = CORD_EMPTY; + Text_t header = EMPTY_TEXT; for (ast_list_t *stmt = block ? Match(block, Block)->statements : NULL; stmt; stmt = stmt->next) { - header = CORD_all(header, compile_statement_namespace_header(ns_env, header_path, stmt->ast)); + header = Texts(header, compile_statement_namespace_header(ns_env, header_path, stmt->ast)); } return header; } typedef struct { env_t *env; - CORD *header; + Text_t *header; Path_t header_path; } compile_typedef_info_t; @@ -4728,9 +4721,9 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) if (ast->tag == StructDef) { DeclareMatch(def, ast, StructDef); if (def->external) return; - CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct")); - CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")); - *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); + Text_t struct_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$struct")); + Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")); + *info->header = Texts(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); } else if (ast->tag == EnumDef) { DeclareMatch(def, ast, EnumDef); bool has_any_tags_with_fields = false; @@ -4739,46 +4732,46 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) } if (has_any_tags_with_fields) { - CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct")); - CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")); - *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); + Text_t struct_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$struct")); + Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")); + *info->header = Texts(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { if (!tag->fields) continue; - CORD tag_struct = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$struct")); - CORD tag_type = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$type")); - *info->header = CORD_all(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n"); + Text_t tag_struct = namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct")); + Text_t tag_type = namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type")); + *info->header = Texts(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n"); } } else { - CORD enum_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$enum")); - CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")); - *info->header = CORD_all(*info->header, "typedef enum ", enum_name, " ", type_name, ";\n"); + Text_t enum_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$enum")); + Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")); + *info->header = Texts(*info->header, "typedef enum ", enum_name, " ", type_name, ";\n"); } } else if (ast->tag == LangDef) { DeclareMatch(def, ast, LangDef); - *info->header = CORD_all(*info->header, "typedef Text_t ", namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")), ";\n"); + *info->header = Texts(*info->header, "typedef Text_t ", namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n"); } } static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast) { - *info->header = CORD_all(*info->header, + *info->header = Texts(*info->header, compile_statement_type_header(info->env, info->header_path, ast), compile_statement_namespace_header(info->env, info->header_path, ast)); } -CORD compile_file_header(env_t *env, Path_t header_path, ast_t *ast) +Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast) { - CORD header = CORD_all( + Text_t header = Texts( "#pragma once\n", - env->do_source_mapping ? CORD_all("#line 1 ", CORD_quoted(ast->file->filename), "\n") : CORD_EMPTY, + env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT, "#include <tomo_"TOMO_VERSION"/tomo.h>\n"); compile_typedef_info_t info = {.env=env, .header=&header, .header_path=header_path}; visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_make_typedefs, &info}); visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_define_types_and_funcs, &info}); - header = CORD_all(header, "void ", namespace_name(env, env->namespace, "$initialize"), "(void);\n"); + header = Texts(header, "void ", namespace_name(env, env->namespace, Text("$initialize")), "(void);\n"); return header; } diff --git a/src/compile.h b/src/compile.h index f4452288..2e866cc2 100644 --- a/src/compile.h +++ b/src/compile.h @@ -2,24 +2,23 @@ // Compilation functions -#include <gc/cord.h> #include <gc.h> #include <stdio.h> #include "environment.h" #include "stdlib/datatypes.h" -CORD expr_as_text(CORD expr, type_t *t, CORD color); -CORD compile_file(env_t *env, ast_t *ast); -CORD compile_file_header(env_t *env, Path_t header_path, ast_t *ast); -CORD compile_declaration(type_t *t, const char *name); -CORD compile_type(type_t *t); -CORD compile(env_t *env, ast_t *ast); -CORD compile_namespace_header(env_t *env, const char *ns_name, ast_t *block); -CORD compile_statement(env_t *env, ast_t *ast); -CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast); -CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast); -CORD compile_type_info(type_t *t); -CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type, const char *version); +Text_t expr_as_text(Text_t expr, type_t *t, Text_t color); +Text_t compile_file(env_t *env, ast_t *ast); +Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast); +Text_t compile_declaration(type_t *t, Text_t name); +Text_t compile_type(type_t *t); +Text_t compile(env_t *env, ast_t *ast); +Text_t compile_namespace_header(env_t *env, const char *ns_name, ast_t *block); +Text_t compile_statement(env_t *env, ast_t *ast); +Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast); +Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast); +Text_t compile_type_info(type_t *t); +Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/cordhelpers.c b/src/cordhelpers.c deleted file mode 100644 index 353a52d9..00000000 --- a/src/cordhelpers.c +++ /dev/null @@ -1,66 +0,0 @@ -// Some helper functions for the GC Cord library - -#include <gc/cord.h> -#include <stdint.h> - -#include "cordhelpers.h" -#include "stdlib/print.h" -#include "stdlib/util.h" - -public CORD CORD_quoted(CORD str) -{ - CORD quoted = "\""; - CORD_pos i; -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - CORD_FOR(i, str) { -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - char c = CORD_pos_fetch(i); - switch (c) { - case '\a': quoted = CORD_cat(quoted, "\\a"); break; - case '\b': quoted = CORD_cat(quoted, "\\b"); break; - case '\x1b': quoted = CORD_cat(quoted, "\\e"); break; - case '\f': quoted = CORD_cat(quoted, "\\f"); break; - case '\n': quoted = CORD_cat(quoted, "\\n"); break; - case '\r': quoted = CORD_cat(quoted, "\\r"); break; - case '\t': quoted = CORD_cat(quoted, "\\t"); break; - case '\v': quoted = CORD_cat(quoted, "\\v"); break; - case '"': quoted = CORD_cat(quoted, "\\\""); break; - case '\\': quoted = CORD_cat(quoted, "\\\\"); break; - case '\x00' ... '\x06': case '\x0E' ... '\x1A': - case '\x1C' ... '\x1F': case '\x7F' ... '\x7F': - quoted = CORD_all(quoted, "\\x", String(hex((uint64_t)c, .no_prefix=true, .uppercase=true, .digits=2))); - break; - default: quoted = CORD_cat_char(quoted, c); break; - } - } - quoted = CORD_cat_char(quoted, '"'); - return quoted; -} - -public CORD CORD_replace(CORD c, CORD to_replace, CORD replacement) -{ - size_t len = CORD_len(c); - size_t replaced_len = CORD_len(to_replace); - size_t pos = 0; - CORD ret = CORD_EMPTY; - while (pos < len) { - size_t found = CORD_str(c, pos, to_replace); - if (found == CORD_NOT_FOUND) { - if (pos < len) - ret = CORD_cat(ret, CORD_substr(c, pos, len)); - return ret; - } - if (found > pos) - ret = CORD_cat(ret, CORD_substr(c, pos, found-pos)); - ret = CORD_cat(ret, replacement); - pos = found + replaced_len; - } - return ret; -} - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/cordhelpers.h b/src/cordhelpers.h deleted file mode 100644 index b519a443..00000000 --- a/src/cordhelpers.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -// Some helper functions for the GC Cord library - -#include <gc/cord.h> - -#define CORD_all(...) CORD_catn(sizeof((CORD[]){__VA_ARGS__})/sizeof(CORD), __VA_ARGS__) - -CORD CORD_quoted(CORD str); -CORD CORD_replace(CORD c, CORD to_replace, CORD replacement); - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/enums.c b/src/enums.c index 2ff64ad3..c6bd9560 100644 --- a/src/enums.c +++ b/src/enums.c @@ -1,31 +1,29 @@ // Logic for compiling tagged unions (enums) #include <ctype.h> -#include <gc/cord.h> #include <gc.h> #include <stdio.h> #include "ast.h" #include "stdlib/text.h" #include "compile.h" -#include "cordhelpers.h" #include "structs.h" #include "environment.h" #include "typecheck.h" #include "stdlib/util.h" -CORD compile_enum_typeinfo(env_t *env, ast_t *ast) +Text_t compile_enum_typeinfo(env_t *env, ast_t *ast) { DeclareMatch(def, ast, EnumDef); // Compile member types and constructors: - CORD member_typeinfos = CORD_EMPTY; + Text_t member_typeinfos = EMPTY_TEXT; for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { if (!tag->fields) continue; const char *tag_name = String(def->name, "$", tag->name); type_t *tag_type = Table$str_get(*env->types, tag_name); assert(tag_type && tag_type->tag == StructType); - member_typeinfos = CORD_all( + member_typeinfos = Texts( member_typeinfos, compile_struct_typeinfo(env, tag_type, tag_name, tag->fields, tag->secret, false)); } @@ -35,8 +33,8 @@ CORD compile_enum_typeinfo(env_t *env, ast_t *ast) type_t *t = Table$str_get(*env->types, def->name); const char *metamethods = is_packed_data(t) ? "PackedDataEnum$metamethods" : "Enum$metamethods"; - CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info")); - CORD typeinfo = CORD_all("public const TypeInfo_t ", info, " = {", + Text_t info = namespace_name(env, env->namespace, Texts(def->name, "$$info")); + Text_t typeinfo = Texts("public const TypeInfo_t ", info, " = {", String((int64_t)type_size(t)), "u, ", String((int64_t)type_align(t)), "u, .metamethods=", metamethods, ", {.tag=EnumInfo, .EnumInfo={.name=\"", def->name, "\", " ".num_tags=", String((int64_t)num_tags), ", .tags=(NamedType_t[]){"); @@ -45,96 +43,96 @@ CORD compile_enum_typeinfo(env_t *env, ast_t *ast) const char *tag_type_name = String(def->name, "$", tag->name); type_t *tag_type = Table$str_get(*env->types, tag_type_name); if (tag_type && Match(tag_type, StructType)->fields) - typeinfo = CORD_all(typeinfo, "{\"", tag->name, "\", ", compile_type_info(tag_type), "}, "); + typeinfo = Texts(typeinfo, "{\"", tag->name, "\", ", compile_type_info(tag_type), "}, "); else - typeinfo = CORD_all(typeinfo, "{\"", tag->name, "\"}, "); + typeinfo = Texts(typeinfo, "{\"", tag->name, "\"}, "); } - typeinfo = CORD_all(typeinfo, "}}}};\n"); - return CORD_all(member_typeinfos, typeinfo); + typeinfo = Texts(typeinfo, "}}}};\n"); + return Texts(member_typeinfos, typeinfo); } -CORD compile_enum_constructors(env_t *env, ast_t *ast) +Text_t compile_enum_constructors(env_t *env, ast_t *ast) { DeclareMatch(def, ast, EnumDef); - CORD constructors = CORD_EMPTY; + Text_t constructors = EMPTY_TEXT; for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { if (!tag->fields) continue; - CORD arg_sig = CORD_EMPTY; + Text_t arg_sig = EMPTY_TEXT; for (arg_ast_t *field = tag->fields; field; field = field->next) { type_t *field_t = get_arg_ast_type(env, field); - arg_sig = CORD_all(arg_sig, compile_declaration(field_t, CORD_all("$", field->name))); - if (field->next) arg_sig = CORD_cat(arg_sig, ", "); + arg_sig = Texts(arg_sig, compile_declaration(field_t, Texts("$", field->name))); + if (field->next) arg_sig = Texts(arg_sig, ", "); } - if (arg_sig == CORD_EMPTY) arg_sig = "void"; - CORD type_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$type")); - CORD tagged_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name)); - CORD tag_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)); - CORD constructor_impl = CORD_all("public inline ", type_name, " ", tagged_name, "(", arg_sig, ") { return (", + if (arg_sig.length == 0) arg_sig = Text("void"); + Text_t type_name = namespace_name(env, env->namespace, Texts(def->name, "$$type")); + Text_t tagged_name = namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name)); + Text_t tag_name = namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)); + Text_t constructor_impl = Texts("public inline ", type_name, " ", tagged_name, "(", arg_sig, ") { return (", type_name, "){.$tag=", tag_name, ", .", tag->name, "={"); for (arg_ast_t *field = tag->fields; field; field = field->next) { - constructor_impl = CORD_all(constructor_impl, "$", field->name); - if (field->next) constructor_impl = CORD_cat(constructor_impl, ", "); + constructor_impl = Texts(constructor_impl, "$", field->name); + if (field->next) constructor_impl = Texts(constructor_impl, ", "); } - constructor_impl = CORD_cat(constructor_impl, "}}; }\n"); - constructors = CORD_cat(constructors, constructor_impl); + constructor_impl = Texts(constructor_impl, "}}; }\n"); + constructors = Texts(constructors, constructor_impl); } return constructors; } -CORD compile_enum_header(env_t *env, ast_t *ast) +Text_t compile_enum_header(env_t *env, ast_t *ast) { DeclareMatch(def, ast, EnumDef); - CORD all_defs = CORD_EMPTY; - CORD none_name = namespace_name(env, env->namespace, CORD_all(def->name, "$none")); - CORD enum_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$enum")); - CORD enum_tags = CORD_all("{ ", none_name, "=0, "); + Text_t all_defs = EMPTY_TEXT; + Text_t none_name = namespace_name(env, env->namespace, Texts(def->name, "$none")); + Text_t enum_name = namespace_name(env, env->namespace, Texts(def->name, "$$enum")); + Text_t enum_tags = Texts("{ ", none_name, "=0, "); bool has_any_tags_with_fields = false; for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { - CORD tag_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)); - enum_tags = CORD_all(enum_tags, tag_name); - if (tag->next) enum_tags = CORD_all(enum_tags, ", "); + Text_t tag_name = namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)); + enum_tags = Texts(enum_tags, tag_name); + if (tag->next) enum_tags = Texts(enum_tags, ", "); has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL); } - enum_tags = CORD_all(enum_tags, " }"); + enum_tags = Texts(enum_tags, " }"); if (!has_any_tags_with_fields) { - CORD enum_def = CORD_all("enum ", enum_name, " ", enum_tags, ";\n"); - CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info")); - return CORD_all(enum_def, "extern const TypeInfo_t ", info, ";\n"); + Text_t enum_def = Texts("enum ", enum_name, " ", enum_tags, ";\n"); + Text_t info = namespace_name(env, env->namespace, Texts(def->name, "$$info")); + return Texts(enum_def, "extern const TypeInfo_t ", info, ";\n"); } - CORD struct_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$struct")); - CORD enum_def = CORD_all("struct ", struct_name, " {\n" + Text_t struct_name = namespace_name(env, env->namespace, Texts(def->name, "$$struct")); + Text_t enum_def = Texts("struct ", struct_name, " {\n" "enum ", enum_tags, " $tag;\n" "union {\n"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { if (!tag->fields) continue; - CORD field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)), .fields=tag->fields)); - all_defs = CORD_all(all_defs, field_def); - CORD tag_type = namespace_name(env, env->namespace, CORD_all(def->name, "$", tag->name, "$$type")); - enum_def = CORD_all(enum_def, tag_type, " ", tag->name, ";\n"); + Text_t field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=Text$as_c_string(Texts(def->name, "$", tag->name)), .fields=tag->fields)); + all_defs = Texts(all_defs, field_def); + Text_t tag_type = namespace_name(env, env->namespace, Texts(def->name, "$", tag->name, "$$type")); + enum_def = Texts(enum_def, tag_type, " ", tag->name, ";\n"); } - enum_def = CORD_all(enum_def, "};\n};\n"); - all_defs = CORD_all(all_defs, enum_def); + enum_def = Texts(enum_def, "};\n};\n"); + all_defs = Texts(all_defs, enum_def); - CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info")); - all_defs = CORD_all(all_defs, "extern const TypeInfo_t ", info, ";\n"); + Text_t info = namespace_name(env, env->namespace, Texts(def->name, "$$info")); + all_defs = Texts(all_defs, "extern const TypeInfo_t ", info, ";\n"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { if (!tag->fields) continue; - CORD arg_sig = CORD_EMPTY; + Text_t arg_sig = EMPTY_TEXT; for (arg_ast_t *field = tag->fields; field; field = field->next) { type_t *field_t = get_arg_ast_type(env, field); - arg_sig = CORD_all(arg_sig, compile_declaration(field_t, CORD_all("$", field->name))); - if (field->next) arg_sig = CORD_all(arg_sig, ", "); + arg_sig = Texts(arg_sig, compile_declaration(field_t, Texts("$", field->name))); + if (field->next) arg_sig = Texts(arg_sig, ", "); } - if (arg_sig == CORD_EMPTY) arg_sig = "void"; - CORD enum_type = namespace_name(env, env->namespace, CORD_all(def->name, "$$type")); - CORD tagged_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name)); - CORD constructor_def = CORD_all(enum_type, " ", tagged_name, "(", arg_sig, ");\n"); - all_defs = CORD_all(all_defs, constructor_def); + if (arg_sig.length == 0) arg_sig = Text("void"); + Text_t enum_type = namespace_name(env, env->namespace, Texts(def->name, "$$type")); + Text_t tagged_name = namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name)); + Text_t constructor_def = Texts(enum_type, " ", tagged_name, "(", arg_sig, ");\n"); + all_defs = Texts(all_defs, constructor_def); } return all_defs; } diff --git a/src/enums.h b/src/enums.h index 5f693e5a..6f394a60 100644 --- a/src/enums.h +++ b/src/enums.h @@ -2,13 +2,12 @@ // Compilation of tagged unions (enums) -#include <gc/cord.h> - #include "ast.h" #include "environment.h" +#include "stdlib/datatypes.h" -CORD compile_enum_typeinfo(env_t *env, ast_t *ast); -CORD compile_enum_constructors(env_t *env, ast_t *ast); -CORD compile_enum_header(env_t *env, ast_t *ast); +Text_t compile_enum_typeinfo(env_t *env, ast_t *ast); +Text_t compile_enum_constructors(env_t *env, ast_t *ast); +Text_t compile_enum_header(env_t *env, ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/environment.c b/src/environment.c index 0dbe015d..0bcdd592 100644 --- a/src/environment.c +++ b/src/environment.c @@ -4,7 +4,6 @@ #include <signal.h> #include <sys/stat.h> -#include "cordhelpers.h" #include "environment.h" #include "parse.h" #include "stdlib/datatypes.h" @@ -78,17 +77,17 @@ env_t *global_env(bool source_mapping) struct { const char *name; type_t *type; - CORD typename; - CORD typeinfo; + Text_t typename; + Text_t typeinfo; List_t namespace; } global_types[] = { - {"Void", Type(VoidType), "Void_t", "Void$info", {}}, - {"Abort", Type(AbortType), "void", "Abort$info", {}}, - {"Memory", Type(MemoryType), "Memory_t", "Memory$info", {}}, - {"Bool", Type(BoolType), "Bool_t", "Bool$info", TypedList(ns_entry_t, + {"Void", Type(VoidType), Text("Void_t"), Text("Void$info"), {}}, + {"Abort", Type(AbortType), Text("void"), Text("Abort$info"), {}}, + {"Memory", Type(MemoryType), Text("Memory_t"), Text("Memory$info"), {}}, + {"Bool", Type(BoolType), Text("Bool_t"), Text("Bool$info"), TypedList(ns_entry_t, {"parse", "Bool$parse", "func(text:Text -> Bool?)"}, )}, - {"Byte", Type(ByteType), "Byte_t", "Byte$info", TypedList(ns_entry_t, + {"Byte", Type(ByteType), Text("Byte_t"), Text("Byte$info"), TypedList(ns_entry_t, {"max", "Byte$max", "Byte"}, {"get_bit", "Byte$get_bit", "func(x:Byte, bit_index:Int -> Bool)"}, {"hex", "Byte$hex", "func(byte:Byte, uppercase=yes, prefix=no -> Text)"}, @@ -96,7 +95,7 @@ env_t *global_env(bool source_mapping) {"min", "Byte$min", "Byte"}, {"to", "Byte$to", "func(first:Byte, last:Byte, step:Int8?=none -> func(->Byte?))"}, )}, - {"Int", Type(BigIntType), "Int_t", "Int$info", TypedList(ns_entry_t, + {"Int", Type(BigIntType), Text("Int_t"), Text("Int$info"), TypedList(ns_entry_t, {"abs", "Int$abs", "func(x:Int -> Int)"}, {"bit_and", "Int$bit_and", "func(x,y:Int -> Int)"}, {"bit_or", "Int$bit_or", "func(x,y:Int -> Int)"}, @@ -132,7 +131,7 @@ env_t *global_env(bool source_mapping) {"times", "Int$times", "func(x,y:Int -> Int)"}, {"to", "Int$to", "func(first:Int,last:Int,step:Int?=none -> func(->Int?))"}, )}, - {"Int64", Type(IntType, .bits=TYPE_IBITS64), "Int64_t", "Int64$info", TypedList(ns_entry_t, + {"Int64", Type(IntType, .bits=TYPE_IBITS64), Text("Int64_t"), Text("Int64$info"), TypedList(ns_entry_t, {"abs", "labs", "func(i:Int64 -> Int64)"}, {"bits", "Int64$bits", "func(x:Int64 -> [Bool])"}, {"clamped", "Int64$clamped", "func(x,low,high:Int64 -> Int64)"}, @@ -154,7 +153,7 @@ env_t *global_env(bool source_mapping) {"wrapping_minus", "Int64$wrapping_minus", "func(x:Int64,y:Int64 -> Int64)"}, {"wrapping_plus", "Int64$wrapping_plus", "func(x:Int64,y:Int64 -> Int64)"}, )}, - {"Int32", Type(IntType, .bits=TYPE_IBITS32), "Int32_t", "Int32$info", TypedList(ns_entry_t, + {"Int32", Type(IntType, .bits=TYPE_IBITS32), Text("Int32_t"), Text("Int32$info"), TypedList(ns_entry_t, {"abs", "abs", "func(i:Int32 -> Int32)"}, {"bits", "Int32$bits", "func(x:Int32 -> [Bool])"}, {"clamped", "Int32$clamped", "func(x,low,high:Int32 -> Int32)"}, @@ -176,7 +175,7 @@ env_t *global_env(bool source_mapping) {"wrapping_minus", "Int32$wrapping_minus", "func(x:Int32,y:Int32 -> Int32)"}, {"wrapping_plus", "Int32$wrapping_plus", "func(x:Int32,y:Int32 -> Int32)"}, )}, - {"Int16", Type(IntType, .bits=TYPE_IBITS16), "Int16_t", "Int16$info", TypedList(ns_entry_t, + {"Int16", Type(IntType, .bits=TYPE_IBITS16), Text("Int16_t"), Text("Int16$info"), TypedList(ns_entry_t, {"abs", "abs", "func(i:Int16 -> Int16)"}, {"bits", "Int16$bits", "func(x:Int16 -> [Bool])"}, {"clamped", "Int16$clamped", "func(x,low,high:Int16 -> Int16)"}, @@ -198,7 +197,7 @@ env_t *global_env(bool source_mapping) {"wrapping_minus", "Int16$wrapping_minus", "func(x:Int16,y:Int16 -> Int16)"}, {"wrapping_plus", "Int16$wrapping_plus", "func(x:Int16,y:Int16 -> Int16)"}, )}, - {"Int8", Type(IntType, .bits=TYPE_IBITS8), "Int8_t", "Int8$info", TypedList(ns_entry_t, + {"Int8", Type(IntType, .bits=TYPE_IBITS8), Text("Int8_t"), Text("Int8$info"), TypedList(ns_entry_t, {"abs", "abs", "func(i:Int8 -> Int8)"}, {"bits", "Int8$bits", "func(x:Int8 -> [Bool])"}, {"clamped", "Int8$clamped", "func(x,low,high:Int8 -> Int8)"}, @@ -224,7 +223,7 @@ env_t *global_env(bool source_mapping) #define F(name) {#name, #name, "func(n:Num -> Num)"} #define F_opt(name) {#name, #name, "func(n:Num -> Num?)"} #define F2(name) {#name, #name, "func(x,y:Num -> Num)"} - {"Num", Type(NumType, .bits=TYPE_NBITS64), "Num_t", "Num$info", TypedList(ns_entry_t, + {"Num", Type(NumType, .bits=TYPE_NBITS64), Text("Num_t"), Text("Num$info"), TypedList(ns_entry_t, {"near", "Num$near", "func(x,y:Num, ratio=1e-9, min_epsilon=1e-9 -> Bool)"}, {"clamped", "Num$clamped", "func(x,low,high:Num -> Num)"}, {"percent", "Num$percent", "func(n:Num,precision=0.01 -> Text)"}, @@ -256,7 +255,7 @@ env_t *global_env(bool source_mapping) #define F(name) {#name, #name"f", "func(n:Num32 -> Num32)"} #define F_opt(name) {#name, #name"f", "func(n:Num32 -> Num32?)"} #define F2(name) {#name, #name"f", "func(x,y:Num32 -> Num32)"} - {"Num32", Type(NumType, .bits=TYPE_NBITS32), "Num32_t", "Num32$info", TypedList(ns_entry_t, + {"Num32", Type(NumType, .bits=TYPE_NBITS32), Text("Num32_t"), Text("Num32$info"), TypedList(ns_entry_t, {"near", "Num32$near", "func(x,y:Num32, ratio=Num32(1e-9), min_epsilon=Num32(1e-9) -> Bool)"}, {"clamped", "Num32$clamped", "func(x,low,high:Num32 -> Num32)"}, {"percent", "Num32$percent", "func(n:Num32,precision=Num32(.01) -> Text)"}, @@ -280,19 +279,19 @@ env_t *global_env(bool source_mapping) F_opt(tan), F(tanh), F_opt(tgamma), F(trunc), F_opt(y0), F_opt(y1), F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter), )}, - {"CString", Type(CStringType), "char*", "CString$info", TypedList(ns_entry_t, + {"CString", Type(CStringType), Text("char*"), Text("CString$info"), TypedList(ns_entry_t, {"as_text", "Text$from_str", "func(str:CString -> Text)"}, )}, #undef F2 #undef F_opt #undef F #undef C - {"PathType", PATH_TYPE_TYPE, "PathType_t", "PathType$info", TypedList(ns_entry_t, + {"PathType", PATH_TYPE_TYPE, Text("PathType_t"), Text("PathType$info"), TypedList(ns_entry_t, {"Relative", "((PathType_t){.$tag=PATH_RELATIVE})", "PathType"}, {"Absolute", "((PathType_t){.$tag=PATH_ABSOLUTE})", "PathType"}, {"Home", "((PathType_t){.$tag=PATH_HOME})", "PathType"}, )}, - {"Path", PATH_TYPE, "Path_t", "Path$info", TypedList(ns_entry_t, + {"Path", PATH_TYPE, Text("Path_t"), Text("Path$info"), TypedList(ns_entry_t, {"accessed", "Path$accessed", "func(path:Path, follow_symlinks=yes -> Int64?)"}, {"append", "Path$append", "func(path:Path, text:Text, permissions=Int32(0o644))"}, {"append_bytes", "Path$append_bytes", "func(path:Path, bytes:[Byte], permissions=Int32(0o644))"}, @@ -337,7 +336,7 @@ env_t *global_env(bool source_mapping) {"write_unique", "Path$write_unique", "func(path:Path, text:Text -> Path)"}, {"write_unique_bytes", "Path$write_unique_bytes", "func(path:Path, bytes:[Byte] -> Path)"}, )}, - {"Text", TEXT_TYPE, "Text_t", "Text$info", TypedList(ns_entry_t, + {"Text", TEXT_TYPE, Text("Text_t"), Text("Text$info"), TypedList(ns_entry_t, {"as_c_string", "Text$as_c_string", "func(text:Text -> CString)"}, {"at", "Text$cluster", "func(text:Text, index:Int -> Text)"}, {"by_line", "Text$by_line", "func(text:Text -> func(->Text?))"}, @@ -412,7 +411,7 @@ env_t *global_env(bool source_mapping) 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); if (type->tag == ClosureType) type = Match(type, ClosureType)->fn; - set_binding(ns_env, entry->name, type, entry->code); + set_binding(ns_env, entry->name, type, Text$from_str(entry->code)); } } @@ -424,7 +423,7 @@ env_t *global_env(bool source_mapping) for (size_t i = 0; i < sizeof(constructor_infos)/sizeof(constructor_infos[0]); i++) { \ type_t *t = parse_type_string(ns_env, constructor_infos[i].type_str); \ List$insert(&ns_env->namespace->constructors, \ - ((binding_t[1]){{.code=constructor_infos[i].c_name, \ + ((binding_t[1]){{.code=Text$from_str(constructor_infos[i].c_name), \ .type=Match(t, ClosureType)->fn}}), I(0), sizeof(binding_t)); \ } \ } while (0) @@ -515,7 +514,7 @@ env_t *global_env(bool source_mapping) set_binding(namespace_env(env, "Path"), "from_text", NewFunctionType(PATH_TYPE, {.name="text", .type=TEXT_TYPE}), - "Path$from_text"); + Text("Path$from_text")); struct { const char *name, *code, *type_str; @@ -536,23 +535,23 @@ env_t *global_env(bool source_mapping) type_t *type = parse_type_string(env, global_vars[i].type_str); if (!type) compiler_err(NULL, NULL, NULL, "Couldn't parse type string for ", global_vars[i].name, ": ", global_vars[i].type_str); if (type->tag == ClosureType) type = Match(type, ClosureType)->fn; - Table$str_set(env->globals, global_vars[i].name, new(binding_t, .type=type, .code=global_vars[i].code)); + Table$str_set(env->globals, global_vars[i].name, new(binding_t, .type=type, .code=Text$from_str(global_vars[i].code))); } _global_env = env; return env; } -CORD CONSTFUNC namespace_name(env_t *env, namespace_t *ns, CORD name) +Text_t CONSTFUNC namespace_name(env_t *env, namespace_t *ns, Text_t name) { for (; ns; ns = ns->parent) - name = CORD_all(ns->name, "$", name); - if (env->id_suffix) - name = CORD_all(name, env->id_suffix); + name = Texts(ns->name, "$", name); + if (env->id_suffix.length > 0) + name = Texts(name, env->id_suffix); return name; } -CORD get_id_suffix(const char *filename) +Text_t get_id_suffix(const char *filename) { assert(filename); Path_t path = Path$from_str(filename); @@ -564,7 +563,7 @@ CORD 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: ", id_file); - return Text$as_c_string(Texts(Text("$"), id)); + return Texts(Text("$"), id); } env_t *load_module_env(env_t *env, ast_t *ast) @@ -630,10 +629,10 @@ env_t *for_scope(env_t *env, ast_t *ast) vars[num_vars++] = Match(var->ast, Var)->name; } if (num_vars == 1) { - set_binding(scope, vars[0], item_t, CORD_cat("_$", vars[0])); + set_binding(scope, vars[0], item_t, Texts("_$", vars[0])); } else if (num_vars == 2) { - set_binding(scope, vars[0], INT_TYPE, CORD_cat("_$", vars[0])); - set_binding(scope, vars[1], item_t, CORD_cat("_$", vars[1])); + set_binding(scope, vars[0], INT_TYPE, Texts("_$", vars[0])); + set_binding(scope, vars[1], item_t, Texts("_$", vars[1])); } return scope; } @@ -643,7 +642,7 @@ env_t *for_scope(env_t *env, ast_t *ast) code_err(for_->vars->next->ast, "This is too many variables for this loop"); type_t *item_type = Match(iter_t, SetType)->item_type; const char *name = Match(for_->vars->ast, Var)->name; - set_binding(scope, name, item_type, CORD_cat("_$", name)); + set_binding(scope, name, item_type, Texts("_$", name)); } return scope; } @@ -658,11 +657,11 @@ env_t *for_scope(env_t *env, ast_t *ast) type_t *key_t = Match(iter_t, TableType)->key_type; if (num_vars == 1) { - set_binding(scope, vars[0], key_t, CORD_cat("_$", vars[0])); + set_binding(scope, vars[0], key_t, Texts("_$", vars[0])); } else if (num_vars == 2) { - set_binding(scope, vars[0], key_t, CORD_cat("_$", vars[0])); + set_binding(scope, vars[0], key_t, Texts("_$", vars[0])); type_t *value_t = Match(iter_t, TableType)->value_type; - set_binding(scope, vars[1], value_t, CORD_cat("_$", vars[1])); + set_binding(scope, vars[1], value_t, Texts("_$", vars[1])); } return scope; } @@ -671,7 +670,7 @@ env_t *for_scope(env_t *env, ast_t *ast) if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop"); const char *var = Match(for_->vars->ast, Var)->name; - set_binding(scope, var, INT_TYPE, CORD_cat("_$", var)); + set_binding(scope, var, INT_TYPE, Texts("_$", var)); } return scope; } @@ -683,7 +682,7 @@ env_t *for_scope(env_t *env, ast_t *ast) code_err(for_->vars->next->ast, "This is too many variables for this loop"); const char *var = Match(for_->vars->ast, Var)->name; type_t *non_opt_type = fn->ret->tag == OptionalType ? Match(fn->ret, OptionalType)->type : fn->ret; - set_binding(scope, var, non_opt_type, CORD_cat("_$", var)); + set_binding(scope, var, non_opt_type, Texts("_$", var)); } return scope; } @@ -700,7 +699,7 @@ env_t *get_namespace_by_type(env_t *env, type_t *t) case TableType: return NULL; case CStringType: case BoolType: case IntType: case BigIntType: case NumType: case ByteType: { - binding_t *b = get_binding(env, CORD_to_const_char_star(type_to_cord(t))); + binding_t *b = get_binding(env, Text$as_c_string(type_to_text(t))); assert(b); return Match(b->type, TypeInfoType)->env; } @@ -784,7 +783,7 @@ PUREFUNC binding_t *get_metamethod_binding(env_t *env, ast_e tag, ast_t *lhs, as return is_valid_call(env, fn->args, args, true) ? b : NULL; } -void set_binding(env_t *env, const char *name, type_t *type, CORD code) +void set_binding(env_t *env, const char *name, type_t *type, Text_t code) { assert(name); Table$str_set(env->locals, name, new(binding_t, .type=type, .code=code)); diff --git a/src/environment.h b/src/environment.h index 85287d02..2d4e822c 100644 --- a/src/environment.h +++ b/src/environment.h @@ -2,8 +2,7 @@ // Compilation environments -#include <gc/cord.h> - +#include "stdlib/datatypes.h" #include "stdlib/print.h" #include "stdlib/stacktrace.h" #include "stdlib/stdlib.h" @@ -11,10 +10,10 @@ #include "types.h" typedef struct { - CORD local_typedefs; - CORD staticdefs; - CORD lambdas; - CORD variable_initializers; + Text_t local_typedefs; + Text_t staticdefs; + Text_t lambdas; + Text_t variable_initializers; } compilation_unit_t; typedef struct deferral_s { @@ -28,7 +27,7 @@ typedef struct loop_ctx_s { const char *loop_name; ast_list_t *loop_vars; deferral_t *deferred; - CORD skip_label, stop_label; + Text_t skip_label, stop_label; } loop_ctx_t; typedef struct namespace_s { @@ -43,7 +42,7 @@ typedef struct env_s { // - Resolved path for local imports (so that `use ./foo.tm` is the same as `use ./baz/../foo.tm`) // - Raw 'use' string for module imports namespace_t *namespace; - const char *id_suffix; + Text_t id_suffix; Table_t *imports; compilation_unit_t *code; type_t *fn_ret; @@ -55,13 +54,13 @@ typedef struct env_s { typedef struct { type_t *type; - CORD code; + Text_t code; } binding_t; env_t *global_env(bool source_mapping); env_t *load_module_env(env_t *env, ast_t *ast); -CORD namespace_name(env_t *env, namespace_t *ns, CORD name); -CORD get_id_suffix(const char *filename); +Text_t namespace_name(env_t *env, namespace_t *ns, Text_t name); +Text_t get_id_suffix(const char *filename); env_t *get_namespace_by_type(env_t *env, type_t *t); env_t *fresh_scope(env_t *env); env_t *for_scope(env_t *env, ast_t *ast); @@ -87,7 +86,7 @@ env_t *namespace_env(env_t *env, const char *namespace_name); binding_t *get_binding(env_t *env, const char *name); binding_t *get_constructor(env_t *env, type_t *t, arg_ast_t *args); PUREFUNC binding_t *get_metamethod_binding(env_t *env, ast_e tag, ast_t *lhs, ast_t *rhs, type_t *ret); -void set_binding(env_t *env, const char *name, type_t *type, CORD code); +void set_binding(env_t *env, const char *name, type_t *type, Text_t code); binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name); #define code_err(ast, ...) compiler_err((ast)->file, (ast)->start, (ast)->end, __VA_ARGS__) extern type_t *TEXT_TYPE; diff --git a/src/parse.c b/src/parse.c index e2f267c1..181aae58 100644 --- a/src/parse.c +++ b/src/parse.c @@ -20,7 +20,6 @@ #include <signal.h> #include "ast.h" -#include "cordhelpers.h" #include "stdlib/integers.h" #include "stdlib/paths.h" #include "stdlib/print.h" @@ -1212,17 +1211,25 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open int64_t starting_indent = get_indent(ctx, pos); int64_t string_indent = starting_indent + SPACES_PER_INDENT; ast_list_t *chunks = NULL; - CORD chunk = CORD_EMPTY; + Text_t chunk = EMPTY_TEXT; const char *chunk_start = pos; int depth = 1; bool leading_newline = false; - for (; pos < ctx->file->text + ctx->file->len && depth > 0; ) { + int64_t plain_span_len = 0; +#define FLUSH_PLAIN_SPAN() do { \ + if (plain_span_len > 0) { \ + chunk = Texts(chunk, Text$from_strn(pos - plain_span_len, (size_t)plain_span_len)); \ + plain_span_len = 0; \ + } } while (0) + for (const char *end = ctx->file->text + ctx->file->len; pos < end && depth > 0; ) { + const char *after_indentation = pos; if (*pos == open_interp) { // Interpolation + FLUSH_PLAIN_SPAN(); const char *interp_start = pos; - if (chunk) { - ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk); + if (chunk.length > 0) { + ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text=chunk); chunks = new(ast_list_t, .ast=literal, .next=chunks); - chunk = CORD_EMPTY; + chunk = EMPTY_TEXT; } ++pos; ast_t *interp; @@ -1232,13 +1239,14 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open chunks = new(ast_list_t, .ast=interp, .next=chunks); chunk_start = pos; } else if (allow_escapes && *pos == '\\') { + FLUSH_PLAIN_SPAN(); const char *c = unescape(ctx, &pos); - chunk = CORD_cat(chunk, c); + chunk = Texts(chunk, Text$from_str(c)); } else if (!leading_newline && *pos == open_quote && closing[(int)open_quote]) { // Nested pair begin if (get_indent(ctx, pos) == starting_indent) { ++depth; } - chunk = CORD_cat_char(chunk, *pos); + plain_span_len += 1; ++pos; } else if (!leading_newline && *pos == close_quote) { // Nested pair end if (get_indent(ctx, pos) == starting_indent) { @@ -1246,15 +1254,19 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open if (depth == 0) break; } - chunk = CORD_cat_char(chunk, *pos); + plain_span_len += 1; ++pos; - } else if (newline_with_indentation(&pos, string_indent)) { // Newline - if (!leading_newline && !(chunk || chunks)) { + } else if (newline_with_indentation(&after_indentation, string_indent)) { // Newline + FLUSH_PLAIN_SPAN(); + pos = after_indentation; + if (!leading_newline && !(chunk.length > 0 || chunks)) { leading_newline = true; } else { - chunk = CORD_cat_char(chunk, '\n'); + chunk = Texts(chunk, Text("\n")); } - } else if (newline_with_indentation(&pos, starting_indent)) { // Line continuation (..) + } else if (newline_with_indentation(&after_indentation, starting_indent)) { // Line continuation (..) + FLUSH_PLAIN_SPAN(); + pos = after_indentation; if (*pos == close_quote) { break; } else if (some_of(&pos, ".") >= 2) { @@ -1264,15 +1276,22 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open parser_err(ctx, pos, eol(pos), "This multi-line string should be either indented or have '..' at the front"); } } else { // Plain character - chunk = CORD_cat_char(chunk, *pos); - ++pos; + ucs4_t codepoint; + const char *next = (const char*)u8_next(&codepoint, (const uint8_t*)pos); + plain_span_len += (int64_t)(next - pos); + if (next == NULL) + break; + pos = next; } } - if (chunk) { - ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk); + FLUSH_PLAIN_SPAN(); +#undef FLUSH_PLAIN_SPAN + + if (chunk.length > 0) { + ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text=chunk); chunks = new(ast_list_t, .ast=literal, .next=chunks); - chunk = NULL; + chunk = EMPTY_TEXT; } REVERSE_LIST(chunks); @@ -2295,11 +2314,11 @@ PARSER(parse_inline_c) { spaces(&pos); if (!match(&pos, "(")) parser_err(ctx, start, pos, "I expected a '(' here"); - chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, "({"), + chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, Text("({")), .next=_parse_text_helper(ctx, &pos, '(', ')', '@', false)); if (type) { REVERSE_LIST(chunks); - chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, "; })"), .next=chunks); + chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, Text("; })")), .next=chunks); REVERSE_LIST(chunks); } } else { diff --git a/src/stdlib/print.h b/src/stdlib/print.h index 5ef5b6ed..ce20152b 100644 --- a/src/stdlib/print.h +++ b/src/stdlib/print.h @@ -12,7 +12,6 @@ #include <assert.h> #include <ctype.h> #include <gc.h> -#include <gc/cord.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> diff --git a/src/stdlib/text.h b/src/stdlib/text.h index fc336612..642a74b6 100644 --- a/src/stdlib/text.h +++ b/src/stdlib/text.h @@ -8,6 +8,7 @@ #include "datatypes.h" #include "integers.h" +#include "mapmacro.h" #include "optionals.h" #include "types.h" #include "util.h" @@ -26,10 +27,20 @@ typedef struct { #define Text(str) ((Text_t){.length=sizeof(str)-1, .tag=TEXT_ASCII, .ascii="" str}) -//int Text$print(FILE *stream, Text_t t); +static inline Text_t Text_from_str_literal(const char *str) { + return (Text_t){.length=strlen(str), .tag=TEXT_ASCII, .ascii=str}; +} + +static inline Text_t Text_from_text(Text_t t) { + return t; +} + +#define convert_to_text(x) _Generic(x, Text_t: Text_from_text, char*: Text$from_str, const char*: Text$from_str)(x) + Text_t Text$_concat(int n, Text_t items[n]); #define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__})/sizeof(Text_t), (Text_t[]){__VA_ARGS__}) -#define Texts(...) Text$concat(__VA_ARGS__) +#define Texts(...) Text$concat(MAP_LIST(convert_to_text, __VA_ARGS__)) +// int Text$print(FILE *stream, Text_t t); Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int); Text_t Text$from(Text_t text, Int_t first); Text_t Text$to(Text_t text, Int_t last); diff --git a/src/structs.c b/src/structs.c index 88de7aac..3e51f81b 100644 --- a/src/structs.c +++ b/src/structs.c @@ -1,21 +1,20 @@ // Logic for compiling new struct types defined in code #include <ctype.h> -#include <gc/cord.h> #include <gc.h> #include <stdio.h> #include "ast.h" #include "stdlib/text.h" #include "compile.h" -#include "cordhelpers.h" #include "environment.h" #include "typecheck.h" #include "stdlib/util.h" -CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque) +Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque) { - CORD typeinfo_name = namespace_name(env, env->namespace, CORD_cat(name, "$$info")); - CORD type_code = Match(t, StructType)->external ? name : CORD_all("struct ", namespace_name(env, env->namespace, CORD_cat(name, "$$struct"))); + Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(name, "$$info")); + Text_t type_code = Match(t, StructType)->external ? + Text$from_str(name) : Texts("struct ", namespace_name(env, env->namespace, Texts(name, "$$struct"))); int num_fields = 0; for (arg_ast_t *f = fields; f; f = f->next) @@ -25,32 +24,33 @@ CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t short_name = strrchr(short_name, '$') + 1; const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods"; - CORD typeinfo = CORD_all("public const TypeInfo_t ", typeinfo_name, + Text_t typeinfo = Texts("public const TypeInfo_t ", typeinfo_name, " = {.size=sizeof(", type_code, "), .align=__alignof__(", type_code, "), " ".metamethods=", metamethods, ", " ".tag=StructInfo, .StructInfo.name=\"", short_name, "\"", - is_secret ? ", .StructInfo.is_secret=true" : CORD_EMPTY, - is_opaque ? ", .StructInfo.is_opaque=true" : CORD_EMPTY, + is_secret ? Text(", .StructInfo.is_secret=true") : EMPTY_TEXT, + is_opaque ? Text(", .StructInfo.is_opaque=true") : EMPTY_TEXT, ", .StructInfo.num_fields=", String(num_fields)); if (fields) { - typeinfo = CORD_all(typeinfo, ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){"); + typeinfo = Texts(typeinfo, ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){"); for (arg_ast_t *f = fields; f; f = f->next) { type_t *field_type = get_arg_ast_type(env, f); - typeinfo = CORD_all(typeinfo, "{\"", f->name, "\", ", compile_type_info(field_type), "}"); - if (f->next) typeinfo = CORD_all(typeinfo, ", "); + typeinfo = Texts(typeinfo, "{\"", f->name, "\", ", compile_type_info(field_type), "}"); + if (f->next) typeinfo = Texts(typeinfo, ", "); } - typeinfo = CORD_all(typeinfo, "}"); + typeinfo = Texts(typeinfo, "}"); } - return CORD_all(typeinfo, "};\n"); + return Texts(typeinfo, "};\n"); } -CORD compile_struct_header(env_t *env, ast_t *ast) +Text_t compile_struct_header(env_t *env, ast_t *ast) { DeclareMatch(def, ast, StructDef); - CORD typeinfo_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$info")); - CORD type_code = def->external ? def->name : CORD_all("struct ", namespace_name(env, env->namespace, CORD_all(def->name, "$$struct"))); + Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(def->name, "$$info")); + Text_t type_code = def->external ? Text$from_str(def->name) + : Texts("struct ", namespace_name(env, env->namespace, Texts(def->name, "$$struct"))); - CORD fields = CORD_EMPTY; + Text_t fields = EMPTY_TEXT; for (arg_ast_t *field = def->fields; field; field = field->next) { type_t *field_t = get_arg_ast_type(env, field); type_t *check_for_opaque = non_optional(field_t); @@ -60,18 +60,19 @@ CORD compile_struct_header(env_t *env, ast_t *ast) else if (field->value) code_err(field->value, "This is an opaque type, so it can't be used as a struct field type"); } - fields = CORD_all(fields, compile_declaration(field_t, field->name), field_t->tag == BoolType ? ":1" : CORD_EMPTY, ";\n"); + fields = Texts(fields, compile_declaration(field_t, Text$from_str(field->name)), + field_t->tag == BoolType ? Text(":1") : EMPTY_TEXT, ";\n"); } - CORD struct_code = def->external ? CORD_EMPTY : CORD_all(type_code, " {\n", fields, "};\n"); + Text_t struct_code = def->external ? EMPTY_TEXT : Texts(type_code, " {\n", fields, "};\n"); type_t *t = Table$str_get(*env->types, def->name); - CORD unpadded_size = def->opaque ? CORD_all("sizeof(", type_code, ")") : String((int64_t)unpadded_struct_size(t)); - CORD typeinfo_code = CORD_all("extern const TypeInfo_t ", typeinfo_name, ";\n"); - CORD optional_code = CORD_EMPTY; + Text_t unpadded_size = def->opaque ? Texts("sizeof(", type_code, ")") : Text$from_str(String((int64_t)unpadded_struct_size(t))); + Text_t typeinfo_code = Texts("extern const TypeInfo_t ", typeinfo_name, ";\n"); + Text_t optional_code = EMPTY_TEXT; if (!def->opaque) { - optional_code = CORD_all("DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", unpadded_size, ", ", - namespace_name(env, env->namespace, CORD_all("$Optional", def->name, "$$type")), ");\n"); + optional_code = Texts("DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", unpadded_size, ", ", + namespace_name(env, env->namespace, Texts("$Optional", def->name, "$$type")), ");\n"); } - return CORD_all(struct_code, optional_code, typeinfo_code); + return Texts(struct_code, optional_code, typeinfo_code); } // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/structs.h b/src/structs.h index 328972cd..d5337626 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2,12 +2,10 @@ // Compilation of user-defined structs -#include <gc/cord.h> - #include "ast.h" #include "environment.h" -CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque); -CORD compile_struct_header(env_t *env, ast_t *ast); +Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque); +Text_t compile_struct_header(env_t *env, ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -2,7 +2,6 @@ #include <ctype.h> #include <errno.h> #include <gc.h> -#include <gc/cord.h> #include <libgen.h> #include <spawn.h> #include <stdio.h> @@ -15,7 +14,6 @@ #include "ast.h" #include "compile.h" -#include "cordhelpers.h" #include "modules.h" #include "parse.h" #include "stdlib/bools.h" @@ -777,12 +775,12 @@ void transpile_header(env_t *base_env, Path_t path) env_t *module_env = load_module_env(base_env, ast); - CORD h_code = compile_file_header(module_env, Path$resolved(h_filename, Path$from_str(".")), ast); + Text_t h_code = compile_file_header(module_env, Path$resolved(h_filename, Path$from_str(".")), ast); FILE *header = fopen(Path$as_c_string(h_filename), "w"); if (!header) print_err("Failed to open header file: ", h_filename); - CORD_put(h_code, header); + Text$print(header, h_code); if (fclose(header) == -1) print_err("Failed to write header file: ", h_filename); @@ -802,13 +800,13 @@ void transpile_code(env_t *base_env, Path_t path) env_t *module_env = load_module_env(base_env, ast); - CORD c_code = compile_file(module_env, ast); + Text_t c_code = compile_file(module_env, ast); FILE *c_file = fopen(Path$as_c_string(c_filename), "w"); if (!c_file) print_err("Failed to write C file: ", c_filename); - CORD_put(c_code, c_file); + Text$print(c_file, c_code); const char *version = get_version(Path$parent(path)); binding_t *main_binding = get_binding(module_env, "main"); @@ -819,15 +817,15 @@ void transpile_code(env_t *base_env, Path_t path) "The main() function in this file has a return type of ", type_to_str(ret), ", but it should not have any return value!"); - CORD_put(CORD_all( + Text$print(c_file, Texts( "int parse_and_run$$", main_binding->code, "(int argc, char *argv[]) {\n", - module_env->do_source_mapping ? "#line 1\n" : CORD_EMPTY, + module_env->do_source_mapping ? Text("#line 1\n") : EMPTY_TEXT, "tomo_init();\n", - namespace_name(module_env, module_env->namespace, "$initialize"), "();\n" + namespace_name(module_env, module_env->namespace, Text("$initialize")), "();\n" "\n", compile_cli_arg_call(module_env, main_binding->code, main_binding->type, version), "return 0;\n" - "}\n"), c_file); + "}\n")); } if (fclose(c_file) == -1) @@ -878,7 +876,7 @@ Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t FILE *runner = run_cmd(cc, " ", cflags, " -O", optimization, " ", ldflags, " ", ldlibs, " ", list_text(extra_ldlibs), " ", paths_str(object_files), " -x c - -o ", exe_path); - CORD program = CORD_all( + Text_t program = Texts( "extern int parse_and_run$$", main_binding->code, "(int argc, char *argv[]);\n" "__attribute__ ((noinline))\n" "int main(int argc, char *argv[]) {\n" @@ -888,11 +886,11 @@ Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t if (show_codegen.length > 0) { FILE *out = run_cmd(show_codegen); - CORD_put(program, out); + Text$print(out, program); pclose(out); } - CORD_put(program, runner); + Text$print(runner, program); int status = pclose(runner); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) exit(EXIT_FAILURE); diff --git a/src/typecheck.c b/src/typecheck.c index 6fdfb1d8..d4ff0e7d 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -9,7 +9,6 @@ #include <sys/stat.h> #include "ast.h" -#include "cordhelpers.h" #include "environment.h" #include "modules.h" #include "parse.h" @@ -235,7 +234,7 @@ void prebind_statement(env_t *env, ast_t *statement) type_t *type = Type(StructType, .name=def->name, .opaque=true, .external=def->external, .env=ns_env); // placeholder Table$str_set(env->types, def->name, type); set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env), - namespace_name(env, env->namespace, CORD_all(def->name, "$$info"))); + namespace_name(env, env->namespace, Texts(def->name, "$$info"))); for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) prebind_statement(ns_env, stmt->ast); break; @@ -249,7 +248,7 @@ void prebind_statement(env_t *env, ast_t *statement) type_t *type = Type(EnumType, .name=def->name, .opaque=true, .env=ns_env); // placeholder Table$str_set(env->types, def->name, type); set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env), - namespace_name(env, env->namespace, CORD_all(def->name, "$$info"))); + namespace_name(env, env->namespace, Texts(def->name, "$$info"))); for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) prebind_statement(ns_env, stmt->ast); break; @@ -263,7 +262,7 @@ void prebind_statement(env_t *env, ast_t *statement) type_t *type = Type(TextType, .lang=def->name, .env=ns_env); Table$str_set(env->types, def->name, type); set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env), - namespace_name(env, env->namespace, CORD_all(def->name, "$$info"))); + namespace_name(env, env->namespace, Texts(def->name, "$$info"))); for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) prebind_statement(ns_env, stmt->ast); break; @@ -319,11 +318,11 @@ void bind_statement(env_t *env, ast_t *statement) code_err(statement, "I couldn't figure out the type of this value"); if (type->tag == FunctionType) type = Type(ClosureType, type); - CORD code; + Text_t code; if (name[0] != '_' && (env->namespace || decl->top_level)) - code = namespace_name(env, env->namespace, name); + code = namespace_name(env, env->namespace, Text$from_str(name)); else - code = CORD_all("_$", name); + code = Texts("_$", name); set_binding(env, name, type, code); break; } @@ -331,7 +330,7 @@ void bind_statement(env_t *env, ast_t *statement) DeclareMatch(def, statement, FunctionDef); const char *name = Match(def->name, Var)->name; type_t *type = get_function_def_type(env, statement); - set_binding(env, name, type, namespace_name(env, env->namespace, name)); + set_binding(env, name, type, namespace_name(env, env->namespace, Text$from_str(name))); break; } case ConvertDef: { @@ -341,8 +340,8 @@ void bind_statement(env_t *env, ast_t *statement) if (!name) code_err(statement, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t)); - CORD code = namespace_name(env, env->namespace, - CORD_all(name, "$", String(get_line_number(statement->file, statement->start)))); + Text_t code = namespace_name(env, env->namespace, + Texts(name, "$", String(get_line_number(statement->file, statement->start)))); binding_t binding = {.type=type, .code=code}; env_t *type_ns = get_namespace_by_type(env, ret_t); List$insert(&type_ns->namespace->constructors, &binding, I(0), sizeof(binding)); @@ -438,13 +437,13 @@ void bind_statement(env_t *env, ast_t *statement) for (tag_t *tag = tags; tag; tag = tag->next) { if (Match(tag->type, StructType)->fields) { // Constructor: type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type); - set_binding(ns_env, tag->name, constructor_t, namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name))); + set_binding(ns_env, tag->name, constructor_t, namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name))); } else if (has_any_tags_with_fields) { // Empty singleton value: - CORD code = CORD_all("((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), "){", - namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)), "})"); + Text_t code = Texts("((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), "){", + namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)), "})"); set_binding(ns_env, tag->name, type, code); } else { - CORD code = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)); + Text_t code = namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)); set_binding(ns_env, tag->name, type, code); } Table$str_set(env->types, String(def->name, "$", tag->name), tag->type); @@ -462,7 +461,7 @@ void bind_statement(env_t *env, ast_t *statement) Table$str_set(env->types, def->name, type); set_binding(ns_env, "from_text", NewFunctionType(type, {.name="text", .type=TEXT_TYPE}), - CORD_all("(", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), ")")); + Texts("(", namespace_name(env, env->namespace, Texts(def->name, "$$type")), ")")); for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) bind_statement(ns_env, stmt->ast); @@ -520,7 +519,7 @@ void bind_statement(env_t *env, ast_t *statement) if (var) { type_t *type = get_type(env, statement); assert(type); - set_binding(env, Match(var, Var)->name, type, CORD_EMPTY); + set_binding(env, Match(var, Var)->name, type, EMPTY_TEXT); } break; } @@ -529,7 +528,7 @@ void bind_statement(env_t *env, ast_t *statement) type_t *t = parse_type_ast(env, ext->type); if (t->tag == ClosureType) t = Match(t, ClosureType)->fn; - set_binding(env, ext->name, t, ext->name); + set_binding(env, ext->name, t, Text$from_str(ext->name)); break; } default: break; @@ -545,7 +544,7 @@ type_t *get_function_def_type(env_t *env, ast_t *ast) for (arg_ast_t *arg = arg_asts; arg; arg = arg->next) { type_t *t = arg->type ? parse_type_ast(env, arg->type) : get_type(env, arg->value); args = new(arg_t, .name=arg->name, .type=t, .default_val=arg->value, .next=args); - set_binding(scope, arg->name, t, CORD_EMPTY); + set_binding(scope, arg->name, t, EMPTY_TEXT); } REVERSE_LIST(args); @@ -593,7 +592,7 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) if (fn->args && !fn->args->next && tag_struct->fields && tag_struct->fields->next) { if (fn->args->value->tag != Var) code_err(fn->args->value, "I expected a variable here"); - set_binding(scope, Match(fn->args->value, Var)->name, tag_type, CORD_EMPTY); + set_binding(scope, Match(fn->args->value, Var)->name, tag_type, EMPTY_TEXT); return scope; } @@ -606,7 +605,7 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) if (var->value->tag != Var) code_err(var->value, "I expected this to be a plain variable so I could bind it to a value"); if (!streq(Match(var->value, Var)->name, "_")) - set_binding(scope, Match(var->value, Var)->name, field->type, CORD_EMPTY); + set_binding(scope, Match(var->value, Var)->name, field->type, EMPTY_TEXT); field = field->next; } return scope; @@ -1322,7 +1321,7 @@ type_t *get_type(env_t *env, ast_t *ast) code_err(reduction->iter, "I don't know how to do a reduction over ", type_to_str(iter_t), " values"); if (reduction->key && !(reduction->op == Min || reduction->op == Max)) { env_t *item_scope = fresh_scope(env); - set_binding(item_scope, "$", iterated, CORD_EMPTY); + set_binding(item_scope, "$", iterated, EMPTY_TEXT); iterated = get_type(item_scope, reduction->key); } return iterated->tag == OptionalType ? iterated : Type(OptionalType, .type=iterated); @@ -1347,7 +1346,7 @@ type_t *get_type(env_t *env, ast_t *ast) for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) { type_t *t = get_arg_ast_type(env, arg); args = new(arg_t, .name=arg->name, .type=t, .next=args); - set_binding(scope, arg->name, t, CORD_EMPTY); + set_binding(scope, arg->name, t, EMPTY_TEXT); } REVERSE_LIST(args); @@ -1395,16 +1394,16 @@ type_t *get_type(env_t *env, ast_t *ast) truthy_scope = fresh_scope(env); if (condition_type->tag == OptionalType) set_binding(truthy_scope, varname, - Match(condition_type, OptionalType)->type, CORD_EMPTY); + Match(condition_type, OptionalType)->type, EMPTY_TEXT); else - set_binding(truthy_scope, varname, condition_type, CORD_EMPTY); + set_binding(truthy_scope, varname, condition_type, EMPTY_TEXT); } else if (if_->condition->tag == Var) { type_t *condition_type = get_type(env, if_->condition); if (condition_type->tag == OptionalType) { truthy_scope = fresh_scope(env); const char *varname = Match(if_->condition, Var)->name; set_binding(truthy_scope, varname, - Match(condition_type, OptionalType)->type, CORD_EMPTY); + Match(condition_type, OptionalType)->type, EMPTY_TEXT); } } @@ -1454,7 +1453,7 @@ type_t *get_type(env_t *env, ast_t *ast) else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum"); - CORD valid_tags = CORD_EMPTY; + Text_t valid_tags = EMPTY_TEXT; for (match_t *m = matches; m; m = m->next) { if (streq(m->tag->name, tag_name)) { if (m->handled) @@ -1462,12 +1461,12 @@ type_t *get_type(env_t *env, ast_t *ast) m->handled = true; goto found_matching_tag; } - if (valid_tags) valid_tags = CORD_cat(valid_tags, ", "); - valid_tags = CORD_cat(valid_tags, m->tag->name); + if (valid_tags.length > 0) valid_tags = Texts(valid_tags, ", "); + valid_tags = Texts(valid_tags, m->tag->name); } code_err(clause->pattern, "There is no tag '", tag_name, - "' for the type ", type_to_str(subject_t), " (valid tags: ", CORD_to_char_star(valid_tags), ")"); + "' for the type ", type_to_str(subject_t), " (valid tags: ", valid_tags, ")"); found_matching_tag:; } @@ -1502,13 +1501,13 @@ type_t *get_type(env_t *env, ast_t *ast) " value (based on earlier clauses), but it actually has a ", type_to_str(else_t), " value."); return merged; } else { - CORD unhandled = CORD_EMPTY; + Text_t unhandled = EMPTY_TEXT; for (match_t *m = matches; m; m = m->next) { if (!m->handled) - unhandled = unhandled ? CORD_all(unhandled, ", ", m->tag->name) : m->tag->name; + unhandled = unhandled.length > 0 ? Texts(unhandled, ", ", m->tag->name) : Text$from_str(m->tag->name); } - if (unhandled) - code_err(ast, "This 'when' statement doesn't handle the tags: ", CORD_to_const_char_star(unhandled)); + if (unhandled.length > 0) + code_err(ast, "This 'when' statement doesn't handle the tags: ", unhandled); return overall_t; } } @@ -1677,19 +1676,13 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast) return is_constant(env, text->children->ast); } case TextLiteral: { - CORD literal = Match(ast, TextLiteral)->cord; - CORD_pos i; -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - CORD_FOR(i, literal) { - if (!isascii(CORD_pos_fetch(i))) - return false; // Non-ASCII requires grapheme logic, not constant + Text_t literal = Match(ast, TextLiteral)->text; + TextIter_t state = NEW_TEXT_ITER_STATE(literal); + for (int64_t i = 0; i < literal.length; i++) { + int32_t g = Text$get_grapheme_fast(&state, i); + if (g < 0 || g > 127 || !isascii(g)) + return false; } -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif return true; // Literal ASCII string, OK } case Not: return is_constant(env, Match(ast, Not)->value); diff --git a/src/types.c b/src/types.c index 1a2405d4..f2dc5ddd 100644 --- a/src/types.c +++ b/src/types.c @@ -1,102 +1,101 @@ // Logic for handling type_t types -#include <gc/cord.h> #include <limits.h> #include <math.h> #include <signal.h> #include <stdint.h> #include <sys/param.h> -#include "cordhelpers.h" #include "environment.h" #include "stdlib/integers.h" #include "stdlib/print.h" #include "stdlib/tables.h" +#include "stdlib/text.h" #include "stdlib/util.h" #include "types.h" -CORD type_to_cord(type_t *t) { +Text_t type_to_text(type_t *t) { if (!t) - return "(Unknown type)"; + return Text("(Unknown type)"); switch (t->tag) { - case UnknownType: return "???"; - case AbortType: return "Abort"; + case UnknownType: return Text("???"); + case AbortType: return Text("Abort"); case ReturnType: { type_t *ret = Match(t, ReturnType)->ret; - return CORD_all("Return(", ret ? type_to_cord(ret) : "Void", ")"); - } - case VoidType: return "Void"; - case MemoryType: return "Memory"; - case BoolType: return "Bool"; - case ByteType: return "Byte"; - case CStringType: return "CString"; - case TextType: return Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text"; - case BigIntType: return "Int"; - case IntType: return String("Int", Match(t, IntType)->bits); - case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? "Num32" : "Num"; + return Texts("Return(", ret ? type_to_text(ret) : Text("Void"), ")"); + } + case VoidType: return Text("Void"); + case MemoryType: return Text("Memory"); + case BoolType: return Text("Bool"); + case ByteType: return Text("Byte"); + case CStringType: return Text("CString"); + case TextType: return Match(t, TextType)->lang ? Text$from_str(Match(t, TextType)->lang) : Text("Text"); + case BigIntType: return Text("Int"); + case IntType: return Texts("Int", String(Match(t, IntType)->bits)); + case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("Num32") : Text("Num"); case ListType: { DeclareMatch(list, t, ListType); - return CORD_all("[", type_to_cord(list->item_type), "]"); + return Texts("[", type_to_text(list->item_type), "]"); } case TableType: { DeclareMatch(table, t, TableType); - return CORD_all("{", type_to_cord(table->key_type), "=", type_to_cord(table->value_type), "}"); + return Texts("{", type_to_text(table->key_type), "=", type_to_text(table->value_type), "}"); } case SetType: { DeclareMatch(set, t, SetType); - return CORD_all("{", type_to_cord(set->item_type), "}"); + return Texts("{", type_to_text(set->item_type), "}"); } case ClosureType: { - return type_to_cord(Match(t, ClosureType)->fn); + return type_to_text(Match(t, ClosureType)->fn); } case FunctionType: { - CORD c = "func("; + Text_t c = Text("func("); DeclareMatch(fn, t, FunctionType); for (arg_t *arg = fn->args; arg; arg = arg->next) { - c = CORD_cat(c, type_to_cord(arg->type)); - if (arg->next) c = CORD_cat(c, ","); + c = Texts(c, type_to_text(arg->type)); + if (arg->next) c = Texts(c, ","); } if (fn->ret && fn->ret->tag != VoidType) - c = CORD_all(c, fn->args ? " -> " : "-> ", type_to_cord(fn->ret)); - c = CORD_all(c, ")"); + c = Texts(c, fn->args ? " -> " : "-> ", type_to_text(fn->ret)); + c = Texts(c, ")"); return c; } case StructType: { DeclareMatch(struct_, t, StructType); - return struct_->name; + return Text$from_str(struct_->name); } case PointerType: { DeclareMatch(ptr, t, PointerType); - CORD sigil = ptr->is_stack ? "&" : "@"; - return CORD_all(sigil, type_to_cord(ptr->pointed)); + Text_t sigil = ptr->is_stack ? Text("&") : Text("@"); + return Texts(sigil, type_to_text(ptr->pointed)); } case EnumType: { DeclareMatch(tagged, t, EnumType); - return tagged->name; + return Text$from_str(tagged->name); } case OptionalType: { type_t *opt = Match(t, OptionalType)->type; if (opt) - return CORD_all(type_to_cord(opt), "?"); + return Texts(type_to_text(opt), "?"); else - return "(Unknown optional type)"; + return Text("(Unknown optional type)"); } case TypeInfoType: { - return CORD_all("Type$info(", Match(t, TypeInfoType)->name, ")"); + return Texts("Type$info(", Match(t, TypeInfoType)->name, ")"); } case ModuleType: { - return CORD_all("Module(", Match(t, ModuleType)->name, ")"); + return Texts("Module(", Match(t, ModuleType)->name, ")"); } default: { raise(SIGABRT); - return String("Unknown type: ", t->tag); + return Texts("Unknown type: ", String(t->tag)); } } } const char *type_to_str(type_t *t) { - return CORD_to_const_char_star(type_to_cord(t)); + return Text$as_c_string(type_to_text(t)); } PUREFUNC const char *get_type_name(type_t *t) @@ -115,7 +114,7 @@ bool type_eq(type_t *a, type_t *b) if (!a && !b) return true; if (!a || !b) return false; if (a->tag != b->tag) return false; - return (CORD_cmp(type_to_cord(a), type_to_cord(b)) == 0); + return Text$equal_values(type_to_text(a), type_to_text(b)); } bool type_is_a(type_t *t, type_t *req) diff --git a/src/types.h b/src/types.h index 3b789560..be16cd5f 100644 --- a/src/types.h +++ b/src/types.h @@ -132,7 +132,7 @@ struct type_s { #define NUM_TYPE Type(NumType, .bits=TYPE_NBITS64) #define NewFunctionType(ret, ...) _make_function_type(ret, sizeof((arg_t[]){__VA_ARGS__})/sizeof(arg_t), (arg_t[]){__VA_ARGS__}) -CORD type_to_cord(type_t *t); +Text_t type_to_text(type_t *t); const char *type_to_str(type_t *t); const char *get_type_name(type_t *t); PUREFUNC bool type_eq(type_t *a, type_t *b); |
