aboutsummaryrefslogtreecommitdiff
path: root/src/compile
diff options
context:
space:
mode:
Diffstat (limited to 'src/compile')
-rw-r--r--src/compile/assertions.c86
-rw-r--r--src/compile/assertions.h8
-rw-r--r--src/compile/doctests.c1
-rw-r--r--src/compile/statements.c76
4 files changed, 97 insertions, 74 deletions
diff --git a/src/compile/assertions.c b/src/compile/assertions.c
new file mode 100644
index 00000000..6034b828
--- /dev/null
+++ b/src/compile/assertions.c
@@ -0,0 +1,86 @@
+// This file defines how to compile assertions
+
+#include "../ast.h"
+#include "../config.h"
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+#include "../stdlib/print.h"
+#include "../stdlib/text.h"
+#include "../stdlib/util.h"
+#include "../typecheck.h"
+#include "conditionals.h"
+#include "declarations.h"
+#include "promotions.h"
+#include "statements.h"
+#include "text.h"
+
+public
+Text_t compile_assertion(env_t *env, ast_t *ast) {
+ ast_t *expr = Match(ast, Assert)->expr;
+ ast_t *message = Match(ast, Assert)->message;
+ const char *failure = NULL;
+ switch (expr->tag) {
+ case And: {
+ DeclareMatch(and_, ast, And);
+ return Texts(compile_statement(env, WrapAST(ast, Assert, .expr = and_->lhs, .message = message)),
+ compile_statement(env, WrapAST(ast, Assert, .expr = and_->rhs, .message = message)));
+ }
+ case Equals: failure = "!="; goto assert_comparison;
+ case NotEquals: failure = "=="; goto assert_comparison;
+ case LessThan: failure = ">="; goto assert_comparison;
+ case LessThanOrEquals: failure = ">"; goto assert_comparison;
+ case GreaterThan: failure = "<="; goto assert_comparison;
+ case GreaterThanOrEquals:
+ failure = "<";
+ goto assert_comparison;
+ assert_comparison: {
+ binary_operands_t cmp = BINARY_OPERANDS(expr);
+ type_t *lhs_t = get_type(env, cmp.lhs);
+ type_t *rhs_t = get_type(env, cmp.rhs);
+ type_t *operand_t;
+ if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
+ operand_t = rhs_t;
+ } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, cmp.rhs, lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
+ operand_t = rhs_t;
+ } else {
+ code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ }
+
+ ast_t *lhs_var = FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_lhs"))),
+ .type = operand_t);
+ ast_t *rhs_var = FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_rhs"))),
+ .type = operand_t);
+ ast_t *var_comparison = new (ast_t, .file = expr->file, .start = expr->start, .end = expr->end,
+ .tag = expr->tag, .__data.Equals = {.lhs = lhs_var, .rhs = rhs_var});
+ int64_t line = get_line_number(ast->file, ast->start);
+ return Texts("{ // assertion\n", compile_declaration(operand_t, Text("_lhs")), " = ",
+ compile_to_type(env, cmp.lhs, operand_t), ";\n", "\n#line ", String(line), "\n",
+ compile_declaration(operand_t, Text("_rhs")), " = ", compile_to_type(env, cmp.rhs, operand_t),
+ ";\n", "\n#line ", String(line), "\n", "if (!(", compile_condition(env, var_comparison), "))\n",
+ "#line ", String(line), "\n",
+ Texts("fail_source(", quoted_str(ast->file->filename), ", ",
+ String((int64_t)(expr->start - expr->file->text)), ", ",
+ String((int64_t)(expr->end - expr->file->text)), ", ",
+ message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
+ : Text("\"This assertion failed!\""),
+ ", ", "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")),
+ ", "
+ "\" ",
+ failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"),
+ "}\n");
+ }
+ default: {
+ int64_t line = get_line_number(ast->file, ast->start);
+ return Texts("if (!(", compile_condition(env, expr), "))\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(expr->start - expr->file->text)), ", ",
+ String((int64_t)(expr->end - expr->file->text)), ", ",
+ message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
+ : Text("\"This assertion failed!\""),
+ ");\n");
+ }
+ }
+}
diff --git a/src/compile/assertions.h b/src/compile/assertions.h
new file mode 100644
index 00000000..b5f604d2
--- /dev/null
+++ b/src/compile/assertions.h
@@ -0,0 +1,8 @@
+// This file defines how to compile assertions
+#pragma once
+
+#include "../ast.h"
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+
+Text_t compile_assertion(env_t *env, ast_t *ast);
diff --git a/src/compile/doctests.c b/src/compile/doctests.c
index 4d544656..720385d3 100644
--- a/src/compile/doctests.c
+++ b/src/compile/doctests.c
@@ -15,6 +15,7 @@
#include "statements.h"
#include "types.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);
diff --git a/src/compile/statements.c b/src/compile/statements.c
index e94e14a9..3ba560d2 100644
--- a/src/compile/statements.c
+++ b/src/compile/statements.c
@@ -14,6 +14,7 @@
#include "../stdlib/text.h"
#include "../stdlib/util.h"
#include "../typecheck.h"
+#include "assertions.h"
#include "assignments.h"
#include "blocks.h"
#include "conditionals.h"
@@ -24,7 +25,6 @@
#include "functions.h"
#include "promotions.h"
#include "statements.h"
-#include "text.h"
#include "whens.h"
typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *);
@@ -40,79 +40,7 @@ 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 Assert: {
- ast_t *expr = Match(ast, Assert)->expr;
- ast_t *message = Match(ast, Assert)->message;
- const char *failure = NULL;
- switch (expr->tag) {
- case And: {
- DeclareMatch(and_, ast, And);
- return Texts(compile_statement(env, WrapAST(ast, Assert, .expr = and_->lhs, .message = message)),
- compile_statement(env, WrapAST(ast, Assert, .expr = and_->rhs, .message = message)));
- }
- case Equals: failure = "!="; goto assert_comparison;
- case NotEquals: failure = "=="; goto assert_comparison;
- case LessThan: failure = ">="; goto assert_comparison;
- case LessThanOrEquals: failure = ">"; goto assert_comparison;
- case GreaterThan: failure = "<="; goto assert_comparison;
- case GreaterThanOrEquals:
- failure = "<";
- goto assert_comparison;
- {
- assert_comparison:;
- binary_operands_t cmp = BINARY_OPERANDS(expr);
- type_t *lhs_t = get_type(env, cmp.lhs);
- type_t *rhs_t = get_type(env, cmp.rhs);
- type_t *operand_t;
- if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
- operand_t = rhs_t;
- } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
- operand_t = lhs_t;
- } else if (can_compile_to_type(env, cmp.rhs, lhs_t)) {
- operand_t = lhs_t;
- } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
- operand_t = rhs_t;
- } else {
- code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
- }
-
- ast_t *lhs_var =
- FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_lhs"))),
- .type = operand_t);
- ast_t *rhs_var =
- FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_rhs"))),
- .type = operand_t);
- ast_t *var_comparison = new (ast_t, .file = expr->file, .start = expr->start, .end = expr->end,
- .tag = expr->tag, .__data.Equals = {.lhs = lhs_var, .rhs = rhs_var});
- int64_t line = get_line_number(ast->file, ast->start);
- return Texts("{ // assertion\n", compile_declaration(operand_t, Text("_lhs")), " = ",
- compile_to_type(env, cmp.lhs, operand_t), ";\n", "\n#line ", String(line), "\n",
- compile_declaration(operand_t, Text("_rhs")), " = ",
- compile_to_type(env, cmp.rhs, operand_t), ";\n", "\n#line ", String(line), "\n", "if (!(",
- compile_condition(env, var_comparison), "))\n", "#line ", String(line), "\n",
- Texts("fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(expr->start - expr->file->text)), ", ",
- String((int64_t)(expr->end - expr->file->text)), ", ",
- message
- ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
- : Text("\"This assertion failed!\""),
- ", ", "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")),
- ", "
- "\" ",
- failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"),
- "}\n");
- }
- default: {
- int64_t line = get_line_number(ast->file, ast->start);
- return Texts("if (!(", compile_condition(env, expr), "))\n", "#line ", String(line), "\n", "fail_source(",
- quoted_str(ast->file->filename), ", ", String((int64_t)(expr->start - expr->file->text)), ", ",
- String((int64_t)(expr->end - expr->file->text)), ", ",
- message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
- : Text("\"This assertion failed!\""),
- ");\n");
- }
- }
- }
+ case Assert: return compile_assertion(env, ast);
case Declare: {
DeclareMatch(decl, ast, Declare);
const char *name = Match(decl->var, Var)->name;