code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(78 lines)
1 // This file defines how to compile assertions
3 #include "../ast.h"
4 #include "../config.h"
5 #include "../environment.h"
6 #include "../stdlib/datatypes.h"
7 #include "../stdlib/text.h"
8 #include "../stdlib/util.h"
9 #include "../typecheck.h"
10 #include "compilation.h"
12 public
13 Text_t compile_assertion(env_t *env, ast_t *ast) {
14 ast_t *expr = Match(ast, Assert)->expr;
15 ast_t *message = Match(ast, Assert)->message;
16 const char *failure = NULL;
17 switch (expr->tag) {
18 case And: {
19 DeclareMatch(and_, expr, And);
20 return Texts(compile_statement(env, WrapAST(ast, Assert, .expr = and_->lhs, .message = message)),
21 compile_statement(env, WrapAST(ast, Assert, .expr = and_->rhs, .message = message)));
23 case Equals: failure = "!="; goto assert_comparison;
24 case NotEquals: failure = "=="; goto assert_comparison;
25 case LessThan: failure = ">="; goto assert_comparison;
26 case LessThanOrEquals: failure = ">"; goto assert_comparison;
27 case GreaterThan: failure = "<="; goto assert_comparison;
28 case GreaterThanOrEquals:
29 failure = "<";
30 goto assert_comparison;
31 assert_comparison: {
32 binary_operands_t cmp = BINARY_OPERANDS(expr);
33 type_t *lhs_t = get_type(env, cmp.lhs);
34 type_t *rhs_t = get_type(with_enum_scope(env, lhs_t), cmp.rhs);
35 type_t *operand_t;
36 if (type_eq(lhs_t, rhs_t)) {
37 operand_t = lhs_t;
38 } else if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
39 operand_t = rhs_t;
40 } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
41 operand_t = lhs_t;
42 } else if (can_compile_to_type(with_enum_scope(env, lhs_t), cmp.rhs, lhs_t)) {
43 operand_t = lhs_t;
44 } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
45 operand_t = rhs_t;
46 } else {
47 code_err(ast, "I can't do comparisons between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t));
50 ast_t *lhs_var = FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_lhs"))),
51 .type = operand_t);
52 ast_t *rhs_var = FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_rhs"))),
53 .type = operand_t);
54 ast_t *var_comparison = new (ast_t, .file = expr->file, .start = expr->start, .end = expr->end,
55 .tag = expr->tag, .__data.Equals = {.lhs = lhs_var, .rhs = rhs_var});
56 int64_t line = get_line_number(ast->file, ast->start);
57 return Texts(
58 "{ // assertion\n", compile_declaration(operand_t, Text("_lhs")), " = ",
59 compile_to_type(env, cmp.lhs, operand_t), ";\n", "\n#line ", line, "\n",
60 compile_declaration(operand_t, Text("_rhs")), " = ", compile_to_type(env, cmp.rhs, operand_t), ";\n",
61 "\n#line ", line, "\n", "if (!(", compile_condition(env, var_comparison), "))\n", "#line ", line, "\n",
62 Texts("fail_source(", quoted_str(ast->file->filename), ", ", (int64_t)(expr->start - expr->file->text),
63 ", ", (int64_t)(expr->end - expr->file->text), ", Text$concat(",
64 message ? compile_to_type(env, message, Type(TextType)) : Text("Text(\"This assertion failed!\")"),
65 ", Text(\" (\"), ", expr_as_text(Text("_lhs"), operand_t, Text("no")), ", Text(\" ", failure,
66 " \"), ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", Text(\")\")));\n"),
67 "}\n");
69 default: {
70 int64_t line = get_line_number(ast->file, ast->start);
71 return Texts("if (!(", compile_condition(env, expr), "))\n", "#line ", line, "\n", "fail_source(",
72 quoted_str(ast->file->filename), ", ", (int64_t)(expr->start - expr->file->text), ", ",
73 (int64_t)(expr->end - expr->file->text), ", ",
74 message ? compile_to_type(env, message, Type(TextType)) : Text("Text(\"This assertion failed!\")"),
75 ");\n");