aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/README.md1
-rw-r--r--src/ast.c100
-rw-r--r--src/ast.h7
-rw-r--r--src/compile.c2143
-rw-r--r--src/compile.h25
-rw-r--r--src/cordhelpers.c66
-rw-r--r--src/cordhelpers.h11
-rw-r--r--src/enums.c108
-rw-r--r--src/enums.h9
-rw-r--r--src/environment.c79
-rw-r--r--src/environment.h23
-rw-r--r--src/parse.c59
-rw-r--r--src/stdlib/print.h1
-rw-r--r--src/stdlib/text.h15
-rw-r--r--src/structs.c51
-rw-r--r--src/structs.h6
-rw-r--r--src/tomo.c24
-rw-r--r--src/typecheck.c83
-rw-r--r--src/types.c73
-rw-r--r--src/types.h2
20 files changed, 1407 insertions, 1479 deletions
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)
diff --git a/src/ast.c b/src/ast.c
index 5d8b2021..54df3109 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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)
diff --git a/src/ast.h b/src/ast.h
index 36ad0cc9..bda91fdd 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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
diff --git a/src/tomo.c b/src/tomo.c
index 3cfa718d..734abfc3 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -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);