diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-04-28 16:05:09 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-04-28 16:05:09 -0400 |
| commit | 9da5949b953ae5424afb77ff4280399eacf414d4 (patch) | |
| tree | 4db2b1ec3abe4f4e63d0fd57c3efbf588c8f92f4 /src | |
| parent | a49610246e12d8e2947f8ce2bc981acbbb88a901 (diff) | |
Remove remaining printf references
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast.c | 135 | ||||
| -rw-r--r-- | src/compile.c | 243 | ||||
| -rw-r--r-- | src/cordhelpers.c | 17 | ||||
| -rw-r--r-- | src/cordhelpers.h | 3 | ||||
| -rw-r--r-- | src/enums.c | 7 | ||||
| -rw-r--r-- | src/stdlib/fpconv.h | 2 | ||||
| -rw-r--r-- | src/stdlib/integers.c | 7 | ||||
| -rw-r--r-- | src/stdlib/print.c | 102 | ||||
| -rw-r--r-- | src/stdlib/print.h | 7 | ||||
| -rw-r--r-- | src/structs.c | 17 | ||||
| -rw-r--r-- | src/tomo.c | 11 | ||||
| -rw-r--r-- | src/typecheck.c | 4 | ||||
| -rw-r--r-- | src/types.c | 9 |
13 files changed, 315 insertions, 249 deletions
@@ -112,16 +112,15 @@ CORD type_ast_to_sexp(type_ast_t *t) if (!t) return "nil"; switch (t->tag) { -#define T(type, ...) case type: { __typeof(t->__data.type) data = t->__data.type; (void)data; return CORD_asprintf(__VA_ARGS__); } +#define T(type, ...) case type: { __typeof(t->__data.type) data = t->__data.type; (void)data; return CORD_all(__VA_ARGS__); } T(UnknownTypeAST, "(UnknownType)") - T(VarTypeAST, "(VarType \"%s\")", data.name) - T(PointerTypeAST, "(PointerType \"%s\" %r)", - data.is_stack ? "stack" : "heap", type_ast_to_sexp(data.pointed)) - T(ListTypeAST, "(ListType %r)", type_ast_to_sexp(data.item)) - T(SetTypeAST, "(SetType %r)", type_ast_to_sexp(data.item)) - T(TableTypeAST, "(TableType %r %r)", type_ast_to_sexp(data.key), type_ast_to_sexp(data.value)) - T(FunctionTypeAST, "(FunctionType %r %r)", arg_defs_to_sexp(data.args), type_ast_to_sexp(data.ret)) - T(OptionalTypeAST, "(OptionalType %r)", type_ast_to_sexp(data.type)) + T(VarTypeAST, "(VarType \"", data.name, "\")") + T(PointerTypeAST, "(PointerType \"", data.is_stack ? "stack" : "heap", "\" ", type_ast_to_sexp(data.pointed), ")") + T(ListTypeAST, "(ListType ", type_ast_to_sexp(data.item), ")") + T(SetTypeAST, "(SetType ", type_ast_to_sexp(data.item), ")") + T(TableTypeAST, "(TableType ", type_ast_to_sexp(data.key), " ", type_ast_to_sexp(data.value), ")") + 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; } @@ -142,19 +141,19 @@ CORD ast_to_sexp(ast_t *ast) if (!ast) return "nil"; switch (ast->tag) { -#define T(type, ...) case type: { __typeof(ast->__data.type) data = ast->__data.type; (void)data; return CORD_asprintf(__VA_ARGS__); } +#define T(type, ...) case type: { __typeof(ast->__data.type) data = ast->__data.type; (void)data; return CORD_all(__VA_ARGS__); } T(Unknown, "(Unknown)") T(None, "(None)") - T(Bool, "(Bool %s)", data.b ? "yes" : "no") - T(Var, "(Var %r)", CORD_quoted(data.name)) - T(Int, "(Int %r)", CORD_quoted(ast_source(ast))) - T(Num, "(Num %r)", CORD_quoted(ast_source(ast))) - T(TextLiteral, "%r", CORD_quoted(data.cord)) - T(TextJoin, "(Text%r%r)", data.lang ? CORD_all(" :lang ", CORD_quoted(data.lang)) : CORD_EMPTY, ast_list_to_sexp(data.children)) - T(Path, "(Path %r)", CORD_quoted(data.path)) - T(Declare, "(Declare %r %r %r)", ast_to_sexp(data.var), type_ast_to_sexp(data.type), ast_to_sexp(data.value)) - T(Assign, "(Assign (targets %r) (values %r))", ast_list_to_sexp(data.targets), ast_list_to_sexp(data.values)) -#define BINOP(name) T(name, "(" #name " %r %r)", ast_to_sexp(data.lhs), ast_to_sexp(data.rhs)) + 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(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), ")") BINOP(Power) BINOP(PowerUpdate) BINOP(Multiply) BINOP(MultiplyUpdate) BINOP(Divide) BINOP(DivideUpdate) BINOP(Mod) BINOP(ModUpdate) BINOP(Mod1) BINOP(Mod1Update) BINOP(Plus) BINOP(PlusUpdate) BINOP(Minus) BINOP(MinusUpdate) BINOP(Concat) BINOP(ConcatUpdate) BINOP(LeftShift) BINOP(LeftShiftUpdate) BINOP(RightShift) BINOP(RightShiftUpdate) BINOP(UnsignedLeftShift) BINOP(UnsignedLeftShiftUpdate) @@ -162,58 +161,52 @@ CORD ast_to_sexp(ast_t *ast) BINOP(Xor) BINOP(XorUpdate) BINOP(Compare) BINOP(Equals) BINOP(NotEquals) BINOP(LessThan) BINOP(LessThanOrEquals) BINOP(GreaterThan) BINOP(GreaterThanOrEquals) #undef BINOP - T(Negative, "(Negative %r)", ast_to_sexp(data.value)) - T(Not, "(Not %r)", ast_to_sexp(data.value)) - T(HeapAllocate, "(HeapAllocate %r)", ast_to_sexp(data.value)) - T(StackReference, "(StackReference %r)", ast_to_sexp(data.value)) - T(Min, "(Min %r %r%r)", ast_to_sexp(data.lhs), ast_to_sexp(data.rhs), optional_sexp("key", data.key)) - T(Max, "(Max %r %r%r)", ast_to_sexp(data.lhs), ast_to_sexp(data.rhs), optional_sexp("key", data.key)) - T(List, "(List%r)", ast_list_to_sexp(data.items)) - T(Set, "(Set%r)", ast_list_to_sexp(data.items)) - T(Table, "(Table%r%r%r)", - optional_sexp("default", data.default_value), - optional_sexp("fallback", data.fallback), - ast_list_to_sexp(data.entries)) - T(TableEntry, "(TableEntry %r %r)", ast_to_sexp(data.key), ast_to_sexp(data.value)) - T(Comprehension, "(Comprehension %r (vars%r) %r %r)", ast_to_sexp(data.expr), - ast_list_to_sexp(data.vars), ast_to_sexp(data.iter), - optional_sexp("filter", data.filter)) - T(FunctionDef, "(FunctionDef %r %r%r %r)", ast_to_sexp(data.name), - arg_defs_to_sexp(data.args), optional_type_sexp("return", data.ret_type), ast_to_sexp(data.body)) - T(ConvertDef, "(ConvertDef %r %r %r)", - arg_defs_to_sexp(data.args), type_ast_to_sexp(data.ret_type), ast_to_sexp(data.body)) - T(Lambda, "(Lambda %r%r %r)", arg_defs_to_sexp(data.args), - optional_type_sexp("return", data.ret_type), ast_to_sexp(data.body)) - T(FunctionCall, "(FunctionCall %r%r)", ast_to_sexp(data.fn), arg_list_to_sexp(data.args)) - T(MethodCall, "(MethodCall %r %r%r)", ast_to_sexp(data.self), CORD_quoted(data.name), arg_list_to_sexp(data.args)) - T(Block, "(Block%r)", ast_list_to_sexp(data.statements)) - T(For, "(For (vars%r) %r %r %r)", ast_list_to_sexp(data.vars), ast_to_sexp(data.iter), - ast_to_sexp(data.body), ast_to_sexp(data.empty)) - T(While, "(While %r %r)", ast_to_sexp(data.condition), ast_to_sexp(data.body)) - T(Repeat, "(Repeat %r)", ast_to_sexp(data.body)) - T(If, "(If %r %r%r)", ast_to_sexp(data.condition), ast_to_sexp(data.body), optional_sexp("else", data.else_body)) - T(When, "(When %r%r%r)", ast_to_sexp(data.subject), when_clauses_to_sexp(data.clauses), optional_sexp("else", data.else_body)) - T(Reduction, "(Reduction %r %r %r)", CORD_quoted(binop_method_name(data.op)), ast_to_sexp(data.key), - ast_to_sexp(data.iter)) - T(Skip, "(Skip %r)", CORD_quoted(data.target)) - T(Stop, "(Stop %r)", CORD_quoted(data.target)) + T(Negative, "(Negative ", ast_to_sexp(data.value), ")") + T(Not, "(Not ", ast_to_sexp(data.value), ")") + T(HeapAllocate, "(HeapAllocate ", ast_to_sexp(data.value), ")") + T(StackReference, "(StackReference ", ast_to_sexp(data.value), ")") + T(Min, "(Min ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), optional_sexp("key", data.key), ")") + T(Max, "(Max ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), optional_sexp("key", data.key), ")") + T(List, "(List", ast_list_to_sexp(data.items), ")") + T(Set, "(Set", ast_list_to_sexp(data.items), ")") + T(Table, "(Table", optional_sexp("default", data.default_value), optional_sexp("fallback", data.fallback), + ast_list_to_sexp(data.entries), ")") + T(TableEntry, "(TableEntry ", ast_to_sexp(data.key), " ", ast_to_sexp(data.value), ")") + T(Comprehension, "(Comprehension ", ast_to_sexp(data.expr), " (vars", ast_list_to_sexp(data.vars), ") ", + ast_to_sexp(data.iter), " ", optional_sexp("filter", data.filter), ")") + T(FunctionDef, "(FunctionDef ", ast_to_sexp(data.name), " ", arg_defs_to_sexp(data.args), + optional_type_sexp("return", data.ret_type), " ", ast_to_sexp(data.body), ")") + 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(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), ")") + T(While, "(While ", ast_to_sexp(data.condition), " ", ast_to_sexp(data.body), ")") + 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(Pass, "(Pass)") - T(Defer, "(Defer %r)", ast_to_sexp(data.body)) - T(Return, "(Return %r)", ast_to_sexp(data.value)) - T(Extern, "(Extern \"%s\" %r)", data.name, type_ast_to_sexp(data.type)) - T(StructDef, "(StructDef \"%s\" %r %r)", data.name, arg_defs_to_sexp(data.fields), ast_to_sexp(data.namespace)) - T(EnumDef, "(EnumDef \"%s\" (tags %r) %r)", data.name, tags_to_sexp(data.tags), ast_to_sexp(data.namespace)) - T(LangDef, "(LangDef \"%s\" %r)", data.name, ast_to_sexp(data.namespace)) - T(Index, "(Index %r %r)", ast_to_sexp(data.indexed), ast_to_sexp(data.index)) - T(FieldAccess, "(FieldAccess %r \"%s\")", ast_to_sexp(data.fielded), data.field) - T(Optional, "(Optional %r)", ast_to_sexp(data.value)) - T(NonOptional, "(NonOptional %r)", ast_to_sexp(data.value)) - T(DocTest, "(DocTest %r%r)", ast_to_sexp(data.expr), optional_sexp("expected", data.expected)) - T(Assert, "(Assert %r %r)", ast_to_sexp(data.expr), optional_sexp("message", data.message)) - T(Use, "(Use %r %r)", optional_sexp("var", data.var), CORD_quoted(data.path)) - T(InlineCCode, "(InlineCCode %r%r)", ast_list_to_sexp(data.chunks), optional_type_sexp("type", data.type_ast)) - T(Deserialize, "(Deserialize %r %r)", type_ast_to_sexp(data.type), ast_to_sexp(data.value)) - T(Extend, "(Extend \"%s\" %r)", data.name, ast_to_sexp(data.body)) + T(Defer, "(Defer ", ast_to_sexp(data.body), ")") + T(Return, "(Return ", ast_to_sexp(data.value), ")") + T(Extern, "(Extern \"", data.name, "\" ", type_ast_to_sexp(data.type), ")") + T(StructDef, "(StructDef \"", data.name, "\" ", arg_defs_to_sexp(data.fields), " ", ast_to_sexp(data.namespace), ")") + T(EnumDef, "(EnumDef \"", data.name, "\" (tags ", tags_to_sexp(data.tags), ") ", ast_to_sexp(data.namespace), ")") + T(LangDef, "(LangDef \"", data.name, "\" ", ast_to_sexp(data.namespace), ")") + T(Index, "(Index ", ast_to_sexp(data.indexed), " ", ast_to_sexp(data.index), ")") + T(FieldAccess, "(FieldAccess ", ast_to_sexp(data.fielded), " \"", data.field, "\")") + T(Optional, "(Optional ", ast_to_sexp(data.value), ")") + 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(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), ")") default: errx(1, "S-expressions are not implemented for this AST"); #undef T } diff --git a/src/compile.c b/src/compile.c index 37b3934f..1c49c09b 100644 --- a/src/compile.c +++ b/src/compile.c @@ -73,7 +73,7 @@ static CORD with_source_info(env_t *env, ast_t *ast, CORD code) if (code == CORD_EMPTY || !ast || !ast->file || !env->do_source_mapping) return code; int64_t line = get_line_number(ast->file, ast->start); - return CORD_asprintf("\n#line %ld\n%r", line, code); + return CORD_all("\n#line ", String(line), "\n", code); } static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t *needed) @@ -114,10 +114,10 @@ static bool promote(env_t *env, ast_t *ast, CORD *code, type_t *actual, type_t * if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) { *code = CORD_all("({ ", compile_declaration(actual, "opt"), " = ", *code, "; ", "if unlikely (", check_none(actual, "opt"), ")\n", - CORD_asprintf("fail_source(%r, %ld, %ld, \"This was expected to be a value, but it's none\");\n", - CORD_quoted(ast->file->filename), - (long)(ast->start - ast->file->text), - (long)(ast->end - ast->file->text)), + "fail_source(", CORD_quoted(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"), "; })"); return true; } @@ -792,8 +792,8 @@ CORD compile_type(type_t *t) case ByteType: return "Byte_t"; case CStringType: return "const char*"; 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 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 TextType: { DeclareMatch(text, t, TextType); if (!text->lang || streq(text->lang, "Text")) @@ -1188,11 +1188,14 @@ static CORD _compile_statement(env_t *env, ast_t *ast) 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); - CORD_appendf(&test_code, "%r $%ld = %r;\n", compile_type(lhs_t), i++, val_code); + test_code = CORD_all(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_asprintf("$%ld", i++)), ";\n"); + 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"); + i += 1; + } test_code = CORD_all(test_code, "$1; })"); } @@ -1218,27 +1221,27 @@ static CORD _compile_statement(env_t *env, ast_t *ast) test_code = compile(env, test->expr); } if (test->expected) { - return CORD_asprintf( - "%rtest(%r, %r, %r, %r, %ld, %ld);", - setup, compile_type(expr_t), test_code, - compile_to_type(env, test->expected, expr_t), - compile_type_info(expr_t), - (int64_t)(test->expr->start - test->expr->file->text), - (int64_t)(test->expr->end - test->expr->file->text)); + return CORD_all( + setup, + "test(", compile_type(expr_t), ", ", test_code, ", ", + compile_to_type(env, test->expected, expr_t), ", ", + 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)), ");"); } else { if (expr_t->tag == VoidType || expr_t->tag == AbortType) { - return CORD_asprintf("%rinspect_void(%r, %r, %ld, %ld);", - setup, test_code, - compile_type_info(expr_t), - (int64_t)(test->expr->start - test->expr->file->text), - (int64_t)(test->expr->end - test->expr->file->text)); + return CORD_all( + 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_asprintf( - "%rinspect(%r, %r, %r, %ld, %ld);", - setup, compile_type(expr_t), test_code, - compile_type_info(expr_t), - (int64_t)(test->expr->start - test->expr->file->text), - (int64_t)(test->expr->end - test->expr->file->text)); + return CORD_all( + setup, + "inspect(", compile_type(expr_t), ", ", 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)), ");"); } } case Assert: { @@ -1283,26 +1286,26 @@ static CORD _compile_statement(env_t *env, ast_t *ast) compile_declaration(operand_t, "_lhs"), " = ", compile_to_type(env, cmp.lhs, operand_t), ";\n", compile_declaration(operand_t, "_rhs"), " = ", compile_to_type(env, cmp.rhs, operand_t), ";\n", "if (!(", compile_condition(env, var_comparison), "))\n", - CORD_asprintf("fail_source(%r, %ld, %ld, %r, \" (\", %r, \" %s \", %r, \")\");\n", - CORD_quoted(ast->file->filename), - (long)(expr->start - expr->file->text), - (long)(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")), + CORD_all( + "fail_source(", CORD_quoted(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"), "}\n"); } default: { - return CORD_all("if (!(", compile_condition(env, expr), "))\n", - CORD_asprintf("fail_source(%r, %ld, %ld, %r);\n", - CORD_quoted(ast->file->filename), - (long)(expr->start - expr->file->text), - (long)(expr->end - expr->file->text), - message ? CORD_all("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")") - : "\"This assertion failed!\"")); + return CORD_all( + "if (!(", compile_condition(env, expr), "))\n", + "fail_source(", CORD_quoted(ast->file->filename), ", ", + String((long)(expr->start - expr->file->text)), ", ", + String((long)(expr->end - expr->file->text)), ", ", + message ? CORD_all("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")") + : "\"This assertion failed!\"", + ");\n"); } } } @@ -1350,11 +1353,13 @@ static CORD _compile_statement(env_t *env, ast_t *ast) 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); - CORD_appendf(&code, "%r $%ld = %r;\n", compile_type(lhs_t), i++, val); + code = CORD_all(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_asprintf("$%ld", i++)), ";\n"); + code = CORD_all(code, compile_assignment(env, target->ast, CORD_all("$", String(i))), ";\n"); + i += 1; } return CORD_cat(code, "\n}"); } @@ -1410,7 +1415,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (matched) { if (!ctx->skip_label) { static int64_t skip_label_count = 1; - CORD_sprintf(&ctx->skip_label, "skip_%ld", skip_label_count); + ctx->skip_label = CORD_all("skip_", String(skip_label_count)); ++skip_label_count; } CORD code = CORD_EMPTY; @@ -1439,7 +1444,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (matched) { if (!ctx->stop_label) { static int64_t stop_label_count = 1; - CORD_sprintf(&ctx->stop_label, "stop_%ld", stop_label_count); + ctx->stop_label = CORD_all("stop_", String(stop_label_count)); ++stop_label_count; } CORD code = CORD_EMPTY; @@ -1473,7 +1478,8 @@ static CORD _compile_statement(env_t *env, ast_t *ast) if (CORD_ncmp(entry->b->code, 0, "userdata->", 0, strlen("userdata->")) == 0) { Table$str_set(defer_env->locals, entry->name, entry->b); } else { - CORD defer_name = CORD_asprintf("defer$%d$%s", ++defer_id, entry->name); + CORD defer_name = CORD_all("defer$", String(++defer_id), "$", entry->name); + defer_id += 1; code = CORD_all( code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n"); set_binding(defer_env, entry->name, entry->b->type, defer_name); @@ -1992,7 +1998,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) // 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_asprintf("(void)%r;", compile(env, ast)); + return CORD_all("(void)", compile(env, ast), ";"); } } @@ -2004,24 +2010,24 @@ CORD compile_statement(env_t *env, ast_t *ast) { CORD expr_as_text(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 CORD_all("Memory$as_text(stack(", expr, "), ", color, ", &Memory$info)"); 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); + 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)"); 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); - } - case TextType: return CORD_asprintf("Text$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case ListType: return CORD_asprintf("List$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case SetType: return CORD_asprintf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case TableType: return CORD_asprintf("Table$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case FunctionType: case ClosureType: return CORD_asprintf("Func$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case PointerType: return CORD_asprintf("Pointer$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); - case OptionalType: return CORD_asprintf("Optional$as_text(stack(%r), %r, %r)", expr, color, compile_type_info(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), ")"); case StructType: case EnumType: - return CORD_asprintf("generic_as_text(stack(%r), %r, %r)", expr, color, compile_type_info(t)); + return CORD_all("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; @@ -2083,8 +2089,8 @@ CORD compile_to_type(env_t *env, ast_t *ast, type_t *t) } else if (ast->tag == Num && t->tag == NumType) { double n = Match(ast, Num)->n; switch (Match(t, NumType)->bits) { - case TYPE_NBITS64: return CORD_asprintf("N64(%.20g)", n); - case TYPE_NBITS32: return CORD_asprintf("N32(%.10g)", n); + case TYPE_NBITS64: return String(hex_double(n)); + case TYPE_NBITS32: return String(hex_double(n), "f"); default: code_err(ast, "This is not a valid number bit width"); } } else if (ast->tag == None) { @@ -2160,7 +2166,7 @@ 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), CORD_asprintf(", %ld", n)); + CORD code = CORD_all("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)); } @@ -2207,8 +2213,8 @@ CORD compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) { // No comprehension: CORD code = CORD_all("Set(", compile_type(item_type), ", ", - compile_type_info(item_type)); - CORD_appendf(&code, ", %zu", n); + 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)); @@ -2274,7 +2280,7 @@ CORD compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) size_t n = 0; for (ast_list_t *entry = table->entries; entry; entry = entry->next) ++n; - CORD_appendf(&code, ", %zu", n); + code = CORD_all(code, ", ", String(n)); for (ast_list_t *entry = table->entries; entry; entry = entry->next) { DeclareMatch(e, entry->ast, TableEntry); @@ -2317,7 +2323,7 @@ CORD compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type) type_t *pointed = Match(pointer_type, PointerType)->pointed; switch (ast->tag) { case HeapAllocate: { - return CORD_asprintf("heap(%r)", compile_to_type(env, Match(ast, HeapAllocate)->value, pointed)); + return CORD_all("heap(", compile_to_type(env, Match(ast, HeapAllocate)->value, pointed), ")"); } case StackReference: { ast_t *subject = Match(ast, StackReference)->value; @@ -2366,13 +2372,13 @@ 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_asprintf("(Byte_t)(%s)", c_literal); + return CORD_all("(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_asprintf("N64(%s)", c_literal); + return CORD_all("N64(", c_literal, ")"); } else { - return CORD_asprintf("N32(%s)", c_literal); + return CORD_all("N32(", c_literal, ")"); } } else if (target->tag == IntType) { int64_t target_bits = (int64_t)Match(target, IntType)->bits; @@ -2381,19 +2387,19 @@ CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target) if (mpz_cmp_si(i, INT64_MIN) == 0) return "I64(INT64_MIN)"; if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) - return CORD_asprintf("I64(%sL)", c_literal); + return CORD_all("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_asprintf("I32(%s)", c_literal); + return CORD_all("I32(", c_literal, ")"); break; case TYPE_IBITS16: if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0) - return CORD_asprintf("I16(%s)", c_literal); + return CORD_all("I16(", c_literal, ")"); break; case TYPE_IBITS8: if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0) - return CORD_asprintf("I8(%s)", c_literal); + return CORD_all("I8(", c_literal, ")"); break; default: break; } @@ -2423,9 +2429,9 @@ 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 = CORD_asprintf("N64(%.20g)", Num$from_int(int_val, false)); + value = String(hex_double(Num$from_int(int_val, false))); else - value = CORD_asprintf("N32(%.10g)", (double)Num32$from_int(int_val, false)); + value = 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); @@ -2450,9 +2456,9 @@ 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 = CORD_asprintf("N64(%.20g)", Num$from_int(int_val, false)); + value = String(hex_double(Num$from_int(int_val, false))); else - value = CORD_asprintf("N32(%.10g)", (double)Num32$from_int(int_val, false)); + value = 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); @@ -2502,7 +2508,7 @@ CORD compile_string_literal(CORD literal) #ifdef __GNUC__ #pragma GCC diagnostic pop #endif - char c = CORD_pos_fetch(i); + uint8_t c = (uint8_t)CORD_pos_fetch(i); switch (c) { case '\\': code = CORD_cat(code, "\\\\"); break; case '"': code = CORD_cat(code, "\\\""); break; @@ -2514,9 +2520,9 @@ CORD compile_string_literal(CORD literal) case '\v': code = CORD_cat(code, "\\v"); break; default: { if (isprint(c)) - code = CORD_cat_char(code, c); + code = CORD_cat_char(code, (char)c); else - CORD_sprintf(&code, "%r\\x%02X\"\"", code, (uint8_t)c); + code = CORD_all(code, "\\x", String(hex((uint64_t)c, .no_prefix=true, .uppercase=true, .digits=2)), "\"\""); break; } } @@ -2717,15 +2723,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_asprintf("I_small(%s)", str); + return CORD_all("I_small(", str, ")"); } else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) { - return CORD_asprintf("Int$from_int64(%s)", str); + return CORD_all("Int$from_int64(", str, ")"); } else { - return CORD_asprintf("Int$from_str(\"%s\")", str); + return CORD_all("Int$from_str(\"", str, "\")"); } } case Num: { - return CORD_asprintf("N64(%.20g)", Match(ast, Num)->n); + return String(hex_double(Match(ast, Num)->n)); } case Not: { ast_t *value = Match(ast, Not)->value; @@ -2783,10 +2789,10 @@ CORD compile(env_t *env, ast_t *ast) CORD value_code = compile(env, value); return CORD_all("({ ", compile_declaration(t, "opt"), " = ", value_code, "; ", "if unlikely (", check_none(t, "opt"), ")\n", - CORD_asprintf("fail_source(%r, %ld, %ld, \"This was expected to be a value, but it's none\");\n", - CORD_quoted(ast->file->filename), - (long)(value->start - value->file->text), - (long)(value->end - value->file->text)), + "fail_source(", CORD_quoted(ast->file->filename), ", ", + String((long)(value->start - value->file->text)), ", ", + String((long)(value->end - value->file->text)), ", ", + "\"This was expected to be a value, but it's none\");\n", optional_into_nonnone(t, "opt"), "; })"); } case Power: case Multiply: case Divide: case Mod: case Mod1: case Plus: case Minus: case Concat: @@ -3032,13 +3038,13 @@ CORD compile(env_t *env, ast_t *ast) } case Lambda: { DeclareMatch(lambda, ast, Lambda); - CORD name = CORD_asprintf("%rlambda$%ld", namespace_prefix(env, env->namespace), lambda->id); + CORD name = CORD_all(namespace_prefix(env, env->namespace), "lambda$", String(lambda->id)); env->code->function_naming = CORD_all( env->code->function_naming, - CORD_asprintf("register_function(%r, Text(\"%s.tm\"), %ld, Text(%r));\n", - name, file_base_name(ast->file->filename), get_line_number(ast->file, ast->start), - CORD_quoted(type_to_cord(get_type(env, ast))))); + "register_function(", name, ", Text(\"", file_base_name(ast->file->filename), ".tm\"), ", + String(get_line_number(ast->file, ast->start)), + ", Text(", CORD_quoted(type_to_cord(get_type(env, ast))), "));\n"); env_t *body_scope = fresh_scope(env); body_scope->deferred = NULL; @@ -3798,10 +3804,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 CORD_all("(", fielded, ")->", f->field); } else { CORD fielded = compile(env, f->fielded); - return CORD_asprintf("(%r).%s", fielded, f->field); + return CORD_all("(", fielded, ").", f->field); } } } @@ -3894,8 +3900,8 @@ CORD compile(env_t *env, ast_t *ast) return CORD_all("List_get_unchecked(", compile_type(item_type), ", ", list, ", ", index_code, ")"); else return CORD_all("List_get(", compile_type(item_type), ", ", list, ", ", index_code, ", ", - CORD_asprintf("%ld", (int64_t)(indexing->index->start - f->text)), ", ", - CORD_asprintf("%ld", (int64_t)(indexing->index->end - f->text)), + String((int64_t)(indexing->index->start - f->text)), ", ", + String((int64_t)(indexing->index->end - f->text)), ")"); } else if (container_t->tag == TableType) { DeclareMatch(table_type, container_t, TableType); @@ -3984,19 +3990,18 @@ CORD compile_type_info(type_t *t) case PointerType: { DeclareMatch(ptr, t, PointerType); CORD sigil = ptr->is_stack ? "&" : "@"; - return CORD_asprintf("Pointer$info(%r, %r)", - CORD_quoted(sigil), - compile_type_info(ptr->pointed)); + return CORD_all("Pointer$info(", CORD_quoted(sigil), ", ", compile_type_info(ptr->pointed), ")"); } case FunctionType: { - return CORD_asprintf("Function$info(%r)", CORD_quoted(type_to_cord(t))); + return CORD_all("Function$info(", CORD_quoted(type_to_cord(t)), ")"); } case ClosureType: { - return CORD_asprintf("Closure$info(%r)", CORD_quoted(type_to_cord(t))); + return CORD_all("Closure$info(", CORD_quoted(type_to_cord(t)), ")"); } case OptionalType: { type_t *non_optional = Match(t, OptionalType)->type; - return CORD_asprintf("Optional$info(sizeof(%r), __alignof__(%r), %r)", compile_type(non_optional), compile_type(non_optional), compile_type_info(non_optional)); + return CORD_all("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"; @@ -4226,7 +4231,7 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) 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 > ", CORD_asprintf("%ld", cache_size.value), + pop_code = CORD_all("if (cache.entries.length > ", String(cache_size.value), ") Table$remove(&cache, cache.entries.data + cache.entries.stride*0, table_type);\n"); } @@ -4255,10 +4260,10 @@ 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_asprintf("((TypeInfo_t[1]){{.size=sizeof(args), .align=__alignof__(args), .metamethods=%s, " - ".tag=StructInfo, .StructInfo.name=\"FunctionArguments\", " - ".StructInfo.num_fields=%ld, .StructInfo.fields=(NamedType_t[%ld]){", - metamethods, num_fields, num_fields); + CORD args_typeinfo = CORD_all("((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 { "; for (arg_t *f = fields; f; f = f->next) { args_typeinfo = CORD_all(args_typeinfo, "{\"", f->name, "\", ", compile_type_info(f->type), "}"); @@ -4303,8 +4308,8 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) if (!is_inline) { env->code->function_naming = CORD_all( env->code->function_naming, - CORD_asprintf("register_function(%r, Text(\"%s.tm\"), %ld, Text(%r));\n", - name_code, file_base_name(ast->file->filename), get_line_number(ast->file, ast->start), CORD_quoted(text))); + "register_function(", name_code, ", Text(\"", file_base_name(ast->file->filename), ".tm\"), ", + String(get_line_number(ast->file, ast->start)), ", Text(", CORD_quoted(text), "));\n"); } return definition; } @@ -4354,7 +4359,7 @@ 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 = CORD_asprintf("%r%s$%ld", namespace_prefix(env, env->namespace), name, get_line_number(ast->file, ast->start)); + CORD name_code = CORD_all(namespace_prefix(env, env->namespace), name, "$", String(get_line_number(ast->file, ast->start))); return compile_function(env, name_code, ast, &env->code->staticdefs); } case StructDef: { @@ -4374,9 +4379,9 @@ CORD compile_top_level_code(env_t *env, ast_t *ast) } case LangDef: { DeclareMatch(def, ast, LangDef); - CORD code = CORD_asprintf("public const TypeInfo_t %r%s$$info = {%zu, %zu, .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={%r}};\n", - namespace_prefix(env, env->namespace), def->name, sizeof(Text_t), __alignof__(Text_t), - CORD_quoted(def->name)); + CORD code = CORD_all("public const TypeInfo_t ", namespace_prefix(env, env->namespace), + def->name, "$$info = {", String(sizeof(Text_t)), ", ", String(__alignof__(Text_t)), + ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", CORD_quoted(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); } @@ -4637,7 +4642,7 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a ret_type_code = CORD_all("__attribute__((noreturn)) _Noreturn ", ret_type_code); CORD name = CORD_all(namespace_prefix(env, env->namespace), decl_name); if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name)) - name = CORD_asprintf("%r%ld", namespace_prefix(env, env->namespace), get_line_number(ast->file, ast->start)); + name = CORD_all(namespace_prefix(env, env->namespace), String(get_line_number(ast->file, ast->start))); return CORD_all(ret_type_code, " ", name, arg_signature, ";\n"); } case ConvertDef: { @@ -4657,7 +4662,7 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a if (!name) code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t)); name = CORD_all(namespace_prefix(env, env->namespace), name); - CORD name_code = CORD_asprintf("%r$%ld", name, get_line_number(ast->file, ast->start)); + CORD name_code = CORD_all(name, "$", String(get_line_number(ast->file, ast->start))); return CORD_all(ret_type_code, " ", name_code, arg_signature, ";\n"); } default: return CORD_EMPTY; diff --git a/src/cordhelpers.c b/src/cordhelpers.c index 1bff9e9c..353a52d9 100644 --- a/src/cordhelpers.c +++ b/src/cordhelpers.c @@ -1,21 +1,12 @@ // Some helper functions for the GC Cord library #include <gc/cord.h> -#include <stdarg.h> +#include <stdint.h> +#include "cordhelpers.h" +#include "stdlib/print.h" #include "stdlib/util.h" -__attribute__((format(printf, 1, 2))) -public CORD CORD_asprintf(CORD fmt, ...) -{ - va_list args; - va_start(args, fmt); - CORD c = NULL; - CORD_vsprintf(&c, fmt, args); - va_end(args); - return c; -} - public CORD CORD_quoted(CORD str) { CORD quoted = "\""; @@ -42,7 +33,7 @@ public CORD CORD_quoted(CORD str) case '\\': quoted = CORD_cat(quoted, "\\\\"); break; case '\x00' ... '\x06': case '\x0E' ... '\x1A': case '\x1C' ... '\x1F': case '\x7F' ... '\x7F': - CORD_sprintf("ed, "%r\\x%02X", quoted, c); + 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; } diff --git a/src/cordhelpers.h b/src/cordhelpers.h index a1638869..b519a443 100644 --- a/src/cordhelpers.h +++ b/src/cordhelpers.h @@ -3,11 +3,8 @@ #include <gc/cord.h> -#define CORD_appendf(cord, fmt, ...) CORD_sprintf(cord, "%r" fmt, *(cord), __VA_ARGS__) #define CORD_all(...) CORD_catn(sizeof((CORD[]){__VA_ARGS__})/sizeof(CORD), __VA_ARGS__) -__attribute__((format(printf, 1, 2))) -CORD CORD_asprintf(CORD fmt, ...); CORD CORD_quoted(CORD str); CORD CORD_replace(CORD c, CORD to_replace, CORD replacement); diff --git a/src/enums.c b/src/enums.c index ac21bdda..36b5f97f 100644 --- a/src/enums.c +++ b/src/enums.c @@ -36,9 +36,10 @@ 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 typeinfo = CORD_asprintf("public const TypeInfo_t %r$$info = {%zu, %zu, .metamethods=%s, {.tag=EnumInfo, .EnumInfo={.name=\"%s\", " - ".num_tags=%d, .tags=(NamedType_t[]){", - full_name, type_size(t), type_align(t), metamethods, def->name, num_tags); + CORD typeinfo = CORD_all("public const TypeInfo_t ", full_name, "$$info = {", + String(type_size(t)), "u, ", String(type_align(t)), "u, .metamethods=", metamethods, + ", {.tag=EnumInfo, .EnumInfo={.name=\"", def->name, "\", " + ".num_tags=", String(num_tags), ", .tags=(NamedType_t[]){"); for (tag_ast_t *tag = def->tags; tag; tag = tag->next) { const char *tag_type_name = String(def->name, "$", tag->name); diff --git a/src/stdlib/fpconv.h b/src/stdlib/fpconv.h index 360c1f96..1d3dd813 100644 --- a/src/stdlib/fpconv.h +++ b/src/stdlib/fpconv.h @@ -24,7 +24,7 @@ * int str_len = fpconv_dtoa(d, buf); * * buf[str_len] = '\0'; - * printf("%s", buf); + * puts(buf); * } * */ diff --git a/src/stdlib/integers.c b/src/stdlib/integers.c index 86cdeb56..7250e2a2 100644 --- a/src/stdlib/integers.c +++ b/src/stdlib/integers.c @@ -32,11 +32,10 @@ static inline Text_t _int64_to_text(int64_t n) char *p = &buf[19]; bool negative = n < 0; - if (n == 0) - *(p--) = '0'; - - for (; n > 0; n /= 10) + do { *(p--) = '0' + (n % 10); + n /= 10; + } while (n > 0); if (negative) *(p--) = '-'; diff --git a/src/stdlib/print.c b/src/stdlib/print.c index df10a54f..3270c765 100644 --- a/src/stdlib/print.c +++ b/src/stdlib/print.c @@ -14,11 +14,10 @@ public int _print_int(FILE *f, int64_t n) char *p = &buf[19]; bool negative = n < 0; - if (n == 0) - *(p--) = '0'; - - for (; n > 0; n /= 10) + do { *(p--) = '0' + (n % 10); + n /= 10; + } while (n > 0); if (negative) *(p--) = '-'; @@ -31,11 +30,10 @@ public int _print_uint(FILE *f, uint64_t n) char buf[21] = {[20]=0}; // Big enough for UINT64_MAX + '\0' char *p = &buf[19]; - if (n == 0) - *(p--) = '0'; - - for (; n > 0; n /= 10) + do { *(p--) = '0' + (n % 10); + n /= 10; + } while (n > 0); return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f); } @@ -54,15 +52,16 @@ public int _print_hex(FILE *f, hex_format_t hex) } char buf[9] = {[8]='\0'}; // Enough space for FFFFFFFF + '\0' char *p = &buf[7]; - for (uint64_t n = hex.n; n > 0; n /= 16) { - uint8_t digit = n % 16; + do { + uint8_t digit = hex.n % 16; if (digit <= 9) *(p--) = '0' + digit; else if (hex.uppercase) *(p--) = 'A' + digit - 10; else *(p--) = 'a' + digit - 10; - } + hex.n /= 16; + } while (hex.n > 0); printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[7] - p), f); return printed; } @@ -72,18 +71,17 @@ public int _print_oct(FILE *f, oct_format_t oct) int printed = 0; if (!oct.no_prefix) printed += fputs("0o", f); if (oct.digits > 0) { - for (uint64_t n = oct.n; n > 0 && oct.digits > 0; n /= 8) { + for (uint64_t n = oct.n; n > 0 && oct.digits > 0; n /= 8) oct.digits -= 1; - } - for (; oct.digits > 0; oct.digits -= 1) { + for (; oct.digits > 0; oct.digits -= 1) printed += fputc('0', f); - } } char buf[12] = {[11]='\0'}; // Enough space for octal UINT64_MAX + '\0' char *p = &buf[10]; - for (uint64_t n = oct.n; n > 0; n /= 8) { - *(p--) = '0' + (n % 8); - } + do { + *(p--) = '0' + (oct.n % 8); + oct.n /= 8; + } while (oct.n > 0); printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[10] - p), f); return printed; } @@ -95,6 +93,74 @@ public int _print_double(FILE *f, double n) return (int)fwrite(buf, sizeof(char), (size_t)len, f); } +public int _print_hex_double(FILE *f, hex_double_t hex) +{ + if (hex.d != hex.d) + return fputs("NAN", f); + else if (hex.d == 1.0/0.0) + return fputs("INF", f); + else if (hex.d == -1.0/0.0) + return fputs("-INF", f); + else if (hex.d == 0.0) + return fputs("0.0", f); + + union { double d; uint64_t u; } bits = { .d = hex.d }; + + int sign = (bits.u >> 63) & 1ull; + int exp = (int)((bits.u >> 52) & 0x7FF) - 1023ull; + uint64_t frac = bits.u & 0xFFFFFFFFFFFFFull; + + char buf[25]; + char *p = buf; + + if (sign) *p++ = '-'; + *p++ = '0'; + *p++ = 'x'; + + uint64_t mantissa = (1ull << 52) | frac; // implicit 1 + int mantissa_shift = 52; + + while ((mantissa & 0xF) == 0 && mantissa_shift > 0) { + mantissa >>= 4; + mantissa_shift -= 4; + } + + uint64_t int_part = mantissa >> mantissa_shift; + *p++ = "0123456789abcdef"[int_part]; + + *p++ = '.'; + + while (mantissa_shift > 0) { + mantissa_shift -= 4; + uint64_t digit = (mantissa >> mantissa_shift) & 0xF; + *p++ = "0123456789abcdef"[digit]; + } + + *p++ = 'p'; + + if (exp >= 0) { + *p++ = '+'; + } else { + *p++ = '-'; + exp = -exp; + } + + char expbuf[6]; + int ei = 5; + expbuf[ei--] = '\0'; + do { + expbuf[ei--] = '0' + (exp % 10); + exp /= 10; + } while (exp && ei >= 0); + + ei++; + while (expbuf[ei]) + *p++ = expbuf[ei++]; + + *p = '\0'; + return fwrite(buf, sizeof(char), (size_t)(p - buf), f); +} + public int _print_char(FILE *f, char c) { #define ESC(e) "'\\" e "'" diff --git a/src/stdlib/print.h b/src/stdlib/print.h index 454ef6b8..9bd89aea 100644 --- a/src/stdlib/print.h +++ b/src/stdlib/print.h @@ -43,6 +43,11 @@ typedef struct { #define hex(x, ...) ((hex_format_t){.n=x, __VA_ARGS__}) typedef struct { + double d; +} hex_double_t; +#define hex_double(x, ...) ((hex_double_t){.d=x, __VA_ARGS__}) + +typedef struct { uint64_t n; bool no_prefix; int digits; @@ -76,6 +81,7 @@ int _print_int(FILE *f, int64_t x); int _print_uint(FILE *f, uint64_t x); int _print_double(FILE *f, double x); int _print_hex(FILE *f, hex_format_t hex); +int _print_hex_double(FILE *f, hex_double_t hex); int _print_oct(FILE *f, oct_format_t oct); PRINT_FN _print_float(FILE *f, float x) { return _print_double(f, (double)x); } PRINT_FN _print_pointer(FILE *f, void *p) { return _print_hex(f, hex((uint64_t)p)); } @@ -111,6 +117,7 @@ extern int Int$print(FILE *f, Int_t i); float: _print_float, \ double: _print_double, \ hex_format_t: _print_hex, \ + hex_double_t: _print_hex_double, \ oct_format_t: _print_oct, \ quoted_t: _print_quoted, \ string_slice_t: _print_string_slice, \ diff --git a/src/structs.c b/src/structs.c index 401fcb7a..0735d474 100644 --- a/src/structs.c +++ b/src/structs.c @@ -25,14 +25,15 @@ 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_asprintf("public const TypeInfo_t %r = {.size=sizeof(%r), .align=__alignof__(%r), .metamethods=%s, " - ".tag=StructInfo, .StructInfo.name=\"%s\"%s%s, " - ".StructInfo.num_fields=%ld", - typeinfo_name, type_code, type_code, metamethods, short_name, is_secret ? ", .StructInfo.is_secret=true" : "", - is_opaque ? ", .StructInfo.is_opaque=true" : "", - num_fields); + CORD typeinfo = CORD_all("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, + ", .StructInfo.num_fields=", String(num_fields)); if (fields) { - typeinfo = CORD_asprintf("%r, .StructInfo.fields=(NamedType_t[%d]){", typeinfo, num_fields); + typeinfo = CORD_all(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), "}"); @@ -64,7 +65,7 @@ CORD compile_struct_header(env_t *env, ast_t *ast) CORD struct_code = def->external ? CORD_EMPTY : CORD_all(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, ")") : CORD_asprintf("%zu", unpadded_struct_size(t)); + CORD unpadded_size = def->opaque ? CORD_all("sizeof(", type_code, ")") : String(unpadded_struct_size(t)); CORD typeinfo_code = CORD_all("extern const TypeInfo_t ", typeinfo_name, ";\n"); CORD optional_code = CORD_EMPTY; if (!def->opaque) { @@ -68,7 +68,7 @@ static OptionalBool_t verbose = false, static OptionalText_t show_codegen = NONE_TEXT, - cflags = Text("-Werror -fdollars-in-identifiers -std=c2x -Wno-trigraphs -Wno-parentheses-equality " + cflags = Text("-Werror -fdollars-in-identifiers -std=c2x -Wno-trigraphs " " -ffunction-sections -fdata-sections" " -fno-signed-zeros -fno-finite-math-only " " -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -fPIC -ggdb" @@ -211,6 +211,11 @@ int main(int argc, char *argv[]) " -fno-signaling-nans -fno-trapping-math")); } + bool is_clang = (system(String(cc, " -v 2>&1 | grep -q 'clang version'")) == 0); + if (is_clang) { + cflags = Texts(cflags, Text(" -Wno-parentheses-equality")); + } + #ifdef __APPLE__ cflags = Texts(cflags, Text(" -I/opt/homebrew/include")); ldflags = Texts(ldflags, Text(" -L/opt/homebrew/lib -Wl,-rpath,/opt/homebrew/lib")); @@ -432,7 +437,7 @@ static void _compile_file_header_for_library(env_t *env, Path_t header_path, Pat visit_topologically( Match(file_ast, Block)->statements, (Closure_t){.fn=(void*)_compile_statement_header_for_library, &info}); - CORD_fprintf(output, "void %r$initialize(void);\n", namespace_prefix(module_env, module_env->namespace)); + CORD_put(CORD_all("void ", namespace_prefix(module_env, module_env->namespace), "$initialize(void);\n"), output); } void build_library(Path_t lib_dir) @@ -445,7 +450,7 @@ void build_library(Path_t lib_dir) List_t tm_files = Path$glob(Path$with_component(lib_dir, Text("[!._0-9]*.tm"))); env_t *env = fresh_scope(global_env(source_mapping)); List_t object_files = {}, - extra_ldlibs = {}; + extra_ldlibs = {}; compile_files(env, tm_files, &object_files, &extra_ldlibs); diff --git a/src/typecheck.c b/src/typecheck.c index f255f348..6c483511 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -340,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 = CORD_asprintf("%r%r$%ld", namespace_prefix(env, env->namespace), name, - get_line_number(statement->file, statement->start)); + CORD code = CORD_all(namespace_prefix(env, env->namespace), 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)); diff --git a/src/types.c b/src/types.c index dd76258d..e1ada1f8 100644 --- a/src/types.c +++ b/src/types.c @@ -9,6 +9,7 @@ #include "cordhelpers.h" #include "environment.h" #include "stdlib/integers.h" +#include "stdlib/print.h" #include "stdlib/tables.h" #include "stdlib/util.h" #include "types.h" @@ -31,11 +32,11 @@ CORD type_to_cord(type_t *t) { case CStringType: return "CString"; 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 IntType: return String("Int", Match(t, IntType)->bits); case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? "Num32" : "Num"; case ListType: { DeclareMatch(list, t, ListType); - return CORD_asprintf("[%r]", type_to_cord(list->item_type)); + return CORD_all("[", type_to_cord(list->item_type), "]"); } case TableType: { DeclareMatch(table, t, TableType); @@ -43,7 +44,7 @@ CORD type_to_cord(type_t *t) { } case SetType: { DeclareMatch(set, t, SetType); - return CORD_asprintf("{%r}", type_to_cord(set->item_type)); + return CORD_all("{", type_to_cord(set->item_type), "}"); } case ClosureType: { return type_to_cord(Match(t, ClosureType)->fn); @@ -88,7 +89,7 @@ CORD type_to_cord(type_t *t) { } default: { raise(SIGABRT); - return CORD_asprintf("Unknown type: %d", t->tag); + return String("Unknown type: ", t->tag); } } } |
