aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-03-11 14:23:41 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-03-11 14:23:41 -0400
commite7035e6a861c1d5e8a4917e31b1e8b722b54d55b (patch)
tree270eb3d1d61de7ad795472fc374aee94583aa647
parent26476a0b41c480a5eb2c4ade835f48c70070d146 (diff)
Clean up doctest code a bit
-rw-r--r--compile.c68
-rw-r--r--stdlib/stdlib.c36
-rw-r--r--stdlib/stdlib.h22
3 files changed, 57 insertions, 69 deletions
diff --git a/compile.c b/compile.c
index 87ae0edd..5882aae1 100644
--- a/compile.c
+++ b/compile.c
@@ -875,6 +875,8 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
if (norm && norm != buf) free(norm);
}
+ CORD setup = CORD_EMPTY;
+ CORD test_code;
if (test->expr->tag == Declare) {
auto decl = Match(test->expr, Declare);
const char *varname = Match(decl->var, Var)->name;
@@ -887,15 +889,9 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
assert(promote(env, decl->value, &val_code, t, Type(ClosureType, t)));
t = Type(ClosureType, t);
}
- return CORD_asprintf(
- "%r;\n"
- "test((%r = %r), %r, %r, %ld, %ld);\n",
- compile_declaration(t, var),
- var, val_code,
- compile_type_info(env, get_type(env, decl->value)),
- compile_string_literal(output),
- (int64_t)(test->expr->start - test->expr->file->text),
- (int64_t)(test->expr->end - test->expr->file->text));
+ setup = CORD_all(compile_declaration(t, var), ";\n");
+ test_code = CORD_all("(", var, " = ", val_code, ")");
+ expr_t = t;
} else if (test->expr->tag == Assign) {
auto assign = Match(test->expr, Assign);
if (!assign->targets->next && assign->targets->ast->tag == Var && is_idempotent(assign->targets->ast)) {
@@ -908,22 +904,16 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
code_err(test->expr, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
env_t *val_scope = with_enum_scope(env, lhs_t);
CORD value = compile_to_type(val_scope, assign->values->ast, lhs_t);
- return CORD_asprintf(
- "test((%r), %r, %r, %ld, %ld);",
- compile_assignment(env, assign->targets->ast, value),
- compile_type_info(env, lhs_t),
- compile_string_literal(output),
- (int64_t)(test->expr->start - test->expr->file->text),
- (int64_t)(test->expr->end - test->expr->file->text));
+ test_code = CORD_all("(", compile_assignment(env, assign->targets->ast, value), ")");
+ expr_t = lhs_t;
} else {
// Multi-assign or assignment to potentially non-idempotent targets
if (output && assign->targets->next)
code_err(ast, "Sorry, but doctesting with '=' is not supported for multi-assignments");
- CORD code = "test(({ // Assignment\n";
+ test_code = "({ // Assignment\n";
int64_t i = 1;
- type_t *first_type = NULL;
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
@@ -932,21 +922,16 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
if (has_stack_memory(lhs_t))
code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
if (target == assign->targets)
- first_type = lhs_t;
+ 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(&code, "%r $%ld = %r;\n", compile_type(lhs_t), i++, val_code);
+ CORD_appendf(&test_code, "%r $%ld = %r;\n", compile_type(lhs_t), i++, val_code);
}
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");
+ test_code = CORD_all(test_code, compile_assignment(env, target->ast, CORD_asprintf("$%ld", i++)), ";\n");
- CORD_appendf(&code, "$1; }), %r, %r, %ld, %ld);",
- compile_type_info(env, first_type),
- compile_string_literal(output),
- (int64_t)(test->expr->start - test->expr->file->text),
- (int64_t)(test->expr->end - test->expr->file->text));
- return code;
+ test_code = CORD_all(test_code, "$1; })");
}
} else if (test->expr->tag == UpdateAssign) {
type_t *lhs_t = get_type(env, Match(test->expr, UpdateAssign)->lhs);
@@ -961,27 +946,28 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
ast_t *update_var = WrapAST(ast, UpdateAssign,
.lhs=WrapAST(update->lhs, InlineCCode, .code="(*expr)", .type=lhs_t),
.op=update->op, .rhs=update->rhs);
- return CORD_asprintf(
- "test(({%r = &(%r); %r; *expr;}), %r, %r, %ld, %ld);",
- compile_declaration(Type(PointerType, lhs_t), "expr"),
- compile_lvalue(env, update->lhs),
- compile_statement(env, update_var),
- compile_type_info(env, lhs_t),
- compile_string_literal(output),
- (int64_t)(test->expr->start - test->expr->file->text),
- (int64_t)(test->expr->end - test->expr->file->text));
+ test_code = CORD_all("({",
+ compile_declaration(Type(PointerType, lhs_t), "expr"), " = &(", compile_lvalue(env, update->lhs), "); ",
+ compile_statement(env, update_var), "; *expr; })");
+ expr_t = lhs_t;
} else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) {
+ test_code = CORD_all("({", compile_statement(env, test->expr), " NULL;})");
+ } else {
+ test_code = compile(env, test->expr);
+ }
+ if (test->output) {
return CORD_asprintf(
- "test(({%r NULL;}), NULL, NULL, %ld, %ld);",
- compile_statement(env, test->expr),
+ "%rtest(%r, %r, %r, %ld, %ld);",
+ setup, test_code,
+ compile_type_info(env, expr_t),
+ compile_string_literal(output),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
} else {
return CORD_asprintf(
- "test(%r, %r, %r, %ld, %ld);",
- compile(env, test->expr),
+ "%rinspect(%r, %r, %ld, %ld);",
+ setup, test_code,
compile_type_info(env, expr_t),
- compile_string_literal(output),
(int64_t)(test->expr->start - test->expr->file->text),
(int64_t)(test->expr->end - test->expr->file->text));
}
diff --git a/stdlib/stdlib.c b/stdlib/stdlib.c
index 56d8ce99..28174d6c 100644
--- a/stdlib/stdlib.c
+++ b/stdlib/stdlib.c
@@ -566,15 +566,16 @@ public Text_t builtin_last_err()
return Text$from_str(strerror(errno));
}
-static int TEST_DEPTH = 0;
+static int _inspect_depth = 0;
static file_t *file = NULL;
-public void start_test(const char *filename, int64_t start, int64_t end)
+__attribute__((nonnull))
+public void start_inspect(const char *filename, int64_t start, int64_t end)
{
- if (filename && (file == NULL || strcmp(file->filename, filename) != 0))
+ if (file == NULL || strcmp(file->filename, filename) != 0)
file = load_file(filename);
- if (filename && file) {
+ if (file) {
const char *spaces = " ";
int64_t first_line_len = (int64_t)strcspn(file->text + start, "\r\n");
const char *slash = strrchr(filename, '/');
@@ -582,8 +583,8 @@ public void start_test(const char *filename, int64_t start, int64_t end)
int64_t line_num = get_line_number(file, file->text + start);
fprintf(stderr, USE_COLOR ? "%.*s\x1b[33;1m>> \x1b[m%.*s %.*s\x1b[32;2m[%s:%ld]\x1b[m\n" : "%.*s>> %.*s %.*s[%s:%ld]\n",
- 3*TEST_DEPTH, spaces, first_line_len, file->text + start,
- MAX(0, 35-first_line_len-3*TEST_DEPTH), spaces, file_base, line_num);
+ 3*_inspect_depth, spaces, first_line_len, file->text + start,
+ MAX(0, 35-first_line_len-3*_inspect_depth), spaces, file_base, line_num);
// For multi-line expressions, dedent each and print it on a new line with ".. " in front:
if (end > start + first_line_len) {
@@ -594,29 +595,30 @@ public void start_test(const char *filename, int64_t start, int64_t end)
if ((int64_t)strspn(line, " \t") >= indent_len)
line += indent_len;
fprintf(stderr, USE_COLOR ? "%.*s\x1b[33m.. \x1b[m%.*s\n" : "%.*s.. %.*s\n",
- 3*TEST_DEPTH, spaces, strcspn(line, "\r\n"), line);
+ 3*_inspect_depth, spaces, strcspn(line, "\r\n"), line);
}
}
}
- ++TEST_DEPTH;
+ _inspect_depth += 1;
}
-public void end_test(const void *expr, const TypeInfo_t *type)
+__attribute__((nonnull))
+public void end_inspect(const void *expr, const TypeInfo_t *type)
{
- --TEST_DEPTH;
- if (!expr || !type) return;
+ _inspect_depth -= 1;
- Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
- Text_t type_name = generic_as_text(NULL, false, type);
+ if (type->metamethods.as_text) {
+ Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
+ Text_t type_name = generic_as_text(NULL, false, type);
- for (int i = 0; i < 3*TEST_DEPTH; i++) fputc(' ', stderr);
- fprintf(stderr, USE_COLOR ? "\x1b[2m=\x1b[0m %k \x1b[2m: \x1b[36m%k\x1b[m\n" : "= %k : %k\n", &expr_text, &type_name);
+ for (int i = 0; i < 3*_inspect_depth; i++) fputc(' ', stderr);
+ fprintf(stderr, USE_COLOR ? "\x1b[2m=\x1b[0m %k \x1b[2m: \x1b[36m%k\x1b[m\n" : "= %k : %k\n", &expr_text, &type_name);
+ }
}
+__attribute__((nonnull))
public void test_value(const void *expr, const TypeInfo_t *type, const char *expected)
{
- if (!expr || !type || !expected) return;
-
Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
Text_t type_name = generic_as_text(NULL, false, type);
diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
index 93bd4a02..1b633dff 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -29,20 +29,20 @@ _Noreturn void fail_text(Text_t message);
__attribute__((format(printf, 4, 5)))
_Noreturn void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...);
Text_t builtin_last_err();
-void start_test(const char *filename, int64_t start, int64_t end);
-void end_test(const void *expr, const TypeInfo_t *type);
+__attribute__((nonnull))
+void start_inspect(const char *filename, int64_t start, int64_t end);
+__attribute__((nonnull))
+void end_inspect(const void *expr, const TypeInfo_t *type);
+#define inspect(expr, typeinfo, start, end) {\
+ start_inspect(__SOURCE_FILE__, start, end); \
+ auto _expr = expr; \
+ end_inspect(&_expr, typeinfo); \
+}
+__attribute__((nonnull))
void test_value(const void *expr, const TypeInfo_t *type, const char *expected);
#define test(expr, typeinfo, expected, start, end) {\
- const char *_expected = expected; \
- if (!_expected || !_expected[0]) { \
- start_test(__SOURCE_FILE__, start, end); \
- } \
auto _expr = expr; \
- if (!_expected || !_expected[0]) { \
- end_test(&_expr, typeinfo); \
- } else { \
- test_value(&_expr, typeinfo, _expected); \
- } \
+ test_value(&_expr, typeinfo, expected); \
}
void say(Text_t text, bool newline);