aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast.c220
-rw-r--r--ast.h9
-rw-r--r--compile.c208
-rw-r--r--environment.c2
-rw-r--r--parse.c74
-rw-r--r--repl.c16
-rw-r--r--stdlib/text.c2
-rw-r--r--tomo.c11
-rw-r--r--typecheck.c10
-rw-r--r--types.c76
-rw-r--r--types.h3
11 files changed, 328 insertions, 303 deletions
diff --git a/ast.c b/ast.c
index 0593ccbf..b6ba6e00 100644
--- a/ast.c
+++ b/ast.c
@@ -1,15 +1,19 @@
// Some basic operations defined on AST nodes, mainly converting to
// strings for debugging.
-#include <gc/cord.h>
#include <printf.h>
#include <stdarg.h>
#include "ast.h"
+#include "stdlib/arrays.h"
#include "stdlib/datatypes.h"
#include "stdlib/integers.h"
+#include "stdlib/patterns.h"
#include "stdlib/tables.h"
#include "stdlib/text.h"
-#include "cordhelpers.h"
+#include "stdlib/util.h"
+
+#define ast_to_xml_ptr(ast) stack(ast_to_xml(ast))
+#define type_ast_to_xml_ptr(ast) stack(type_ast_to_xml(ast))
static const char *OP_NAMES[] = {
[BINOP_UNKNOWN]="unknown",
@@ -28,159 +32,171 @@ const char *binop_method_names[BINOP_XOR+1] = {
[BINOP_AND]="bit_and", [BINOP_OR]="bit_or", [BINOP_XOR]="bit_xor",
};
-static CORD ast_list_to_xml(ast_list_t *asts);
-static CORD arg_list_to_xml(arg_ast_t *args);
-static CORD when_clauses_to_xml(when_clause_t *clauses);
-static CORD tags_to_xml(tag_ast_t *tags);
-static CORD xml_escape(CORD text);
-static CORD optional_tagged(const char *tag, ast_t *ast);
-static CORD optional_tagged_type(const char *tag, type_ast_t *ast);
+static Text_t _ast_list_to_xml(ast_list_t *asts);
+#define ast_list_to_xml(ast) stack(_ast_list_to_xml(ast))
+static Text_t _arg_list_to_xml(arg_ast_t *args);
+#define arg_list_to_xml(ast) stack(_arg_list_to_xml(ast))
+static Text_t _when_clauses_to_xml(when_clause_t *clauses);
+#define when_clauses_to_xml(...) stack(_when_clauses_to_xml(__VA_ARGS__))
+static Text_t _tags_to_xml(tag_ast_t *tags);
+#define tags_to_xml(...) stack(_tags_to_xml(__VA_ARGS__))
+static Text_t _xml_escape(Text_t text);
+#define xml_escape(...) stack(_xml_escape(__VA_ARGS__))
+static Text_t _optional_tagged(const char *tag, ast_t *ast);
+#define optional_tagged(...) stack(_optional_tagged(__VA_ARGS__))
+static Text_t _optional_tagged_type(const char *tag, type_ast_t *ast);
+#define optional_tagged_type(...) stack(_optional_tagged_type(__VA_ARGS__))
-CORD xml_escape(CORD text)
+Text_t _xml_escape(Text_t text)
{
- text = CORD_replace(text, "&", "&amp;");
- text = CORD_replace(text, "<", "&lt;");
- text = CORD_replace(text, ">", "&gt;");
- return text;
+ typedef struct {Text_t k,v;} replacement_t;
+ Array_t replacements = TypedArray(
+ replacement_t,
+ {Text("&"), Text("&amp;")},
+ {Text("<"), Text("&lt;")},
+ {Text(">"), Text("&gt;")});
+ return Text$replace_all(text, Table$from_entries(replacements, Table$info(&Pattern$info, &Text$info)), Text(""), false);
}
-CORD ast_list_to_xml(ast_list_t *asts)
+Text_t _ast_list_to_xml(ast_list_t *asts)
{
- CORD c = CORD_EMPTY;
+ Text_t text = Text("");
for (; asts; asts = asts->next) {
- c = CORD_cat(c, ast_to_xml(asts->ast));
+ text = Texts(text, ast_to_xml(asts->ast));
}
- return c;
+ return text;
}
-CORD arg_list_to_xml(arg_ast_t *args) {
- CORD c = "<args>";
+Text_t _arg_list_to_xml(arg_ast_t *args) {
+ Text_t text = Text("<args>");
for (; args; args = args->next) {
- CORD arg_cord = args->name ? CORD_all("<arg name=\"", args->name, "\">") : "<arg>";
+ Text_t arg_text = args->name ? Text$format("<arg name=\"%s\">", args->name) : Text("<arg>");
if (args->type)
- arg_cord = CORD_all(arg_cord, "<type>", type_ast_to_xml(args->type), "</type>");
+ arg_text = Texts(arg_text, Text("<type>"), type_ast_to_xml(args->type), Text("</type>"));
if (args->value)
- arg_cord = CORD_all(arg_cord, "<value>", ast_to_xml(args->value), "</value>");
- c = CORD_all(c, arg_cord, "</arg>");
+ arg_text = Texts(text, Text("<value>"), ast_to_xml(args->value), Text("</value>"));
+ text = Texts(text, arg_text, Text("</arg>"));
}
- return CORD_cat(c, "</args>");
+ return Texts(text, Text("</args>"));
}
-CORD when_clauses_to_xml(when_clause_t *clauses) {
- CORD c = CORD_EMPTY;
+Text_t _when_clauses_to_xml(when_clause_t *clauses) {
+ Text_t text = Text("");
for (; clauses; clauses = clauses->next) {
- c = CORD_all(c, "<case tag=\"", ast_to_xml(clauses->tag_name), "\">", ast_list_to_xml(clauses->args), ast_to_xml(clauses->body), "</case>");
+ text = Texts(text, Text("<case tag=\""), ast_to_xml(clauses->tag_name), Text("\">"),
+ _ast_list_to_xml(clauses->args), ast_to_xml(clauses->body), Text("</case>"));
}
- return c;
+ return text;
}
-CORD tags_to_xml(tag_ast_t *tags) {
- CORD c = CORD_EMPTY;
+Text_t _tags_to_xml(tag_ast_t *tags) {
+ Text_t text = Text("");
for (; tags; tags = tags->next) {
- c = CORD_all(c, "<tag name=\"", tags->name, "\">", arg_list_to_xml(tags->fields), "</tag>");
+ text = Texts(text, Text$format("<tag name=\"%s\">%k</tag>", tags->name, arg_list_to_xml(tags->fields)));
}
- return c;
+ return text;
}
-CORD optional_tagged(const char *tag, ast_t *ast)
+Text_t _optional_tagged(const char *tag, ast_t *ast)
{
- return ast ? CORD_all("<", tag, ">", ast_to_xml(ast), "</", tag, ">") : CORD_EMPTY;
+ return ast ? Text$format("<%s>%k</%s>", tag, ast_to_xml_ptr(ast), tag) : Text("");
}
-CORD optional_tagged_type(const char *tag, type_ast_t *ast)
+Text_t _optional_tagged_type(const char *tag, type_ast_t *ast)
{
- return ast ? CORD_all("<", tag, ">", type_ast_to_xml(ast), "</", tag, ">") : CORD_EMPTY;
+ return ast ? Text$format("<%s>%k</%s>", tag, type_ast_to_xml_ptr(ast), tag) : Text("");
}
-CORD ast_to_xml(ast_t *ast)
+Text_t ast_to_xml(ast_t *ast)
{
- if (!ast) return CORD_EMPTY;
+ if (!ast) return Text("");
switch (ast->tag) {
-#define T(type, ...) case type: { auto data = ast->__data.type; (void)data; return CORD_asprintf(__VA_ARGS__); }
+#define T(type, ...) case type: { auto data = ast->__data.type; (void)data; return Text$format(__VA_ARGS__); }
T(Unknown, "<Unknown>")
- T(Null, "<Null>%r</Null>", type_ast_to_xml(data.type))
+ T(Null, "<Null>%k</Null>", stack(type_ast_to_xml(data.type)))
T(Bool, "<Bool value=\"%s\" />", data.b ? "yes" : "no")
T(Var, "<Var>%s</Var>", data.name)
T(Int, "<Int bits=\"%d\">%s</Int>", data.bits, data.str)
T(Num, "<Num bits=\"%d\">%g</Num>", data.bits, data.n)
- T(TextLiteral, "%r", xml_escape(data.cord))
- T(TextJoin, "<Text%r>%r</Text>", data.lang ? CORD_all(" lang=\"", data.lang, "\"") : CORD_EMPTY, ast_list_to_xml(data.children))
- T(Declare, "<Declare var=\"%r\">%r</Declare>", ast_to_xml(data.var), ast_to_xml(data.value))
- T(Assign, "<Assign><targets>%r</targets><values>%r</values></Assign>", ast_list_to_xml(data.targets), ast_list_to_xml(data.values))
- T(BinaryOp, "<BinaryOp op=\"%r\">%r %r</BinaryOp>", xml_escape(OP_NAMES[data.op]), ast_to_xml(data.lhs), ast_to_xml(data.rhs))
- T(UpdateAssign, "<UpdateAssign op=\"%r\">%r %r</UpdateAssign>", xml_escape(OP_NAMES[data.op]), ast_to_xml(data.lhs), ast_to_xml(data.rhs))
- T(Negative, "<Negative>%r</Negative>", ast_to_xml(data.value))
- T(Not, "<Not>%r</Not>", ast_to_xml(data.value))
- T(HeapAllocate, "<HeapAllocate>%r</HeapAllocate>", ast_to_xml(data.value))
- T(Min, "<Min>%r%r%r</Min>", ast_to_xml(data.lhs), ast_to_xml(data.rhs), optional_tagged("key", data.key))
- T(Max, "<Max>%r%r%r</Max>", ast_to_xml(data.lhs), ast_to_xml(data.rhs), optional_tagged("key", data.key))
- T(Array, "<Array>%r%r</Array>", optional_tagged_type("item-type", data.item_type), ast_list_to_xml(data.items))
- T(Set, "<Set>%r%r</Set>",
- optional_tagged_type("item-type", data.item_type),
- ast_list_to_xml(data.items))
- T(Table, "<Table>%r%r%r%r</Table>",
+ T(TextLiteral, "%k", xml_escape(data.text))
+ T(TextJoin, "<Text%k>%k</Text>", stack(data.lang ? Text$format(" lang=\"%s\"", data.lang) : Text("")), ast_list_to_xml(data.children))
+ T(Declare, "<Declare var=\"%k\">%k</Declare>", ast_to_xml_ptr(data.var), ast_to_xml_ptr(data.value))
+ T(Assign, "<Assign><targets>%k</targets><values>%k</values></Assign>", ast_list_to_xml(data.targets), ast_list_to_xml(data.values))
+ T(BinaryOp, "<BinaryOp op=\"%k\">%k %k</BinaryOp>", xml_escape(Text$from_str(OP_NAMES[data.op])),
+ ast_to_xml_ptr(data.lhs), ast_to_xml_ptr(data.rhs))
+ T(UpdateAssign, "<UpdateAssign op=\"%k\">%k %k</UpdateAssign>", xml_escape(Text$from_str(OP_NAMES[data.op])),
+ ast_to_xml_ptr(data.lhs), ast_to_xml_ptr(data.rhs))
+ T(Negative, "<Negative>%k</Negative>", ast_to_xml_ptr(data.value))
+ T(Not, "<Not>%k</Not>", ast_to_xml_ptr(data.value))
+ T(HeapAllocate, "<HeapAllocate>%k</HeapAllocate>", ast_to_xml_ptr(data.value))
+ T(Min, "<Min>%k%k%k</Min>", ast_to_xml_ptr(data.lhs), ast_to_xml_ptr(data.rhs), optional_tagged("key", data.key))
+ T(Max, "<Max>%k%k%k</Max>", ast_to_xml_ptr(data.lhs), ast_to_xml_ptr(data.rhs), optional_tagged("key", data.key))
+ T(Array, "<Array>%k%k</Array>", optional_tagged_type("item-type", data.item_type), ast_list_to_xml(data.items))
+ T(Set, "<Set>%k%k</Set>",
+ optional_tagged_type("item-type", data.item_type), ast_list_to_xml(data.items))
+ T(Table, "<Table>%k%k%k%k</Table>",
optional_tagged_type("key-type", data.key_type), optional_tagged_type("value-type", data.value_type),
ast_list_to_xml(data.entries), optional_tagged("fallback", data.fallback))
- T(TableEntry, "<TableEntry>%r%r</TableEntry>", ast_to_xml(data.key), ast_to_xml(data.value))
- T(Channel, "<Channel>%r%r</Channel>", type_ast_to_xml(data.item_type), optional_tagged("max-size", data.max_size))
- T(Comprehension, "<Comprehension>%r%r%r%r%r</Comprehension>", optional_tagged("expr", data.expr),
+ T(TableEntry, "<TableEntry>%k%k</TableEntry>", ast_to_xml_ptr(data.key), ast_to_xml_ptr(data.value))
+ T(Channel, "<Channel>%k%k</Channel>", type_ast_to_xml_ptr(data.item_type), optional_tagged("max-size", data.max_size))
+ T(Comprehension, "<Comprehension>%k%k%k%k%k</Comprehension>", optional_tagged("expr", data.expr),
ast_list_to_xml(data.vars), optional_tagged("iter", data.iter),
optional_tagged("filter", data.filter))
- T(FunctionDef, "<FunctionDef name=\"%r\">%r%r<body>%r</body></FunctionDef>", ast_to_xml(data.name),
- arg_list_to_xml(data.args), optional_tagged_type("return-type", data.ret_type), ast_to_xml(data.body))
- T(Lambda, "<Lambda>%r%r<body>%r</body></Lambda>)", arg_list_to_xml(data.args),
- optional_tagged_type("return-type", data.ret_type), ast_to_xml(data.body))
- T(FunctionCall, "<FunctionCall><function>%r</function>%r</FunctionCall>", ast_to_xml(data.fn), arg_list_to_xml(data.args))
- T(MethodCall, "<MethodCall><self>%r</self><method>%s</method>%r</MethodCall>", ast_to_xml(data.self), data.name, arg_list_to_xml(data.args))
- T(Block, "<Block>%r</Block>", ast_list_to_xml(data.statements))
- T(For, "<For>%r%r%r%r%r</For>", ast_list_to_xml(data.vars), optional_tagged("iterable", data.iter),
+ T(FunctionDef, "<FunctionDef name=\"%k\">%k%k<body>%k</body></FunctionDef>", ast_to_xml_ptr(data.name),
+ arg_list_to_xml(data.args), optional_tagged_type("return-type", data.ret_type), ast_to_xml_ptr(data.body))
+ T(Lambda, "<Lambda>%k%k<body>%k</body></Lambda>)", arg_list_to_xml(data.args),
+ optional_tagged_type("return-type", data.ret_type), ast_to_xml_ptr(data.body))
+ T(FunctionCall, "<FunctionCall><function>%k</function>%k</FunctionCall>", ast_to_xml_ptr(data.fn), arg_list_to_xml(data.args))
+ T(MethodCall, "<MethodCall><self>%k</self><method>%s</method>%k</MethodCall>", ast_to_xml_ptr(data.self), data.name, arg_list_to_xml(data.args))
+ T(Block, "<Block>%k</Block>", ast_list_to_xml(data.statements))
+ T(For, "<For>%k%k%k%k%k</For>", ast_list_to_xml(data.vars), optional_tagged("iterable", data.iter),
optional_tagged("body", data.body), optional_tagged("empty", data.empty))
- T(While, "<While>%r%r</While>", optional_tagged("condition", data.condition), optional_tagged("body", data.body))
- T(If, "<If>%r%r%r</If>", optional_tagged("condition", data.condition), optional_tagged("body", data.body), optional_tagged("else", data.else_body))
- T(When, "<When><subject>%r</subject>%r%r</When>", ast_to_xml(data.subject), when_clauses_to_xml(data.clauses), optional_tagged("else", data.else_body))
- T(Reduction, "<Reduction>%r%r%r</Reduction>", optional_tagged("iterable", data.iter),
+ T(While, "<While>%k%k</While>", optional_tagged("condition", data.condition), optional_tagged("body", data.body))
+ T(If, "<If>%k%k%k</If>", optional_tagged("condition", data.condition), optional_tagged("body", data.body), optional_tagged("else", data.else_body))
+ T(When, "<When><subject>%k</subject>%k%k</When>", ast_to_xml_ptr(data.subject), when_clauses_to_xml(data.clauses), optional_tagged("else", data.else_body))
+ T(Reduction, "<Reduction>%k%k%k</Reduction>", optional_tagged("iterable", data.iter),
optional_tagged("combination", data.combination), optional_tagged("fallback", data.fallback))
- T(Skip, "<Skip>%r</Skip>", data.target)
- T(Stop, "<Stop>%r</Stop>", data.target)
- T(PrintStatement, "<PrintStatement>%r</PrintStatement>", ast_list_to_xml(data.to_print))
+ T(Skip, "<Skip>%s</Skip>", data.target)
+ T(Stop, "<Stop>%s</Stop>", data.target)
+ T(PrintStatement, "<PrintStatement>%k</PrintStatement>", ast_list_to_xml(data.to_print))
T(Pass, "<Pass/>")
- T(Defer, "<Defer>%r<Defer/>", ast_to_xml(data.body))
- T(Return, "<Return>%r</Return>", ast_to_xml(data.value))
- T(Extern, "<Extern name=\"%s\">%r</Extern>", data.name, type_ast_to_xml(data.type))
- T(StructDef, "<StructDef name=\"%s\">%r<namespace>%r</namespace></StructDef>", data.name, arg_list_to_xml(data.fields), ast_to_xml(data.namespace))
- T(EnumDef, "<EnumDef name=\"%s\"><tags>%r</tags><namespace>%r</namespace></EnumDef>", data.name, tags_to_xml(data.tags), ast_to_xml(data.namespace))
- T(LangDef, "<LangDef name=\"%s\">%r</LangDef>", data.name, ast_to_xml(data.namespace))
- T(Index, "<Index>%r%r</Index>", optional_tagged("indexed", data.indexed), optional_tagged("index", data.index))
- T(FieldAccess, "<FieldAccess field=\"%s\">%r</FieldAccess>", data.field, ast_to_xml(data.fielded))
- T(Optional, "<Optional>%r</Optional>", ast_to_xml(data.value))
- T(NonOptional, "<NonOptional>%r</NonOptional>", ast_to_xml(data.value))
- T(DocTest, "<DocTest>%r<output>%r</output></DocTest>", optional_tagged("expression", data.expr), xml_escape(data.output))
- T(Use, "<Use>%r%r</Use>", optional_tagged("var", data.var), xml_escape(data.path))
- T(InlineCCode, "<InlineCode>%r</InlineCode>", xml_escape(data.code))
- default: return "???";
+ T(Defer, "<Defer>%k<Defer/>", ast_to_xml_ptr(data.body))
+ T(Return, "<Return>%k</Return>", ast_to_xml_ptr(data.value))
+ T(Extern, "<Extern name=\"%s\">%k</Extern>", data.name, type_ast_to_xml_ptr(data.type))
+ T(StructDef, "<StructDef name=\"%s\">%k<namespace>%k</namespace></StructDef>", data.name, arg_list_to_xml(data.fields), ast_to_xml_ptr(data.namespace))
+ T(EnumDef, "<EnumDef name=\"%s\"><tags>%k</tags><namespace>%k</namespace></EnumDef>", data.name, tags_to_xml(data.tags), ast_to_xml_ptr(data.namespace))
+ T(LangDef, "<LangDef name=\"%s\">%k</LangDef>", data.name, ast_to_xml_ptr(data.namespace))
+ T(Index, "<Index>%k%k</Index>", optional_tagged("indexed", data.indexed), optional_tagged("index", data.index))
+ T(FieldAccess, "<FieldAccess field=\"%s\">%k</FieldAccess>", data.field, ast_to_xml_ptr(data.fielded))
+ T(Optional, "<Optional>%k</Optional>", ast_to_xml_ptr(data.value))
+ T(NonOptional, "<NonOptional>%k</NonOptional>", ast_to_xml_ptr(data.value))
+ T(DocTest, "<DocTest>%k<output>%k</output></DocTest>", optional_tagged("expression", data.expr), xml_escape(Text$from_str(data.output)))
+ T(Use, "<Use>%k%k</Use>", optional_tagged("var", data.var), xml_escape(Text$from_str(data.path)))
+ T(InlineCCode, "<InlineCode>%k</InlineCode>", xml_escape(data.code))
+ default: return Text("???");
#undef T
}
}
-CORD type_ast_to_xml(type_ast_t *t)
+Text_t type_ast_to_xml(type_ast_t *t)
{
- if (!t) return "NULL";
+ if (!t) return Text("NULL");
switch (t->tag) {
-#define T(type, ...) case type: { auto data = t->__data.type; (void)data; return CORD_asprintf(__VA_ARGS__); }
+#define T(type, ...) case type: { auto data = t->__data.type; (void)data; return Text$format(__VA_ARGS__); }
T(UnknownTypeAST, "<UnknownType/>")
T(VarTypeAST, "%s", data.name)
- T(PointerTypeAST, "<PointerType is_view=\"%s\">%r</PointerType>",
- data.is_view ? "yes" : "no", type_ast_to_xml(data.pointed))
- T(ArrayTypeAST, "<ArrayType>%r</ArrayType>", type_ast_to_xml(data.item))
- T(SetTypeAST, "<TableType>%r</TableType>", type_ast_to_xml(data.item))
- T(ChannelTypeAST, "<ChannelType>%r</ChannelType>", type_ast_to_xml(data.item))
- T(TableTypeAST, "<TableType>%r %r</TableType>", type_ast_to_xml(data.key), type_ast_to_xml(data.value))
- T(FunctionTypeAST, "<FunctionType>%r %r</FunctionType>", arg_list_to_xml(data.args), type_ast_to_xml(data.ret))
- T(OptionalTypeAST, "<OptionalType>%r</OptionalType>", data.type)
+ T(PointerTypeAST, "<PointerType is_view=\"%s\">%k</PointerType>",
+ data.is_view ? "yes" : "no", type_ast_to_xml_ptr(data.pointed))
+ T(ArrayTypeAST, "<ArrayType>%k</ArrayType>", type_ast_to_xml_ptr(data.item))
+ T(SetTypeAST, "<TableType>%k</TableType>", type_ast_to_xml_ptr(data.item))
+ T(ChannelTypeAST, "<ChannelType>%k</ChannelType>", type_ast_to_xml_ptr(data.item))
+ T(TableTypeAST, "<TableType>%k %k</TableType>", type_ast_to_xml_ptr(data.key), type_ast_to_xml_ptr(data.value))
+ T(FunctionTypeAST, "<FunctionType>%k %k</FunctionType>", arg_list_to_xml(data.args), type_ast_to_xml_ptr(data.ret))
+ T(OptionalTypeAST, "<OptionalType>%k</OptionalType>", type_ast_to_xml_ptr(data.type))
#undef T
- default: return CORD_EMPTY;
+ default: return Text("");
}
}
@@ -191,7 +207,7 @@ int printf_ast(FILE *stream, const struct printf_info *info, const void *const a
if (info->alt)
return fprintf(stream, "%.*s", (int)(ast->end - ast->start), ast->start);
else
- return CORD_put(ast_to_xml(ast), stream);
+ return Text$print(stream, ast_to_xml(ast));
} else {
return fputs("(null)", stream);
}
diff --git a/ast.h b/ast.h
index fada01d4..737b73eb 100644
--- a/ast.h
+++ b/ast.h
@@ -3,7 +3,6 @@
// Logic defining ASTs (abstract syntax trees) to represent code
#include <err.h>
-#include <gc/cord.h>
#include <printf.h>
#include <stdbool.h>
#include <stdint.h>
@@ -172,7 +171,7 @@ struct ast_s {
enum { NBITS_UNSPECIFIED=0, NBITS32=32, NBITS64=64 } bits;
} Num;
struct {
- CORD cord;
+ Text_t text;
} TextLiteral;
struct {
const char *lang;
@@ -321,15 +320,15 @@ struct ast_s {
enum { USE_LOCAL, USE_MODULE, USE_SHARED_OBJECT, USE_HEADER, USE_C_CODE, USE_ASM } what;
} Use;
struct {
- CORD code;
+ Text_t code;
struct type_s *type;
type_ast_t *type_ast;
} InlineCCode;
} __data;
};
-CORD ast_to_xml(ast_t *ast);
-CORD type_ast_to_xml(type_ast_t *ast);
+Text_t ast_to_xml(ast_t *ast);
+Text_t type_ast_to_xml(type_ast_t *ast);
int printf_ast(FILE *stream, const struct printf_info *info, const void *const args[]);
PUREFUNC bool is_idempotent(ast_t *ast);
void visit_topologically(ast_list_t *ast, Closure_t fn);
diff --git a/compile.c b/compile.c
index 775c17df..cde052c6 100644
--- a/compile.c
+++ b/compile.c
@@ -19,6 +19,8 @@
#include "structs.h"
#include "typecheck.h"
+#define type_to_cord(t) ({ Text_t text = type_to_text(t); text.length > 0 ? Text$as_c_string(text) : CORD_EMPTY; })
+
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);
@@ -72,7 +74,7 @@ static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed)
}
if ((actual->tag == IntType || actual->tag == BigIntType) && needed->tag == NumType) {
- *code = CORD_all(type_to_cord(actual), "_to_", type_to_cord(needed), "(", *code, ")");
+ *code = CORD_all(Text$as_c_string(type_to_text(actual)), "_to_", Text$as_c_string(type_to_text(needed)), "(", *code, ")");
return true;
}
@@ -213,8 +215,8 @@ CORD compile_type(type_t *t)
case CStringType: return "char*";
case DateTimeType: return "DateTime_t";
case BigIntType: return "Int_t";
- case IntType: return CORD_asprintf("Int%ld_t", Match(t, IntType)->bits);
- case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits);
+ case IntType: return heap_strf("Int%ld_t", Match(t, IntType)->bits);
+ case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? "Num_t" : heap_strf("Num%ld_t", Match(t, NumType)->bits);
case TextType: {
auto text = Match(t, TextType);
if (!text->lang || streq(text->lang, "Text"))
@@ -313,11 +315,11 @@ static CORD compile_lvalue(env_t *env, ast_t *ast)
if (index->unchecked) {
return CORD_all("Array_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
- ", ", CORD_asprintf("%ld", type_size(item_type)), ")");
+ ", ", heap_strf("%ld", type_size(item_type)), ")");
} else {
return CORD_all("Array_lvalue(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
- ", ", CORD_asprintf("%ld", type_size(item_type)),
+ ", ", heap_strf("%ld", type_size(item_type)),
", ", heap_strf("%ld", ast->start - ast->file->text),
", ", heap_strf("%ld", ast->end - ast->file->text), ")");
}
@@ -503,7 +505,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
assert(promote(env, &val_code, t, Type(ClosureType, t)));
t = Type(ClosureType, t);
}
- return CORD_asprintf(
+ return heap_strf(
"%r;\n"
"test((%r = %r), %r, %r, %ld, %ld);\n",
compile_declaration(t, var),
@@ -527,7 +529,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (!promote(val_scope, &value, rhs_t, lhs_t))
code_err(assign->values->ast, "You cannot assign a %T value to a %T operand", rhs_t, lhs_t);
}
- return CORD_asprintf(
+ return heap_strf(
"test((%r), %r, %r, %ld, %ld);",
compile_assignment(env, assign->targets->ast, value),
compile_type_info(env, lhs_t),
@@ -558,7 +560,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
}
i = 1;
for (ast_list_t *target = assign->targets; target; target = target->next)
- code = CORD_all(code, compile_assignment(env, target->ast, CORD_asprintf("$%ld", i++)), ";\n");
+ code = CORD_all(code, compile_assignment(env, target->ast, heap_strf("$%ld", i++)), ";\n");
CORD_appendf(&code, "$1; }), %r, %r, %ld, %ld);",
compile_type_info(env, get_type(env, assign->targets->ast)),
@@ -569,7 +571,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
}
} else if (test->expr->tag == UpdateAssign) {
type_t *lhs_t = get_type(env, Match(test->expr, UpdateAssign)->lhs);
- return CORD_asprintf(
+ return heap_strf(
"test(({%r %r;}), %r, %r, %ld, %ld);",
compile_statement(env, test->expr),
compile_lvalue(env, Match(test->expr, UpdateAssign)->lhs),
@@ -578,13 +580,13 @@ CORD compile_statement(env_t *env, ast_t *ast)
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) {
- return CORD_asprintf(
+ return heap_strf(
"test(({%r NULL;}), NULL, NULL, %ld, %ld);",
compile_statement(env, test->expr),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else {
- return CORD_asprintf(
+ return heap_strf(
"test(%r, %r, %r, %ld, %ld);",
compile(env, test->expr),
compile_type_info(env, expr_t),
@@ -647,7 +649,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
}
i = 1;
for (ast_list_t *target = assign->targets; target; target = target->next) {
- code = CORD_all(code, compile_assignment(env, target->ast, CORD_asprintf("$%ld", i++)), ";\n");
+ code = CORD_all(code, compile_assignment(env, target->ast, heap_strf("$%ld", i++)), ";\n");
}
return CORD_cat(code, "\n}");
}
@@ -739,7 +741,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (lhs_t->tag == TextType) {
return CORD_all(lhs, " = Texts(", lhs, ", ", rhs, ");");
} else if (lhs_t->tag == ArrayType) {
- CORD padded_item_size = CORD_asprintf("%ld", type_size(Match(lhs_t, ArrayType)->item_type));
+ CORD padded_item_size = heap_strf("%ld", type_size(Match(lhs_t, ArrayType)->item_type));
if (promote(env, &rhs, rhs_t, Match(lhs_t, ArrayType)->item_type)) {
// arr ++= item
if (update->lhs->tag == Var)
@@ -834,7 +836,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (streq(Match(fndef->name, Var)->name, "main"))
body = CORD_all("$", env->namespace->name, "$$initialize();\n", body);
if (CORD_fetch(body, 0) != '{')
- body = CORD_asprintf("{\n%r\n}", body);
+ body = heap_strf("{\n%r\n}", body);
env->code->funcs = CORD_all(env->code->funcs, code, " ", body, "\n");
if (fndef->cache && fndef->args == NULL) { // no-args cache just uses a static var
@@ -865,7 +867,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
CORD pop_code = CORD_EMPTY;
if (fndef->cache->tag == Int && !cache_size.is_null && cache_size.i > 0) {
- pop_code = CORD_all("if (cache.entries.length > ", CORD_asprintf("%ld", cache_size.i),
+ pop_code = CORD_all("if (cache.entries.length > ", heap_strf("%ld", cache_size.i),
") Table$remove(&cache, cache.entries.data + cache.entries.stride*Int$random(I(0), I(cache.entries.length-1)), table_type);\n");
}
@@ -888,17 +890,17 @@ CORD compile_statement(env_t *env, ast_t *ast)
CORD text = CORD_all("func ", Match(fndef->name, Var)->name, "(");
for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) {
- text = CORD_cat(text, type_to_cord(get_arg_ast_type(env, arg)));
+ text = CORD_cat(text, Text$as_c_string(type_to_text(get_arg_ast_type(env, arg))));
if (arg->next) text = CORD_cat(text, ", ");
}
if (ret_t && ret_t->tag != VoidType)
- text = CORD_all(text, ")->", type_to_cord(ret_t));
+ text = CORD_all(text, ")->", Text$as_c_string(type_to_text(ret_t)));
else
text = CORD_all(text, ")");
env->code->function_naming = CORD_all(
env->code->function_naming,
- CORD_asprintf("register_function(%r, Text(\"%r [%s.tm:%ld]\"));\n",
+ heap_strf("register_function(%r, Text(\"%r [%s.tm:%ld]\"));\n",
name, text, file_base_name(ast->file->filename), get_line_number(ast->file, ast->start)));
return CORD_EMPTY;
}
@@ -969,7 +971,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (CORD_ncmp(entry->b->code, 0, "userdata->", 0, strlen("userdata->")) == 0) {
set_binding(defer_env, entry->name, entry->b);
} else {
- CORD defer_name = CORD_asprintf("defer$%d$%s", ++defer_id, entry->name);
+ CORD defer_name = heap_strf("defer$%d$%s", ++defer_id, entry->name);
code = CORD_all(
code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n");
set_binding(defer_env, entry->name, new(binding_t, .type=entry->b->type, .code=defer_name));
@@ -1425,9 +1427,9 @@ CORD compile_statement(env_t *env, ast_t *ast)
case InlineCCode: {
auto inline_code = Match(ast, InlineCCode);
if (inline_code->type)
- return CORD_all("({ ", inline_code->code, "; })");
+ return CORD_all("({ ", Text$as_c_string(inline_code->code), "; })");
else
- return inline_code->code;
+ return Text$as_c_string(inline_code->code);
}
case Use: {
auto use = Match(ast, Use);
@@ -1455,7 +1457,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
default:
if (!is_discardable(env, ast))
code_err(ast, "The %T result of this statement cannot be discarded", get_type(env, ast));
- return CORD_asprintf("(void)%r;", compile(env, ast));
+ return heap_strf("(void)%r;", compile(env, ast));
}
}
@@ -1464,33 +1466,33 @@ CORD compile_statement(env_t *env, ast_t *ast)
// if (!stmt)
// return stmt;
// int64_t line = get_line_number(ast->file, ast->start);
-// return CORD_asprintf("#line %ld\n%r", line, stmt);
+// return heap_strf("#line %ld\n%r", line, stmt);
// }
CORD expr_as_text(env_t *env, CORD expr, type_t *t, CORD color)
{
switch (t->tag) {
- case MemoryType: return CORD_asprintf("Memory$as_text(stack(%r), %r, &Memory$info)", expr, color);
+ case MemoryType: return heap_strf("Memory$as_text(stack(%r), %r, &Memory$info)", expr, color);
case BoolType:
// NOTE: this cannot use stack(), since bools may actually be bit fields:
- return CORD_asprintf("Bool$as_text((Bool_t[1]){%r}, %r, &Bool$info)", expr, color);
- case CStringType: return CORD_asprintf("CString$as_text(stack(%r), %r, &CString$info)", expr, color);
- case DateTimeType: return CORD_asprintf("DateTime$as_text(stack(%r), %r, &DateTime$info)", expr, color);
+ return heap_strf("Bool$as_text((Bool_t[1]){%r}, %r, &Bool$info)", expr, color);
+ case CStringType: return heap_strf("CString$as_text(stack(%r), %r, &CString$info)", expr, color);
+ case DateTimeType: return heap_strf("DateTime$as_text(stack(%r), %r, &DateTime$info)", expr, color);
case BigIntType: case IntType: case ByteType: case NumType: {
- CORD name = type_to_cord(t);
- return CORD_asprintf("%r$as_text(stack(%r), %r, &%r$info)", name, expr, color, name);
+ Text_t name = type_to_text(t);
+ return heap_strf("%k$as_text(stack(%r), %r, &%k$info)", &name, expr, color, &name);
}
case TextType: {
- return CORD_asprintf("Text$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- }
- case ArrayType: return CORD_asprintf("Array$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case SetType: return CORD_asprintf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case ChannelType: return CORD_asprintf("Channel$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case TableType: return CORD_asprintf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case FunctionType: case ClosureType: return CORD_asprintf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case PointerType: return CORD_asprintf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case OptionalType: return CORD_asprintf("Optional$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
- case StructType: case EnumType: return CORD_asprintf("generic_as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ return heap_strf("Text$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ }
+ case ArrayType: return heap_strf("Array$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case SetType: return heap_strf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case ChannelType: return heap_strf("Channel$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case TableType: return heap_strf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case FunctionType: case ClosureType: return heap_strf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case PointerType: return heap_strf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case OptionalType: return heap_strf("Optional$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
+ case StructType: case EnumType: return heap_strf("generic_as_text(stack(%r), %r, %r)", expr, color, compile_type_info(env, t));
default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for %T", t);
}
}
@@ -1592,19 +1594,19 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
switch (target_bits) {
case TYPE_IBITS64:
if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0)
- return CORD_asprintf("I64(%s)", Match(ast, Int)->str);
+ return heap_strf("I64(%s)", Match(ast, Int)->str);
break;
case TYPE_IBITS32:
if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0)
- return CORD_asprintf("I32(%s)", Match(ast, Int)->str);
+ return heap_strf("I32(%s)", Match(ast, Int)->str);
break;
case TYPE_IBITS16:
if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0)
- return CORD_asprintf("I16(%s)", Match(ast, Int)->str);
+ return heap_strf("I16(%s)", Match(ast, Int)->str);
break;
case TYPE_IBITS8:
if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0)
- return CORD_asprintf("I8(%s)", Match(ast, Int)->str);
+ return heap_strf("I8(%s)", Match(ast, Int)->str);
break;
default: break;
}
@@ -1630,7 +1632,7 @@ 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");
double n = Int_to_Num(int_val);
- value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
+ value = heap_strf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
? "N64(%.20g)" : "N32(%.10g)", n);
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
@@ -1659,7 +1661,7 @@ 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");
double n = Int_to_Num(int_val);
- value = CORD_asprintf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
+ value = heap_strf(Match(spec_arg->type, NumType)->bits == TYPE_NBITS64
? "N64(%.20g)" : "N32(%.10g)", n);
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
@@ -1879,7 +1881,7 @@ CORD compile(env_t *env, ast_t *ast)
case Bool: return Match(ast, Bool)->b ? "yes" : "no";
case DateTime: {
auto dt = Match(ast, DateTime)->dt;
- return CORD_asprintf("((DateTime_t){.tv_sec=%ld, .tv_usec=%ld})", dt.tv_sec, dt.tv_usec);
+ return heap_strf("((DateTime_t){.tv_sec=%ld, .tv_usec=%ld})", dt.tv_sec, dt.tv_usec);
}
case Var: {
binding_t *b = get_binding(env, Match(ast, Var)->name);
@@ -1899,31 +1901,31 @@ CORD compile(env_t *env, ast_t *ast)
switch (Match(ast, Int)->bits) {
case IBITS_UNSPECIFIED:
if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) {
- return CORD_asprintf("I_small(%s)", str);
+ return heap_strf("I_small(%s)", str);
} else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) {
- return CORD_asprintf("Int64_to_Int(%s)", str);
+ return heap_strf("Int64_to_Int(%s)", str);
} else {
- return CORD_asprintf("Int$from_str(\"%s\")", str);
+ return heap_strf("Int$from_str(\"%s\")", str);
}
case IBITS64:
if ((mpz_cmp_si(i, INT64_MAX) <= 0) && (mpz_cmp_si(i, INT64_MIN) >= 0))
- return CORD_asprintf("I64(%ldl)", mpz_get_si(i));
+ return heap_strf("I64(%ldl)", mpz_get_si(i));
code_err(ast, "This value cannot fit in a 64-bit integer");
case IBITS32:
if ((mpz_cmp_si(i, INT32_MAX) <= 0) && (mpz_cmp_si(i, INT32_MIN) >= 0))
- return CORD_asprintf("I32(%ld)", mpz_get_si(i));
+ return heap_strf("I32(%ld)", mpz_get_si(i));
code_err(ast, "This value cannot fit in a 32-bit integer");
case IBITS16:
if ((mpz_cmp_si(i, INT16_MAX) <= 0) && (mpz_cmp_si(i, INT16_MIN) >= 0))
- return CORD_asprintf("I16(%ld)", mpz_get_si(i));
+ return heap_strf("I16(%ld)", mpz_get_si(i));
code_err(ast, "This value cannot fit in a 16-bit integer");
case IBITS8:
if ((mpz_cmp_si(i, INT8_MAX) <= 0) && (mpz_cmp_si(i, INT8_MIN) >= 0))
- return CORD_asprintf("I8(%ld)", mpz_get_si(i));
+ return heap_strf("I8(%ld)", mpz_get_si(i));
code_err(ast, "This value cannot fit in a 8-bit integer");
case IBITS_BYTE:
if ((mpz_cmp_si(i, UINT8_MAX) <= 0) && (mpz_cmp_si(i, 0) >= 0))
- return CORD_asprintf("Byte(%ld)", mpz_get_si(i));
+ return heap_strf("Byte(%ld)", mpz_get_si(i));
code_err(ast, "This value cannot fit in a byte");
default: code_err(ast, "Not a valid integer bit width");
}
@@ -1931,9 +1933,9 @@ CORD compile(env_t *env, ast_t *ast)
case Num: {
switch (Match(ast, Num)->bits) {
case NBITS_UNSPECIFIED: case NBITS64:
- return CORD_asprintf("N64(%.20g)", Match(ast, Num)->n);
+ return heap_strf("N64(%.20g)", Match(ast, Num)->n);
case NBITS32:
- return CORD_asprintf("N32(%.10g)", Match(ast, Num)->n);
+ return heap_strf("N32(%.10g)", Match(ast, Num)->n);
default: code_err(ast, "This is not a valid number bit width");
}
}
@@ -1980,7 +1982,7 @@ CORD compile(env_t *env, ast_t *ast)
}
// TODO: for constructors, do new(T, ...) instead of heap((T){...})
- case HeapAllocate: return CORD_asprintf("heap(%r)", compile(env, Match(ast, HeapAllocate)->value));
+ case HeapAllocate: return heap_strf("heap(%r)", compile(env, Match(ast, HeapAllocate)->value));
case Optional: {
ast_t *value = Match(ast, Optional)->value;
CORD value_code = compile(env, value);
@@ -1992,7 +1994,7 @@ CORD compile(env_t *env, ast_t *ast)
CORD value_code = compile(env, value);
return CORD_all("({ ", compile_declaration(t, "opt"), " = ", value_code, "; ",
"if (", check_null(t, "opt"), ")\n",
- CORD_asprintf("fail_source(%r, %ld, %ld, \"This value was expected to be non-null, but it's null!\");\n",
+ heap_strf("fail_source(%r, %ld, %ld, \"This value was expected to be non-null, but it's null!\");\n",
CORD_quoted(ast->file->filename),
(long)(value->start - value->file->text),
(long)(value->end - value->file->text)),
@@ -2090,7 +2092,7 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " == ", rhs, ")");
default:
- return CORD_asprintf("generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(env, operand_t));
+ return heap_strf("generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(env, operand_t));
}
}
case BINOP_NE: {
@@ -2100,7 +2102,7 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " != ", rhs, ")");
default:
- return CORD_asprintf("!generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(env, operand_t));
+ return heap_strf("!generic_equal(stack(%r), stack(%r), %r)", lhs, rhs, compile_type_info(env, operand_t));
}
}
case BINOP_LT: {
@@ -2110,7 +2112,7 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " < ", rhs, ")");
default:
- return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) < 0)", lhs, rhs, compile_type_info(env, operand_t));
+ return heap_strf("(generic_compare(stack(%r), stack(%r), %r) < 0)", lhs, rhs, compile_type_info(env, operand_t));
}
}
case BINOP_LE: {
@@ -2120,7 +2122,7 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " <= ", rhs, ")");
default:
- return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) <= 0)", lhs, rhs, compile_type_info(env, operand_t));
+ return heap_strf("(generic_compare(stack(%r), stack(%r), %r) <= 0)", lhs, rhs, compile_type_info(env, operand_t));
}
}
case BINOP_GT: {
@@ -2130,7 +2132,7 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " > ", rhs, ")");
default:
- return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) > 0)", lhs, rhs, compile_type_info(env, operand_t));
+ return heap_strf("(generic_compare(stack(%r), stack(%r), %r) > 0)", lhs, rhs, compile_type_info(env, operand_t));
}
}
case BINOP_GE: {
@@ -2140,7 +2142,7 @@ CORD compile(env_t *env, ast_t *ast)
case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
return CORD_all("(", lhs, " >= ", rhs, ")");
default:
- return CORD_asprintf("(generic_compare(stack(%r), stack(%r), %r) >= 0)", lhs, rhs, compile_type_info(env, operand_t));
+ return heap_strf("(generic_compare(stack(%r), stack(%r), %r) >= 0)", lhs, rhs, compile_type_info(env, operand_t));
}
}
case BINOP_AND: {
@@ -2179,7 +2181,7 @@ CORD compile(env_t *env, ast_t *ast)
return CORD_all("Text$concat(", lhs, ", ", rhs, ")");
}
case ArrayType: {
- CORD padded_item_size = CORD_asprintf("%ld", type_size(Match(operand_t, ArrayType)->item_type));
+ CORD padded_item_size = heap_strf("%ld", type_size(Match(operand_t, ArrayType)->item_type));
return CORD_all("Array$concat(", lhs, ", ", rhs, ", ", padded_item_size, ")");
}
default:
@@ -2191,7 +2193,7 @@ CORD compile(env_t *env, ast_t *ast)
code_err(ast, "unimplemented binop");
}
case TextLiteral: {
- CORD literal = Match(ast, TextLiteral)->cord;
+ CORD literal = CORD_from_char_star(Text$as_c_string(Match(ast, TextLiteral)->text));
if (literal == CORD_EMPTY)
return "Text(\"\")";
@@ -2219,7 +2221,7 @@ CORD compile(env_t *env, ast_t *ast)
if (!chunks) {
return CORD_all(lang_constructor, "(\"\")");
} else if (!chunks->next && chunks->ast->tag == TextLiteral) {
- CORD literal = Match(chunks->ast, TextLiteral)->cord;
+ CORD literal = Text$as_c_string(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), ")");
@@ -2335,7 +2337,7 @@ CORD compile(env_t *env, ast_t *ast)
{
env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env;
- CORD code = CORD_all("TypedArrayN(", compile_type(item_type), CORD_asprintf(", %ld", n));
+ CORD code = CORD_all("TypedArrayN(", compile_type(item_type), heap_strf(", %ld", n));
for (ast_list_t *item = array->items; item; item = item->next) {
code = CORD_all(code, ", ", compile_to_type(scope, item->ast, item_type));
}
@@ -2347,7 +2349,7 @@ CORD compile(env_t *env, ast_t *ast)
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 = heap_strf("arr$%ld", comp_num++);
- ast_t *comprehension_var = FakeAST(InlineCCode, .code=CORD_all("&", comprehension_name),
+ ast_t *comprehension_var = FakeAST(InlineCCode, .code=Text$format("&%s", comprehension_name),
.type=Type(PointerType, .pointed=array_type, .is_view=true));
Closure_t comp_action = {.fn=add_to_array_comprehension, .userdata=comprehension_var};
scope->comprehension_action = &comp_action;
@@ -2426,7 +2428,7 @@ CORD compile(env_t *env, ast_t *ast)
static int64_t comp_num = 1;
env_t *scope = fresh_scope(env);
const char *comprehension_name = heap_strf("table$%ld", comp_num++);
- ast_t *comprehension_var = FakeAST(InlineCCode, .code=CORD_all("&", comprehension_name),
+ ast_t *comprehension_var = FakeAST(InlineCCode, .code=Text$format("&%s", comprehension_name),
.type=Type(PointerType, .pointed=table_type, .is_view=true));
CORD code = CORD_all("({ Table_t ", comprehension_name, " = {");
@@ -2480,7 +2482,7 @@ CORD compile(env_t *env, ast_t *ast)
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 = heap_strf("set$%ld", comp_num++);
- ast_t *comprehension_var = FakeAST(InlineCCode, .code=CORD_all("&", comprehension_name),
+ ast_t *comprehension_var = FakeAST(InlineCCode, .code=Text$format("&%s", comprehension_name),
.type=Type(PointerType, .pointed=set_type, .is_view=true));
CORD code = CORD_all("({ Table_t ", comprehension_name, " = {};");
Closure_t comp_action = {.fn=add_to_set_comprehension, .userdata=comprehension_var};
@@ -2507,11 +2509,11 @@ CORD compile(env_t *env, ast_t *ast)
}
case Lambda: {
auto lambda = Match(ast, Lambda);
- CORD name = CORD_asprintf("%rlambda$%ld", namespace_prefix(env, env->namespace), lambda->id);
+ CORD name = heap_strf("%rlambda$%ld", namespace_prefix(env, env->namespace), lambda->id);
env->code->function_naming = CORD_all(
env->code->function_naming,
- CORD_asprintf("register_function(%r, Text(\"%r [%s.tm:%ld]\"));\n",
+ heap_strf("register_function(%r, Text(\"%r [%s.tm:%ld]\"));\n",
name, type_to_cord(get_type(env, ast)), file_base_name(ast->file->filename), get_line_number(ast->file, ast->start)));
env_t *body_scope = fresh_scope(env);
@@ -2614,7 +2616,7 @@ CORD compile(env_t *env, ast_t *ast)
switch (self_value_t->tag) {
case ArrayType: {
type_t *item_t = Match(self_value_t, ArrayType)->item_type;
- CORD padded_item_size = CORD_asprintf("%ld", type_size(item_t));
+ CORD padded_item_size = heap_strf("%ld", type_size(item_t));
if (streq(call->name, "insert")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
@@ -2699,8 +2701,8 @@ CORD compile(env_t *env, ast_t *ast)
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=TYPE_IBITS32));
ast_t *default_cmp = FakeAST(InlineCCode,
- .code=CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(env, item_t), "})"),
+ .code=Text$format("((Closure_t){.fn=generic_compare, .userdata=(void*)%s})",
+ CORD_to_const_char_star(compile_type_info(env, 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));
@@ -2712,8 +2714,8 @@ CORD compile(env_t *env, ast_t *ast)
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=TYPE_IBITS32));
ast_t *default_cmp = FakeAST(InlineCCode,
- .code=CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(env, item_t), "})"),
+ .code=Text$format("((Closure_t){.fn=generic_compare, .userdata=(void*)%s})",
+ CORD_to_const_char_star(compile_type_info(env, 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);
@@ -2724,8 +2726,8 @@ CORD compile(env_t *env, ast_t *ast)
type_t *fn_t = Type(FunctionType, .args=new(arg_t, .name="x", .type=item_ptr, .next=new(arg_t, .name="y", .type=item_ptr)),
.ret=Type(IntType, .bits=TYPE_IBITS32));
ast_t *default_cmp = FakeAST(InlineCCode,
- .code=CORD_all("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(env, item_t), "})"),
+ .code=Text$format("((Closure_t){.fn=generic_compare, .userdata=(void*)%s})",
+ CORD_to_const_char_star(compile_type_info(env, 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));
@@ -2839,7 +2841,7 @@ CORD compile(env_t *env, ast_t *ast)
}
case ChannelType: {
type_t *item_t = Match(self_value_t, ChannelType)->item_type;
- CORD padded_item_size = CORD_asprintf("%ld", type_size(item_t));
+ CORD padded_item_size = heap_strf("%ld", type_size(item_t));
arg_t *front_default_end = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, false));
arg_t *front_default_start = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, true));
if (streq(call->name, "give")) {
@@ -2999,11 +3001,11 @@ CORD compile(env_t *env, ast_t *ast)
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_string_literal(Text$as_c_string(Match(call->args->value, TextLiteral)->text));
else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children == NULL)
return "\"\"";
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 compile_string_literal(Text$as_c_string(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->text));
type_t *actual = get_type(env, call->args->value);
return CORD_all("Text$as_c_string(", expr_as_text(env, compile(env, call->args->value), actual, "no"), ")");
} else if (t->tag == DateTimeType) {
@@ -3153,7 +3155,7 @@ CORD compile(env_t *env, ast_t *ast)
env_t *scope = fresh_scope(env);
set_binding(scope, "$reduction", new(binding_t, .type=t, .code="reduction"));
ast_t *item = FakeAST(Var, "$iter_value");
- ast_t *body = FakeAST(InlineCCode, .code="{}"); // placeholder
+ ast_t *body = FakeAST(InlineCCode, .code=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(scope, loop);
@@ -3167,14 +3169,16 @@ CORD compile(env_t *env, ast_t *ast)
early_out = "if (reduction) break;";
}
- body->__data.InlineCCode.code = CORD_all(
+ body->__data.InlineCCode.code = Text$format(
"if (!has_value) {\n"
- " reduction = ", compile(body_scope, item), ";\n"
+ " reduction = %s;\n"
" has_value = yes;\n"
"} else {\n"
- " reduction = ", compile(body_scope, reduction->combination), ";\n",
- early_out,
- "}\n");
+ " reduction = %s;\n"
+ "}\n%s\n",
+ CORD_to_const_char_star(compile(body_scope, item)),
+ CORD_to_const_char_star(compile(body_scope, reduction->combination)),
+ CORD_to_const_char_star(early_out));
CORD empty_handling;
if (reduction->fallback) {
@@ -3185,7 +3189,7 @@ CORD compile(env_t *env, ast_t *ast)
empty_handling = CORD_all("if (!has_value) reduction = ", compile(env, reduction->fallback), ";\n");
}
} else {
- empty_handling = CORD_asprintf("if (!has_value) fail_source(%r, %ld, %ld, \"This collection was empty!\");\n",
+ empty_handling = heap_strf("if (!has_value) fail_source(%r, %ld, %ld, \"This collection was empty!\");\n",
CORD_quoted(ast->file->filename),
(long)(reduction->iter->start - reduction->iter->file->text),
(long)(reduction->iter->end - reduction->iter->file->text));
@@ -3228,10 +3232,10 @@ CORD compile(env_t *env, ast_t *ast)
if (streq(field->name, f->field)) {
if (fielded_t->tag == PointerType) {
CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
- return CORD_asprintf("(%r)->$%s", fielded, f->field);
+ return heap_strf("(%r)->$%s", fielded, f->field);
} else {
CORD fielded = compile(env, f->fielded);
- return CORD_asprintf("(%r).$%s", fielded, f->field);
+ return heap_strf("(%r).$%s", fielded, f->field);
}
}
}
@@ -3284,7 +3288,7 @@ CORD compile(env_t *env, ast_t *ast)
return CORD_all("({ Array_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries;\n"
"ARRAY_INCREF(*entries);\n"
"Array_t values = *entries;\n"
- "values.data += ", CORD_asprintf("%zu", offset), ";\n"
+ "values.data += ", heap_strf("%zu", 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 : NULL_TABLE; })");
@@ -3330,8 +3334,8 @@ CORD compile(env_t *env, ast_t *ast)
else
return CORD_all("Array_get(", compile_type(item_type), ", ", arr, ", ",
compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64)), ", ",
- CORD_asprintf("%ld", (int64_t)(indexing->index->start - f->text)), ", ",
- CORD_asprintf("%ld", (int64_t)(indexing->index->end - f->text)),
+ heap_strf("%ld", (int64_t)(indexing->index->start - f->text)), ", ",
+ heap_strf("%ld", (int64_t)(indexing->index->end - f->text)),
")");
} else {
code_err(ast, "Indexing is not supported for type: %T", container_t);
@@ -3340,9 +3344,9 @@ 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", Match(ast, InlineCCode)->code, "\n}");
+ return CORD_all("{\n", Text$as_c_string(Match(ast, InlineCCode)->code), "\n}");
else
- return CORD_all("({ ", Match(ast, InlineCCode)->code, "; })");
+ return CORD_all("({ ", Text$as_c_string(Match(ast, InlineCCode)->code), "; })");
}
case Use: code_err(ast, "Compiling 'use' as expression!");
case Defer: code_err(ast, "Compiling 'defer' as expression!");
@@ -3476,7 +3480,7 @@ CORD compile_type_info(env_t *env, type_t *t)
}
case ChannelType: {
type_t *item_t = Match(t, ChannelType)->item_type;
- return CORD_asprintf("Channel$info(%r)", compile_type_info(env, item_t));
+ return heap_strf("Channel$info(%r)", compile_type_info(env, item_t));
}
case TableType: {
type_t *key_type = Match(t, TableType)->key_type;
@@ -3486,19 +3490,19 @@ CORD compile_type_info(env_t *env, type_t *t)
case PointerType: {
auto ptr = Match(t, PointerType);
CORD sigil = ptr->is_view ? "&" : "@";
- return CORD_asprintf("Pointer$info(%r, %r)",
+ return heap_strf("Pointer$info(%r, %r)",
CORD_quoted(sigil),
compile_type_info(env, ptr->pointed));
}
case FunctionType: {
- return CORD_asprintf("Function$info(%r)", CORD_quoted(type_to_cord(t)));
+ return heap_strf("Function$info(%r)", CORD_quoted(type_to_cord(t)));
}
case ClosureType: {
- return CORD_asprintf("Closure$info(%r)", CORD_quoted(type_to_cord(t)));
+ return heap_strf("Closure$info(%r)", CORD_quoted(type_to_cord(t)));
}
case OptionalType: {
type_t *non_optional = Match(t, OptionalType)->type;
- return CORD_asprintf("Optional$info(%zu, %zu, %r)", type_size(t), type_align(t), compile_type_info(env, non_optional));
+ return heap_strf("Optional$info(%zu, %zu, %r)", type_size(t), type_align(t), compile_type_info(env, non_optional));
}
case TypeInfoType: return CORD_all("TypeInfo$info(", CORD_quoted(type_to_cord(Match(t, TypeInfoType)->type)), ")");
case MemoryType: return "&Memory$info";
diff --git a/environment.c b/environment.c
index ffc23df1..c980bd16 100644
--- a/environment.c
+++ b/environment.c
@@ -613,7 +613,7 @@ binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name)
case TableType: return NULL;
case CStringType: case DateTimeType:
case BoolType: case IntType: case BigIntType: case NumType: {
- binding_t *b = get_binding(env, CORD_to_const_char_star(type_to_cord(cls_type)));
+ binding_t *b = get_binding(env, Text$as_c_string(type_to_text(cls_type)));
assert(b);
return get_binding(Match(b->type, TypeInfoType)->env, name);
}
diff --git a/parse.c b/parse.c
index 73c5dc1d..0f32e021 100644
--- a/parse.c
+++ b/parse.c
@@ -7,6 +7,7 @@
#include <stdbool.h>
#include <string.h>
#include <unistr.h>
+#include <unigbrk.h>
#include <unictype.h>
#include <uniname.h>
#include <signal.h>
@@ -1283,13 +1284,12 @@ PARSER(parse_text) {
// Escape sequence, e.g. \r\n
if (*pos == '\\') {
- CORD cord = CORD_EMPTY;
+ Text_t text = Text("");
do {
const char *c = unescape(ctx, &pos);
- cord = CORD_cat(cord, c);
- // cord = CORD_cat_char(cord, c);
+ text = Texts(text, Text$from_str(c));
} while (*pos == '\\');
- return NewAST(ctx->file, start, pos, TextLiteral, .cord=cord);
+ return NewAST(ctx->file, start, pos, TextLiteral, .text=text);
}
char open_quote, close_quote, open_interp = '$';
@@ -1330,17 +1330,17 @@ PARSER(parse_text) {
int64_t string_indent = starting_indent + 1;
ast_list_t *chunks = NULL;
- CORD chunk = CORD_EMPTY;
+ Text_t chunk = Text("");
const char *chunk_start = pos;
int depth = 1;
bool leading_newline = false;
for (; pos < ctx->file->text + ctx->file->len && depth > 0; ) {
if (*pos == open_interp) { // Interpolation
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=Text$format("%k", &chunk)); // Collapse text
chunks = new(ast_list_t, .ast=literal, .next=chunks);
- chunk = NULL;
+ chunk = Text("");
}
++pos;
ast_t *interp;
@@ -1353,7 +1353,7 @@ PARSER(parse_text) {
if (get_indent(ctx, pos) == starting_indent) {
++depth;
}
- chunk = CORD_cat_char(chunk, *pos);
+ chunk = Texts(chunk, Text$format("%c", *pos));
++pos;
} else if (!leading_newline && *pos == close_quote) { // Nested pair end
if (get_indent(ctx, pos) == starting_indent) {
@@ -1361,13 +1361,13 @@ PARSER(parse_text) {
if (depth == 0)
break;
}
- chunk = CORD_cat_char(chunk, *pos);
+ chunk = Texts(chunk, Text$format("%c", *pos));
++pos;
} else if (newline_with_indentation(&pos, string_indent)) { // Newline
- if (!leading_newline && !(chunk || chunks)) {
+ 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 (..)
if (*pos == close_quote) {
@@ -1378,16 +1378,19 @@ PARSER(parse_text) {
} else {
parser_err(ctx, pos, strchrnul(pos, '\n'), "This multi-line string should be either indented or have '..' at the front");
}
- } else { // Plain character
- chunk = CORD_cat_char(chunk, *pos);
- ++pos;
+ } else { // Regular grapheme cluster (no escapes etc.)
+ char *next = (char*)u8_grapheme_next((const uint8_t*)pos, (const uint8_t*)ctx->file->text + ctx->file->len);
+ while (next < ctx->file->text + ctx->file->len && !isascii(*next))
+ next = (char*)u8_grapheme_next((const uint8_t*)next, (const uint8_t*)ctx->file->text + ctx->file->len);
+ Text_t cluster = Text$from_strn(pos, (size_t)(next-pos));
+ chunk = Texts(chunk, cluster);
+ pos = next;
}
}
- 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=Text$format("%k", &chunk)); // Collapse text
chunks = new(ast_list_t, .ast=literal, .next=chunks);
- chunk = NULL;
}
REVERSE_LIST(chunks);
@@ -1407,13 +1410,13 @@ PARSER(parse_path) {
const char *chunk_start = start + 1;
ast_list_t *chunks = NULL;
- CORD chunk_text = CORD_EMPTY;
+ Text_t chunk_text = Text("");
int paren_depth = 1;
while (pos < ctx->file->text + ctx->file->len) {
switch (*pos) {
case '\\': {
++pos;
- chunk_text = CORD_asprintf("%r%.*s%c", chunk_text, (size_t)(pos - chunk_start), chunk_start, *pos);
+ chunk_text = Text$format("%k%.*s%c", &chunk_text, (size_t)(pos - chunk_start), chunk_start, *pos);
++pos;
chunk_start = pos;
continue;
@@ -1422,12 +1425,12 @@ PARSER(parse_path) {
const char *interp_start = pos;
if (pos > chunk_start)
- chunk_text = CORD_asprintf("%r%.*s", chunk_text, (size_t)(pos - chunk_start), chunk_start);
+ chunk_text = Text$format("%k%.*s", &chunk_text, (size_t)(pos - chunk_start), chunk_start);
- if (chunk_text) {
- ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk_text);
+ if (chunk_text.length > 0) {
+ ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text=chunk_text);
chunks = new(ast_list_t, .ast=literal, .next=chunks);
- chunk_text = CORD_EMPTY;
+ chunk_text = Text("");
}
++pos;
if (*pos == ' ' || *pos == '\t')
@@ -1455,10 +1458,10 @@ PARSER(parse_path) {
end_of_path:;
if (pos > chunk_start)
- chunk_text = CORD_asprintf("%r%.*s", chunk_text, (size_t)(pos - chunk_start), chunk_start);
+ chunk_text = Text$format("%k%.*s", &chunk_text, (size_t)(pos - chunk_start), chunk_start);
- if (chunk_text != CORD_EMPTY) {
- ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk_text);
+ if (chunk_text.length > 0) {
+ ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text=chunk_text);
chunks = new(ast_list_t, .ast=literal, .next=chunks);
}
@@ -2283,7 +2286,7 @@ PARSER(parse_inline_c) {
if (depth != 0)
parser_err(ctx, start, start+1, "I couldn't find the closing '}' for this inline C code");
- CORD c_code = GC_strndup(c_code_start, (size_t)((pos-1) - c_code_start));
+ Text_t c_code = Text$format("%.*s", (size_t)((pos-1) - c_code_start), c_code_start);
return NewAST(ctx->file, start, pos, InlineCCode, .code=c_code, .type_ast=type);
}
@@ -2322,16 +2325,16 @@ PARSER(parse_say) {
spaces(&pos);
ast_list_t *chunks = NULL;
- CORD chunk = CORD_EMPTY;
+ Text_t chunk = Text("");
const char *chunk_start = pos;
const char open_interp = '$';
while (pos < ctx->file->text + ctx->file->len) {
if (*pos == open_interp) { // Interpolation
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=Text$format("%k", &chunk));
chunks = new(ast_list_t, .ast=literal, .next=chunks);
- chunk = NULL;
+ chunk = Text("");
}
++pos;
ast_t *interp;
@@ -2343,15 +2346,14 @@ PARSER(parse_say) {
} else if (*pos == '\r' || *pos == '\n') { // Newline
break;
} else { // Plain character
- chunk = CORD_cat_char(chunk, *pos);
+ chunk = Texts(chunk, Text$format("%c", *pos));
++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=Text$format("%k", &chunk));
chunks = new(ast_list_t, .ast=literal, .next=chunks);
- chunk = NULL;
}
REVERSE_LIST(chunks);
diff --git a/repl.c b/repl.c
index c9d518d3..e88efcbd 100644
--- a/repl.c
+++ b/repl.c
@@ -135,7 +135,7 @@ const TypeInfo_t *type_to_type_info(type_t *t)
}
case PointerType: {
auto ptr = Match(t, PointerType);
- CORD sigil = ptr->is_view ? "&" : "@";
+ const char *sigil = ptr->is_view ? "&" : "@";
const TypeInfo_t *pointed_info = type_to_type_info(ptr->pointed);
const TypeInfo_t pointer_info = {.size=sizeof(void*), .align=__alignof__(void*),
.tag=PointerInfo, .PointerInfo={.sigil=sigil, .pointed=pointed_info}};
@@ -372,24 +372,24 @@ void eval(env_t *env, ast_t *ast, void *dest)
break;
}
case TextLiteral:
- if (dest) *(CORD*)dest = Match(ast, TextLiteral)->cord;
+ if (dest) *(Text_t*)dest = Match(ast, TextLiteral)->text;
break;
case TextJoin: {
- CORD ret = CORD_EMPTY;
+ Text_t ret = Text("");
for (ast_list_t *chunk = Match(ast, TextJoin)->children; chunk; chunk = chunk->next) {
type_t *chunk_t = get_type(env, chunk->ast);
if (chunk_t->tag == TextType) {
- CORD c;
- eval(env, chunk->ast, &c);
- ret = CORD_cat(ret, c);
+ Text_t chunk_text;
+ eval(env, chunk->ast, &chunk_text);
+ ret = Texts(ret, chunk_text);
} else {
size_t chunk_size = type_size(chunk_t);
char buf[chunk_size];
eval(env, chunk->ast, buf);
- ret = CORD_cat(ret, Text$as_c_string(obj_to_text(chunk_t, buf, false)));
+ ret = Texts(ret, obj_to_text(chunk_t, buf, false));
}
}
- if (dest) *(CORD*)dest = ret;
+ if (dest) *(Text_t*)dest = ret;
break;
}
case BinaryOp: {
diff --git a/stdlib/text.c b/stdlib/text.c
index 7b579f5e..deca024a 100644
--- a/stdlib/text.c
+++ b/stdlib/text.c
@@ -630,7 +630,7 @@ public Text_t Text$from_strn(const char *str, size_t len)
ucs4_t buf[128];
size_t length = sizeof(buf)/sizeof(buf[0]);
- ucs4_t *codepoints = u8_to_u32((uint8_t*)str, (size_t)ascii_span + strlen(str + ascii_span), buf, &length);
+ ucs4_t *codepoints = u8_to_u32((uint8_t*)str, len, buf, &length);
Text_t ret = text_from_u32(codepoints, (int64_t)length, true);
if (codepoints != buf) free(codepoints);
return ret;
diff --git a/tomo.c b/tomo.c
index f59000e7..79bcaf66 100644
--- a/tomo.c
+++ b/tomo.c
@@ -60,6 +60,13 @@ static Text_t escape_lib_name(Text_t lib_name);
static void build_library(Text_t lib_dir_name);
static void compile_files(env_t *env, Array_t files, bool only_compile_arguments, Array_t *object_files, Array_t *ldlibs);
+static int printf_cord(FILE *stream, const struct printf_info *info, const void *const argv[])
+{
+ (void)info;
+ CORD c = *(CORD*)argv[0];
+ return CORD_put(c, stream);
+}
+
#pragma GCC diagnostic ignored "-Wstack-protector"
int main(int argc, char *argv[])
{
@@ -69,6 +76,8 @@ int main(int argc, char *argv[])
errx(1, "Couldn't set printf specifier");
if (register_printf_specifier('k', printf_text, printf_text_size))
errx(1, "Couldn't set printf specifier");
+ if (register_printf_specifier('r', printf_cord, printf_pointer_size))
+ errx(1, "Couldn't set printf specifier");
Text_t usage = Text("\x1b[33;4;1mUsage:\x1b[m\n"
@@ -315,7 +324,7 @@ void build_library(Text_t lib_dir_name)
errx(WEXITSTATUS(status), "Failed to run `patchelf` to rename dynamic symbols with library prefix");
if (verbose)
- CORD_printf("Successfully renamed symbols with library prefix!\n");
+ printf("Successfully renamed symbols with library prefix!\n");
unlink("symbol_renames.txt");
diff --git a/typecheck.c b/typecheck.c
index 6cc41216..43dec880 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -1326,14 +1326,8 @@ 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;
-#pragma GCC diagnostic ignored "-Wsign-conversion"
- CORD_FOR(i, literal) {
- if (!isascii(CORD_pos_fetch(i)))
- return false; // Non-ASCII requires grapheme logic, not constant
- }
- return true; // Literal ASCII string, OK
+ Text_t text = Match(ast, TextLiteral)->text;
+ return (text.tag == TEXT_SHORT_ASCII || text.tag == TEXT_ASCII);
}
case Not: return is_constant(env, Match(ast, Not)->value);
case Negative: return is_constant(env, Match(ast, Negative)->value);
diff --git a/types.c b/types.c
index 1a140a32..6a007c3e 100644
--- a/types.c
+++ b/types.c
@@ -1,91 +1,91 @@
// 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 "stdlib/datatypes.h"
#include "stdlib/integers.h"
#include "stdlib/tables.h"
+#include "stdlib/text.h"
#include "stdlib/util.h"
-#include "cordhelpers.h"
#include "types.h"
-CORD type_to_cord(type_t *t) {
+Text_t type_to_text(type_t *t) {
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 DateTimeType: return "DateTime";
- case TextType: return Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text";
- case BigIntType: return "Int";
- case IntType: return CORD_asprintf("Int%d", Match(t, IntType)->bits);
- case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? "Num32" : "Num";
+ return Texts(Text("Return("), ret ? type_to_text(ret) : Text("Void"), Text(")"));
+ }
+ 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 DateTimeType: return Text("DateTime");
+ case TextType: return Match(t, TextType)->lang ? Text$from_str(Match(t, TextType)->lang) : Text("Text");
+ case BigIntType: return Text("Int");
+ case IntType: return Text$format("Int%d", Match(t, IntType)->bits);
+ case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("Num32") : Text("Num");
case ArrayType: {
auto array = Match(t, ArrayType);
- return CORD_asprintf("[%r]", type_to_cord(array->item_type));
+ return Texts(Text("["), type_to_text(array->item_type), Text("]"));
}
case ChannelType: {
auto array = Match(t, ChannelType);
- return CORD_asprintf("||%r", type_to_cord(array->item_type));
+ return Texts(Text("||"), type_to_text(array->item_type));
}
case TableType: {
auto table = Match(t, TableType);
- return CORD_asprintf("{%r:%r}", type_to_cord(table->key_type), type_to_cord(table->value_type));
+ return Texts(Text("{"), type_to_text(table->key_type), Text(":"), type_to_text(table->value_type), Text("}"));
}
case SetType: {
auto set = Match(t, SetType);
- return CORD_asprintf("{%r}", type_to_cord(set->item_type));
+ return Texts(Text("{"), type_to_text(set->item_type), Text("}"));
}
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 text = Text("func(");
auto fn = Match(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, ", ");
+ text = Texts(text, type_to_text(arg->type));
+ if (arg->next) text = Texts(text, Text(", "));
}
if (fn->ret && fn->ret->tag != VoidType)
- c = CORD_all(c, "->", type_to_cord(fn->ret));
- c = CORD_all(c, ")");
- return c;
+ text = Texts(text, Text("->"), type_to_text(fn->ret));
+ text = Texts(text, Text(")"));
+ return text;
}
case StructType: {
auto struct_ = Match(t, StructType);
- return struct_->name;
+ return Text$from_str(struct_->name);
}
case PointerType: {
auto ptr = Match(t, PointerType);
- CORD sigil = ptr->is_view ? "&" : "@";
- return CORD_all(sigil, type_to_cord(ptr->pointed));
+ Text_t sigil = ptr->is_view ? Text("&") : Text("@");
+ return Texts(sigil, type_to_text(ptr->pointed));
}
case EnumType: {
auto tagged = Match(t, EnumType);
- return tagged->name;
+ return Text$from_str(tagged->name);
}
case OptionalType: {
- return CORD_all(type_to_cord(Match(t, OptionalType)->type), "?");
+ return Texts(type_to_text(Match(t, OptionalType)->type), Text("?"));
}
case TypeInfoType: {
- return CORD_all("Type$info(", Match(t, TypeInfoType)->name, ")");
+ return Texts(Text("Type$info("), Text$from_str(Match(t, TypeInfoType)->name), Text(")"));
}
case ModuleType: {
- return CORD_all("Module(", Match(t, ModuleType)->name, ")");
+ return Texts(Text("Module("), Text$from_str(Match(t, ModuleType)->name), Text(")"));
}
default: {
raise(SIGABRT);
- return CORD_asprintf("Unknown type: %d", t->tag);
+ return Text$format("Unknown type: %d", t->tag);
}
}
}
@@ -104,14 +104,14 @@ int printf_type(FILE *stream, const struct printf_info *info, const void *const
(void)info;
type_t *t = *(type_t**)args[0];
if (!t) return fputs("(null)", stream);
- return CORD_put(type_to_cord(t), stream);
+ return Text$print(stream, type_to_text(t));
}
bool type_eq(type_t *a, type_t *b)
{
if (a == b) return true;
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/types.h b/types.h
index 96e0b6c5..f9e050e6 100644
--- a/types.h
+++ b/types.h
@@ -7,6 +7,7 @@
#include "ast.h"
#include "stdlib/arrays.h"
+#include "stdlib/datatypes.h"
typedef struct type_s type_t;
@@ -135,7 +136,7 @@ struct type_s {
int printf_pointer_size(const struct printf_info *info, size_t n, int argtypes[n], int size[n]);
int printf_type(FILE *stream, const struct printf_info *info, const void *const args[]);
-CORD type_to_cord(type_t *t);
+Text_t type_to_text(type_t *t);
PUREFUNC bool type_eq(type_t *a, type_t *b);
PUREFUNC bool type_is_a(type_t *t, type_t *req);
type_t *type_or_type(type_t *a, type_t *b);