diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-09-21 16:54:36 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-09-21 16:54:36 -0400 |
| commit | 1cec086a6034ad546977cae7aeaf4bb876d21970 (patch) | |
| tree | cd2889aea7ca830359ba329a3f82b96e706bcdee | |
| parent | 0ab878ff4f72f7f6f6f64c1fc5d8023cd19fbe82 (diff) | |
Deprecate `>> x ... = val` form of doctests and rename them to 'debugdoctests-to-debuglog
logs', also add multi-expression support
| -rw-r--r-- | CHANGES.md | 2 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | src/ast.c | 9 | ||||
| -rw-r--r-- | src/ast.h | 7 | ||||
| -rw-r--r-- | src/compile/README.md | 2 | ||||
| -rw-r--r-- | src/compile/compilation.h | 2 | ||||
| -rw-r--r-- | src/compile/debuglog.c | 115 | ||||
| -rw-r--r-- | src/compile/debuglog.h (renamed from src/compile/doctests.h) | 4 | ||||
| -rw-r--r-- | src/compile/doctests.c | 118 | ||||
| -rw-r--r-- | src/compile/expressions.c | 2 | ||||
| -rw-r--r-- | src/compile/functions.c | 5 | ||||
| -rw-r--r-- | src/compile/statements.c | 2 | ||||
| -rw-r--r-- | src/formatter/formatter.c | 16 | ||||
| -rw-r--r-- | src/formatter/utils.c | 8 | ||||
| -rw-r--r-- | src/parse/statements.c | 25 | ||||
| -rw-r--r-- | src/parse/statements.h | 2 | ||||
| -rw-r--r-- | src/stdlib/stdlib.c | 38 | ||||
| -rw-r--r-- | src/stdlib/stdlib.h | 8 | ||||
| -rw-r--r-- | src/typecheck.c | 12 |
19 files changed, 169 insertions, 210 deletions
@@ -16,6 +16,8 @@ - Use `C_code` instead. - Deprecated the postfix `?` to make values optional. - Explicitly optional values can be declared as `my_var : T? = value`. +- Deprecated `>> ... = ...` form of doctests. They are now called "debug logs" + and you can specify multiple values: `>> a, b, c` - Added a `--format` flag to the `tomo` binary that autoformats your code (currently unstable, do not rely on it just yet). - Standardized text methods for Unicode encodings: @@ -78,7 +78,7 @@ are implemented in Tomo. [text](docs/text.md). - Full-featured [libraries/modules](docs/libraries.md) - [Full UTF8 support](docs/text.md) for all text operations -- Built-in doctests with syntax highlighting +- Built-in debugging prints with syntax highlighting - [Automatic command line argument parsing with type safety](docs/command-line-parsing.md) - [Easy interoperability with C](docs/c-interoperability.md) - Built-in [data serialization and deserialization](docs/serialization.md). @@ -270,7 +270,7 @@ Text_t ast_to_sexp(ast_t *ast) { T(Index, "(Index ", ast_to_sexp(data.indexed), " ", ast_to_sexp(data.index), ")"); T(FieldAccess, "(FieldAccess ", ast_to_sexp(data.fielded), " \"", data.field, "\")"); T(NonOptional, "(NonOptional ", ast_to_sexp(data.value), ")"); - T(DocTest, "(DocTest ", ast_to_sexp(data.expr), optional_sexp("expected", data.expected), ")"); + T(DebugLog, "(DebugLog ", ast_list_to_sexp(data.values), ")"); T(Assert, "(Assert ", ast_to_sexp(data.expr), " ", optional_sexp("message", data.message), ")"); T(Use, "(Use ", optional_sexp("var", data.var), " ", quoted_text(data.path), ")"); T(InlineCCode, "(InlineCCode ", ast_list_to_sexp(data.chunks), optional_type_sexp("type", data.type_ast), ")"); @@ -658,10 +658,9 @@ void ast_visit(ast_t *ast, void (*visitor)(ast_t *, void *), void *userdata) { ast_visit(Match(ast, NonOptional)->value, visitor, userdata); return; } - case DocTest: { - DeclareMatch(test, ast, DocTest); - ast_visit(test->expr, visitor, userdata); - ast_visit(test->expected, visitor, userdata); + case DebugLog: { + DeclareMatch(show, ast, DebugLog); + ast_visit_list(show->values, visitor, userdata); return; } case Assert: { @@ -270,7 +270,7 @@ typedef enum { Index, FieldAccess, NonOptional, - DocTest, + DebugLog, Assert, Use, InlineCCode, @@ -439,9 +439,8 @@ struct ast_s { ast_t *value; } NonOptional; struct { - ast_t *expr, *expected; - bool skip_source : 1; - } DocTest; + ast_list_t *values; + } DebugLog; struct { ast_t *expr, *message; } Assert; diff --git a/src/compile/README.md b/src/compile/README.md index df76d648..7a841231 100644 --- a/src/compile/README.md +++ b/src/compile/README.md @@ -11,7 +11,7 @@ This directory contains the source files for actual cross-compilation - Comparisons (`a == b`, `a > b`, etc): [comparisons.c](comparisons.c) - Conditionals (`if` statements): [conditionals.c](conditionals.c) - Variable declarations: [declarations.c](declarations.c) -- Doctests (`>> test`): [doctests.c](doctests.c) +- Debug logs (`>> expr`): [debuglog.c](debuglog.c) - Enums (`enum`): [enums.c](enums.c) - General logic for compiling expressions: [expressions.c](expressions.c) - Field accesses (`foo.baz`) [fieldaccess.c](fieldaccess.c) diff --git a/src/compile/compilation.h b/src/compile/compilation.h index d881684b..5c949836 100644 --- a/src/compile/compilation.h +++ b/src/compile/compilation.h @@ -10,8 +10,8 @@ #include "comparisons.h" // IWYU pragma: export #include "compilation.h" // IWYU pragma: export #include "conditionals.h" // IWYU pragma: export +#include "debuglog.h" // IWYU pragma: export #include "declarations.h" // IWYU pragma: export -#include "doctests.h" // IWYU pragma: export #include "enums.h" // IWYU pragma: export #include "expressions.h" // IWYU pragma: export #include "fieldaccess.h" // IWYU pragma: export diff --git a/src/compile/debuglog.c b/src/compile/debuglog.c new file mode 100644 index 00000000..498820ee --- /dev/null +++ b/src/compile/debuglog.c @@ -0,0 +1,115 @@ +// This file defines how to compile debug_log + +#include "../ast.h" +#include "../config.h" +#include "../environment.h" +#include "../stdlib/datatypes.h" +#include "../stdlib/text.h" +#include "../stdlib/util.h" +#include "../typecheck.h" +#include "compilation.h" + +public +Text_t compile_debug_log(env_t *env, ast_t *ast) { + DeclareMatch(debug, ast, DebugLog); + Text_t code = EMPTY_TEXT; + for (ast_list_t *value = debug->values; value; value = value->next) { + type_t *expr_t = get_type(env, value->ast); + if (!expr_t) code_err(value->ast, "I couldn't figure out the type of this expression"); + + Text_t setup = EMPTY_TEXT; + Text_t value_code; + if (value->ast->tag == Declare) { + DeclareMatch(decl, value->ast, Declare); + type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); + if (t->tag == FunctionType) t = Type(ClosureType, t); + Text_t var = Texts("_$", Match(decl->var, Var)->name); + Text_t val_code = compile_declared_value(env, value->ast); + setup = Texts(compile_declaration(t, var), ";\n"); + value_code = Texts("(", var, " = ", val_code, ")"); + expr_t = t; + } else if (value->ast->tag == Assign) { + DeclareMatch(assign, value->ast, Assign); + if (!assign->targets->next && assign->targets->ast->tag == Var && is_idempotent(assign->targets->ast)) { + // Common case: assigning to one variable: + type_t *lhs_t = get_type(env, assign->targets->ast); + if (assign->targets->ast->tag == Index && lhs_t->tag == OptionalType + && value_type(get_type(env, Match(assign->targets->ast, Index)->indexed))->tag == TableType) + lhs_t = Match(lhs_t, OptionalType)->type; + if (has_stack_memory(lhs_t)) + code_err(value->ast, "Stack references cannot be assigned " + "to variables because the " + "variable's scope may outlive the " + "scope of the stack memory."); + env_t *val_scope = with_enum_scope(env, lhs_t); + value_code = Texts("(", + compile_assignment(env, assign->targets->ast, + compile_to_type(val_scope, assign->values->ast, lhs_t)), + ")"); + expr_t = lhs_t; + } else { + // Multi-assign or assignment to potentially non-idempotent + // targets + value_code = Text("({ // Assignment\n"); + + int64_t i = 1; + for (ast_list_t *target = assign->targets, *assign_value = assign->values; target && assign_value; + target = target->next, assign_value = assign_value->next) { + type_t *lhs_t = get_type(env, target->ast); + if (target->ast->tag == Index && lhs_t->tag == OptionalType + && value_type(get_type(env, Match(target->ast, Index)->indexed))->tag == TableType) + lhs_t = Match(lhs_t, OptionalType)->type; + if (has_stack_memory(lhs_t)) + code_err(ast, "Stack references cannot be assigned to " + "variables because the " + "variable's scope may outlive the scope " + "of the stack memory."); + if (target == assign->targets) expr_t = lhs_t; + env_t *val_scope = with_enum_scope(env, lhs_t); + Text_t val_code = compile_to_type(val_scope, assign_value->ast, lhs_t); + value_code = Texts(value_code, compile_type(lhs_t), " $", i, " = ", val_code, ";\n"); + i += 1; + } + i = 1; + for (ast_list_t *target = assign->targets; target; target = target->next) { + value_code = Texts(value_code, compile_assignment(env, target->ast, Texts("$", i)), ";\n"); + i += 1; + } + + value_code = Texts(value_code, "$1; })"); + } + } else if (is_update_assignment(value->ast)) { + binary_operands_t update = UPDATE_OPERANDS(value->ast); + type_t *lhs_t = get_type(env, update.lhs); + if (update.lhs->tag == Index) { + type_t *indexed = value_type(get_type(env, Match(update.lhs, Index)->indexed)); + if (indexed->tag == TableType && Match(indexed, TableType)->default_value == NULL) + code_err(update.lhs, "Update assignments are not currently " + "supported for tables"); + } + + ast_t *update_var = new (ast_t); + *update_var = *value->ast; + update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type = lhs_t); // UNSAFE + value_code = + Texts("({", compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(", + compile_lvalue(env, update.lhs), "); ", compile_statement(env, update_var), "; *expr; })"); + expr_t = lhs_t; + } else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) { + value_code = Texts("({", compile_statement(env, value->ast), " NULL;})"); + } else { + value_code = compile(env, value->ast); + } + if (expr_t->tag == VoidType || expr_t->tag == AbortType) { + value_code = Texts(setup, "inspect_void(", value_code, ", ", compile_type_info(expr_t), ", ", + (int64_t)(value->ast->start - value->ast->file->text), ", ", + (int64_t)(value->ast->end - value->ast->file->text), ");"); + } else { + value_code = Texts(setup, "inspect(", compile_type(expr_t), ", ", value_code, ", ", + compile_type_info(expr_t), ", ", (int64_t)(value->ast->start - value->ast->file->text), + ", ", (int64_t)(value->ast->end - value->ast->file->text), ");"); + } + code = Texts(code, value_code); + } + return code; +} diff --git a/src/compile/doctests.h b/src/compile/debuglog.h index 06603e1a..30b14776 100644 --- a/src/compile/doctests.h +++ b/src/compile/debuglog.h @@ -1,4 +1,4 @@ -// This file defines how to compile doctests +// This file defines how to compile debug logs #pragma once @@ -6,4 +6,4 @@ #include "../environment.h" #include "../stdlib/datatypes.h" -Text_t compile_doctest(env_t *env, ast_t *ast); +Text_t compile_debug_log(env_t *env, ast_t *ast); diff --git a/src/compile/doctests.c b/src/compile/doctests.c deleted file mode 100644 index 20081ae7..00000000 --- a/src/compile/doctests.c +++ /dev/null @@ -1,118 +0,0 @@ -// This file defines how to compile doctests - -#include "../ast.h" -#include "../config.h" -#include "../environment.h" -#include "../stdlib/datatypes.h" -#include "../stdlib/text.h" -#include "../stdlib/util.h" -#include "../typecheck.h" -#include "compilation.h" - -public -Text_t compile_doctest(env_t *env, ast_t *ast) { - DeclareMatch(test, ast, DocTest); - type_t *expr_t = get_type(env, test->expr); - if (!expr_t) code_err(test->expr, "I couldn't figure out the type of this expression"); - - Text_t setup = EMPTY_TEXT; - Text_t test_code; - if (test->expr->tag == Declare) { - DeclareMatch(decl, test->expr, Declare); - type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); - if (t->tag == FunctionType) t = Type(ClosureType, t); - Text_t var = Texts("_$", Match(decl->var, Var)->name); - Text_t val_code = compile_declared_value(env, test->expr); - setup = Texts(compile_declaration(t, var), ";\n"); - test_code = Texts("(", var, " = ", val_code, ")"); - expr_t = t; - } else if (test->expr->tag == Assign) { - DeclareMatch(assign, test->expr, Assign); - if (!assign->targets->next && assign->targets->ast->tag == Var && is_idempotent(assign->targets->ast)) { - // Common case: assigning to one variable: - type_t *lhs_t = get_type(env, assign->targets->ast); - if (assign->targets->ast->tag == Index && lhs_t->tag == OptionalType - && value_type(get_type(env, Match(assign->targets->ast, Index)->indexed))->tag == TableType) - lhs_t = Match(lhs_t, OptionalType)->type; - if (has_stack_memory(lhs_t)) - code_err(test->expr, "Stack references cannot be assigned " - "to variables because the " - "variable's scope may outlive the " - "scope of the stack memory."); - env_t *val_scope = with_enum_scope(env, lhs_t); - Text_t value = compile_to_type(val_scope, assign->values->ast, lhs_t); - test_code = Texts("(", compile_assignment(env, assign->targets->ast, value), ")"); - expr_t = lhs_t; - } else { - // Multi-assign or assignment to potentially non-idempotent - // targets - if (test->expected && assign->targets->next) - code_err(ast, "Sorry, but doctesting with '=' is not " - "supported for " - "multi-assignments"); - - test_code = Text("({ // Assignment\n"); - - int64_t i = 1; - for (ast_list_t *target = assign->targets, *value = assign->values; target && value; - target = target->next, value = value->next) { - type_t *lhs_t = get_type(env, target->ast); - if (target->ast->tag == Index && lhs_t->tag == OptionalType - && value_type(get_type(env, Match(target->ast, Index)->indexed))->tag == TableType) - lhs_t = Match(lhs_t, OptionalType)->type; - if (has_stack_memory(lhs_t)) - code_err(ast, "Stack references cannot be assigned to " - "variables because the " - "variable's scope may outlive the scope " - "of the stack memory."); - if (target == assign->targets) expr_t = lhs_t; - env_t *val_scope = with_enum_scope(env, lhs_t); - Text_t val_code = compile_to_type(val_scope, value->ast, lhs_t); - test_code = Texts(test_code, compile_type(lhs_t), " $", i, " = ", val_code, ";\n"); - i += 1; - } - i = 1; - for (ast_list_t *target = assign->targets; target; target = target->next) { - test_code = Texts(test_code, compile_assignment(env, target->ast, Texts("$", i)), ";\n"); - i += 1; - } - - test_code = Texts(test_code, "$1; })"); - } - } else if (is_update_assignment(test->expr)) { - binary_operands_t update = UPDATE_OPERANDS(test->expr); - type_t *lhs_t = get_type(env, update.lhs); - if (update.lhs->tag == Index) { - type_t *indexed = value_type(get_type(env, Match(update.lhs, Index)->indexed)); - if (indexed->tag == TableType && Match(indexed, TableType)->default_value == NULL) - code_err(update.lhs, "Update assignments are not currently " - "supported for tables"); - } - - ast_t *update_var = new (ast_t); - *update_var = *test->expr; - update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type = lhs_t); // UNSAFE - test_code = Texts("({", compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(", - compile_lvalue(env, update.lhs), "); ", compile_statement(env, update_var), "; *expr; })"); - expr_t = lhs_t; - } else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) { - test_code = Texts("({", compile_statement(env, test->expr), " NULL;})"); - } else { - test_code = compile(env, test->expr); - } - if (test->expected) { - return Texts(setup, "test(", 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), ");"); - } else { - if (expr_t->tag == VoidType || expr_t->tag == AbortType) { - return Texts(setup, "inspect_void(", 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 Texts(setup, "inspect(", 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), ");"); - } -} diff --git a/src/compile/expressions.c b/src/compile/expressions.c index f4326b00..a4603cd5 100644 --- a/src/compile/expressions.c +++ b/src/compile/expressions.c @@ -249,7 +249,7 @@ Text_t compile(env_t *env, ast_t *ast) { case Stop: case Pass: case Return: - case DocTest: + case DebugLog: case Assert: code_err(ast, "This is not a valid expression"); case Unknown: default: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast)); diff --git a/src/compile/functions.c b/src/compile/functions.c index 5f6f7e91..eea46ebf 100644 --- a/src/compile/functions.c +++ b/src/compile/functions.c @@ -556,8 +556,9 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, NonOptional)->value); break; } - case DocTest: { - add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, DocTest)->expr); + case DebugLog: { + for (ast_list_t *value = Match(ast, DebugLog)->values; value; value = value->next) + add_closed_vars(closed_vars, enclosing_scope, env, value->ast); break; } case Assert: { diff --git a/src/compile/statements.c b/src/compile/statements.c index a7705adc..37eff680 100644 --- a/src/compile/statements.c +++ b/src/compile/statements.c @@ -36,7 +36,7 @@ static Text_t compile_simple_update_assignment(env_t *env, ast_t *ast, const cha static Text_t _compile_statement(env_t *env, ast_t *ast) { switch (ast->tag) { case When: return compile_when_statement(env, ast); - case DocTest: return compile_doctest(env, ast); + case DebugLog: return compile_debug_log(env, ast); case Assert: return compile_assertion(env, ast); case Declare: { DeclareMatch(decl, ast, Declare); diff --git a/src/formatter/formatter.c b/src/formatter/formatter.c index 69c1a213..42204b01 100644 --- a/src/formatter/formatter.c +++ b/src/formatter/formatter.c @@ -119,7 +119,7 @@ OptionalText_t format_inline_code(ast_t *ast, Table_t comments) { /*inline*/ case Extend: /*inline*/ case FunctionDef: /*inline*/ case ConvertDef: - /*inline*/ case DocTest: + /*inline*/ case DebugLog: return NONE_TEXT; /*inline*/ case Assert: { DeclareMatch(assert, ast, Assert); @@ -775,13 +775,13 @@ Text_t format_code(ast_t *ast, Table_t comments, Text_t indent) { return Texts(termify(call->self, comments, indent), ".", Text$from_str(call->name), "(", args, Text$has(args, Text("\n")) ? Texts("\n", indent) : EMPTY_TEXT, ")"); } - /*multiline*/ case DocTest: { - DeclareMatch(test, ast, DocTest); - Text_t expr = fmt(test->expr, comments, indent); - Text_t code = Texts(">> ", expr); - if (test->expected) { - Text_t expected = fmt(test->expected, comments, indent); - code = Texts(code, "\n", indent, "= ", expected); + /*multiline*/ case DebugLog: { + DeclareMatch(debug, ast, DebugLog); + Text_t code = Texts(">> "); + for (ast_list_t *value = debug->values; value; value = value->next) { + Text_t expr = fmt(value->ast, comments, indent); + code = Texts(code, expr); + if (value->next) code = Texts(code, ", "); } return code; } diff --git a/src/formatter/utils.c b/src/formatter/utils.c index bbe74d7f..9cd0227d 100644 --- a/src/formatter/utils.c +++ b/src/formatter/utils.c @@ -44,16 +44,16 @@ CONSTFUNC int suggested_blank_lines(ast_t *first, ast_t *second) { for (;;) { if (first->tag == Declare && Match(first, Declare)->value) { first = Match(first, Declare)->value; - } else if (first->tag == DocTest && Match(first, DocTest)->expr && Match(first, DocTest)->expected == NULL) { - first = Match(first, DocTest)->expr; + } else if (first->tag == DebugLog) { + return 1; } else break; } for (;;) { if (second->tag == Declare && Match(second, Declare)->value) { second = Match(second, Declare)->value; - } else if (second->tag == DocTest && Match(second, DocTest)->expr && Match(second, DocTest)->expected == NULL) { - second = Match(second, DocTest)->expr; + } else if (second->tag == DebugLog) { + return 1; } else break; } diff --git a/src/parse/statements.c b/src/parse/statements.c index 9606acdc..c767ae0b 100644 --- a/src/parse/statements.c +++ b/src/parse/statements.c @@ -2,7 +2,6 @@ #include <gc.h> #include <stdbool.h> -#include <string.h> #include "../ast.h" #include "../stdlib/util.h" @@ -96,20 +95,24 @@ ast_t *parse_update(parse_ctx_t *ctx, const char *pos) { .__data.PlusUpdate.rhs = rhs); } -ast_t *parse_doctest(parse_ctx_t *ctx, const char *pos) { +ast_t *parse_debug_log(parse_ctx_t *ctx, const char *pos) { const char *start = pos; if (!match(&pos, ">>")) return NULL; spaces(&pos); - ast_t *expr = expect(ctx, start, &pos, parse_statement, "I couldn't parse the expression for this doctest"); - whitespace(ctx, &pos); - ast_t *expected = NULL; - if (match(&pos, "=")) { + ast_t *first_value = + expect(ctx, start, &pos, parse_statement, "I couldn't parse the expression for this debugging message"); + ast_list_t *values = new (ast_list_t, .ast = first_value, .next = NULL); + spaces(&pos); + while (match(&pos, ",")) { + spaces(&pos); + ast_t *value = optional(ctx, &pos, parse_statement); + if (!value) break; + values = new (ast_list_t, .ast = value, .next = values); spaces(&pos); - expected = expect(ctx, start, &pos, parse_extended_expr, "I couldn't parse the expected expression here"); - } else { - pos = expr->end; } - return NewAST(ctx->file, start, pos, DocTest, .expr = expr, .expected = expected); + REVERSE_LIST(values); + whitespace(ctx, &pos); + return NewAST(ctx->file, start, pos, DebugLog, .values = values); } ast_t *parse_assert(parse_ctx_t *ctx, const char *pos) { @@ -130,7 +133,7 @@ ast_t *parse_assert(parse_ctx_t *ctx, const char *pos) { ast_t *parse_statement(parse_ctx_t *ctx, const char *pos) { ast_t *stmt = NULL; - if ((stmt = parse_declaration(ctx, pos)) || (stmt = parse_doctest(ctx, pos)) || (stmt = parse_assert(ctx, pos))) + if ((stmt = parse_declaration(ctx, pos)) || (stmt = parse_debug_log(ctx, pos)) || (stmt = parse_assert(ctx, pos))) return stmt; if (!(false || (stmt = parse_update(ctx, pos)) || (stmt = parse_assignment(ctx, pos)))) diff --git a/src/parse/statements.h b/src/parse/statements.h index fbc1af8f..ebf90c90 100644 --- a/src/parse/statements.h +++ b/src/parse/statements.h @@ -6,7 +6,7 @@ ast_t *parse_assignment(parse_ctx_t *ctx, const char *pos); ast_t *parse_declaration(parse_ctx_t *ctx, const char *pos); -ast_t *parse_doctest(parse_ctx_t *ctx, const char *pos); +ast_t *parse_debug_log(parse_ctx_t *ctx, const char *pos); ast_t *parse_assert(parse_ctx_t *ctx, const char *pos); ast_t *parse_statement(parse_ctx_t *ctx, const char *pos); ast_t *parse_update(parse_ctx_t *ctx, const char *pos); diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c index 5ea8cb79..0756eab3 100644 --- a/src/stdlib/stdlib.c +++ b/src/stdlib/stdlib.c @@ -87,6 +87,7 @@ void start_inspect(const char *filename, int64_t start, int64_t end) { if (file) { size_t first_line_len = strcspn(file->text + start, "\r\n"); + if (first_line_len > (size_t)(end - start)) first_line_len = (size_t)(end - start); const char *slash = strrchr(filename, '/'); const char *file_base = slash ? slash + 1 : filename; @@ -132,43 +133,6 @@ void end_inspect(const void *expr, const TypeInfo_t *type) { } } -__attribute__((nonnull)) public -void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected, - const TypeInfo_t *type) { - if (generic_equal(expr, expected, type)) return; - - print_stacktrace(stderr, 2); - fprint(stderr, ""); - fflush(stderr); - - start_inspect(filename, start, end); - end_inspect(expr, type); - fflush(stdout); - - Text_t expr_text = generic_as_text(expr, USE_COLOR, type); - Text_t expected_text = generic_as_text(expected, USE_COLOR, type); - if (USE_COLOR) { - fprint(stderr, - "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\n" - "You expected: \x1b[m", - expected_text, - "\x1b[0m\n" - "\x1b[1m But I got:\x1b[m ", - expr_text, "\n"); - } else { - fprint(stderr, - "\n==================== TEST FAILED ====================\n\n" - "You expected: ", - expected_text, - "\n" - " But I got: ", - expr_text, "\n"); - } - - fflush(stderr); - raise(SIGABRT); -} - public void say(Text_t text, bool newline) { Text$print(stdout, text); diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h index 9bae5a6c..e52b5cd1 100644 --- a/src/stdlib/stdlib.h +++ b/src/stdlib/stdlib.h @@ -69,14 +69,6 @@ void end_inspect(const void *expr, const TypeInfo_t *type); expr; \ end_inspect(NULL, typeinfo); \ } -__attribute__((nonnull)) void test_value(const char *filename, int64_t start, int64_t end, const void *expr, - const void *expected, const TypeInfo_t *type); -#define test(type, expr, expected, typeinfo, start, end) \ - { \ - type _expr = expr; \ - type _expected = expected; \ - test_value(__SOURCE_FILE__, start, end, &_expr, &_expected, typeinfo); \ - } void say(Text_t text, bool newline); Text_t ask(Text_t prompt, bool bold, bool force_tty); diff --git a/src/typecheck.c b/src/typecheck.c index b4798768..308ed259 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -263,8 +263,9 @@ static env_t *load_module(env_t *env, ast_t *use_ast) { void prebind_statement(env_t *env, ast_t *statement) { switch (statement->tag) { - case DocTest: { - prebind_statement(env, Match(statement, DocTest)->expr); + case DebugLog: { + for (ast_list_t *value = Match(statement, DebugLog)->values; value; value = value->next) + prebind_statement(env, value->ast); break; } case Assert: { @@ -351,8 +352,9 @@ void prebind_statement(env_t *env, ast_t *statement) { void bind_statement(env_t *env, ast_t *statement) { switch (statement->tag) { - case DocTest: { - bind_statement(env, Match(statement, DocTest)->expr); + case DebugLog: { + for (ast_list_t *value = Match(statement, DebugLog)->values; value; value = value->next) + prebind_statement(env, value->ast); break; } case Assert: { @@ -1105,7 +1107,7 @@ type_t *get_type(env_t *env, ast_t *ast) { case Declare: case Assign: case UPDATE_CASES: - case DocTest: + case DebugLog: case Assert: { return Type(VoidType); } |
