aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compile/conditionals.c125
-rw-r--r--src/compile/conditionals.h10
-rw-r--r--src/compile/expressions.c54
-rw-r--r--src/compile/statements.c58
-rw-r--r--src/compile/statements.h1
5 files changed, 138 insertions, 110 deletions
diff --git a/src/compile/conditionals.c b/src/compile/conditionals.c
new file mode 100644
index 00000000..98919152
--- /dev/null
+++ b/src/compile/conditionals.c
@@ -0,0 +1,125 @@
+// This file defines how to compile conditionals
+
+#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 "expressions.h"
+#include "optionals.h"
+#include "statements.h"
+
+public
+Text_t compile_condition(env_t *env, ast_t *ast) {
+ type_t *t = get_type(env, ast);
+ if (t->tag == BoolType) {
+ return compile(env, ast);
+ } else if (t->tag == TextType) {
+ return Texts("(", compile(env, ast), ").length");
+ } else if (t->tag == ListType) {
+ return Texts("(", compile(env, ast), ").length");
+ } else if (t->tag == TableType || t->tag == SetType) {
+ return Texts("(", compile(env, ast), ").entries.length");
+ } else if (t->tag == OptionalType) {
+ return Texts("!", check_none(t, compile(env, ast)));
+ } else if (t->tag == PointerType) {
+ code_err(ast, "This pointer will always be non-none, so it should not be "
+ "used in a conditional.");
+ } else {
+ code_err(ast, type_to_str(t), " values cannot be used for conditionals");
+ }
+ return EMPTY_TEXT;
+}
+
+public
+Text_t compile_if_statement(env_t *env, ast_t *ast) {
+ DeclareMatch(if_, ast, If);
+ ast_t *condition = if_->condition;
+ if (condition->tag == Declare) {
+ if (Match(condition, Declare)->value == NULL) code_err(condition, "This declaration must have a value");
+ env_t *truthy_scope = fresh_scope(env);
+ Text_t code = Texts("IF_DECLARE(", compile_statement(truthy_scope, condition), ", ");
+ bind_statement(truthy_scope, condition);
+ ast_t *var = Match(condition, Declare)->var;
+ code = Texts(code, compile_condition(truthy_scope, var), ", ");
+ type_t *cond_t = get_type(truthy_scope, var);
+ if (cond_t->tag == OptionalType) {
+ set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type,
+ optional_into_nonnone(cond_t, compile(truthy_scope, var)));
+ }
+ code = Texts(code, compile_statement(truthy_scope, if_->body), ")");
+ if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+ return code;
+ } else {
+ Text_t code = Texts("if (", compile_condition(env, condition), ")");
+ env_t *truthy_scope = env;
+ type_t *cond_t = get_type(env, condition);
+ if (condition->tag == Var && cond_t->tag == OptionalType) {
+ truthy_scope = fresh_scope(env);
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(cond_t, OptionalType)->type,
+ optional_into_nonnone(cond_t, compile(truthy_scope, condition)));
+ }
+ code = Texts(code, compile_statement(truthy_scope, if_->body));
+ if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+ return code;
+ }
+}
+
+public
+Text_t compile_if_expression(env_t *env, ast_t *ast) {
+ DeclareMatch(if_, ast, If);
+ ast_t *condition = if_->condition;
+ Text_t decl_code = EMPTY_TEXT;
+ env_t *truthy_scope = env, *falsey_scope = env;
+
+ Text_t condition_code;
+ if (condition->tag == Declare) {
+ DeclareMatch(decl, condition, Declare);
+ if (decl->value == NULL) code_err(condition, "This declaration must have a value");
+ type_t *condition_type =
+ decl->type ? parse_type_ast(env, decl->type) : get_type(env, Match(condition, Declare)->value);
+ if (condition_type->tag != OptionalType)
+ code_err(condition,
+ "This `if var := ...:` declaration should be an "
+ "optional "
+ "type, not ",
+ type_to_str(condition_type));
+
+ if (is_incomplete_type(condition_type)) code_err(condition, "This type is incomplete!");
+
+ decl_code = compile_statement(env, condition);
+ ast_t *var = Match(condition, Declare)->var;
+ truthy_scope = fresh_scope(env);
+ bind_statement(truthy_scope, condition);
+ condition_code = compile_condition(truthy_scope, var);
+ set_binding(truthy_scope, Match(var, Var)->name, Match(condition_type, OptionalType)->type,
+ optional_into_nonnone(condition_type, compile(truthy_scope, var)));
+ } else if (condition->tag == Var) {
+ type_t *condition_type = get_type(env, condition);
+ condition_code = compile_condition(env, condition);
+ if (condition_type->tag == OptionalType) {
+ truthy_scope = fresh_scope(env);
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(condition_type, OptionalType)->type,
+ optional_into_nonnone(condition_type, compile(truthy_scope, condition)));
+ }
+ } else {
+ condition_code = compile_condition(env, condition);
+ }
+
+ type_t *true_type = get_type(truthy_scope, if_->body);
+ type_t *false_type = get_type(falsey_scope, if_->else_body);
+ if (true_type->tag == AbortType || true_type->tag == ReturnType)
+ return Texts("({ ", decl_code, "if (", condition_code, ") ", compile_statement(truthy_scope, if_->body), "\n",
+ compile(falsey_scope, if_->else_body), "; })");
+ else if (false_type->tag == AbortType || false_type->tag == ReturnType)
+ return Texts("({ ", decl_code, "if (!(", condition_code, ")) ", compile_statement(falsey_scope, if_->else_body),
+ "\n", compile(truthy_scope, if_->body), "; })");
+ else if (decl_code.length > 0)
+ return Texts("({ ", decl_code, "(", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
+ compile(falsey_scope, if_->else_body), ";})");
+ else
+ return Texts("((", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
+ compile(falsey_scope, if_->else_body), ")");
+}
diff --git a/src/compile/conditionals.h b/src/compile/conditionals.h
new file mode 100644
index 00000000..26546e10
--- /dev/null
+++ b/src/compile/conditionals.h
@@ -0,0 +1,10 @@
+// This file defines how to compile conditionals
+#pragma once
+
+#include "../ast.h"
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+
+Text_t compile_condition(env_t *env, ast_t *ast);
+Text_t compile_if_statement(env_t *env, ast_t *ast);
+Text_t compile_if_expression(env_t *env, ast_t *ast);
diff --git a/src/compile/expressions.c b/src/compile/expressions.c
index 28db606b..e485e450 100644
--- a/src/compile/expressions.c
+++ b/src/compile/expressions.c
@@ -355,60 +355,6 @@ Text_t compile(env_t *env, ast_t *ast) {
"when; })");
}
case If: {
- DeclareMatch(if_, ast, If);
- ast_t *condition = if_->condition;
- Text_t decl_code = EMPTY_TEXT;
- env_t *truthy_scope = env, *falsey_scope = env;
-
- Text_t condition_code;
- if (condition->tag == Declare) {
- DeclareMatch(decl, condition, Declare);
- if (decl->value == NULL) code_err(condition, "This declaration must have a value");
- type_t *condition_type =
- decl->type ? parse_type_ast(env, decl->type) : get_type(env, Match(condition, Declare)->value);
- if (condition_type->tag != OptionalType)
- code_err(condition,
- "This `if var := ...:` declaration should be an "
- "optional "
- "type, not ",
- type_to_str(condition_type));
-
- if (is_incomplete_type(condition_type)) code_err(condition, "This type is incomplete!");
-
- decl_code = compile_statement(env, condition);
- ast_t *var = Match(condition, Declare)->var;
- truthy_scope = fresh_scope(env);
- bind_statement(truthy_scope, condition);
- condition_code = compile_condition(truthy_scope, var);
- set_binding(truthy_scope, Match(var, Var)->name, Match(condition_type, OptionalType)->type,
- optional_into_nonnone(condition_type, compile(truthy_scope, var)));
- } else if (condition->tag == Var) {
- type_t *condition_type = get_type(env, condition);
- condition_code = compile_condition(env, condition);
- if (condition_type->tag == OptionalType) {
- truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name, Match(condition_type, OptionalType)->type,
- optional_into_nonnone(condition_type, compile(truthy_scope, condition)));
- }
- } else {
- condition_code = compile_condition(env, condition);
- }
-
- type_t *true_type = get_type(truthy_scope, if_->body);
- type_t *false_type = get_type(falsey_scope, if_->else_body);
- if (true_type->tag == AbortType || true_type->tag == ReturnType)
- return Texts("({ ", decl_code, "if (", condition_code, ") ", compile_statement(truthy_scope, if_->body),
- "\n", compile(falsey_scope, if_->else_body), "; })");
- else if (false_type->tag == AbortType || false_type->tag == ReturnType)
- return Texts("({ ", decl_code, "if (!(", condition_code, ")) ",
- compile_statement(falsey_scope, if_->else_body), "\n", compile(truthy_scope, if_->body),
- "; })");
- else if (decl_code.length > 0)
- return Texts("({ ", decl_code, "(", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
- compile(falsey_scope, if_->else_body), ";})");
- else
- return Texts("((", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
- compile(falsey_scope, if_->else_body), ")");
}
case Reduction: {
DeclareMatch(reduction, ast, Reduction);
diff --git a/src/compile/statements.c b/src/compile/statements.c
index 7683b552..114e73cd 100644
--- a/src/compile/statements.c
+++ b/src/compile/statements.c
@@ -3,7 +3,6 @@
#include <glob.h>
#include "../ast.h"
-#include "expressions.h"
#include "../config.h"
#include "../environment.h"
#include "../modules.h"
@@ -17,7 +16,9 @@
#include "../typecheck.h"
#include "assignments.h"
#include "blocks.h"
+#include "conditionals.h"
#include "declarations.h"
+#include "expressions.h"
#include "functions.h"
#include "optionals.h"
#include "pointers.h"
@@ -35,28 +36,6 @@ Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) {
return Texts("\n#line ", String(line), "\n", code);
}
-public
-Text_t compile_condition(env_t *env, ast_t *ast) {
- type_t *t = get_type(env, ast);
- if (t->tag == BoolType) {
- return compile(env, ast);
- } else if (t->tag == TextType) {
- return Texts("(", compile(env, ast), ").length");
- } else if (t->tag == ListType) {
- return Texts("(", compile(env, ast), ").length");
- } else if (t->tag == TableType || t->tag == SetType) {
- return Texts("(", compile(env, ast), ").entries.length");
- } else if (t->tag == OptionalType) {
- return Texts("!", check_none(t, compile(env, ast)));
- } else if (t->tag == PointerType) {
- code_err(ast, "This pointer will always be non-none, so it should not be "
- "used in a conditional.");
- } else {
- code_err(ast, type_to_str(t), " values cannot be used for conditionals");
- }
- return EMPTY_TEXT;
-}
-
static Text_t _compile_statement(env_t *env, ast_t *ast) {
switch (ast->tag) {
case When: {
@@ -955,38 +934,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) {
default: code_err(for_->iter, "Iteration is not implemented for type: ", type_to_str(iter_t));
}
}
- case If: {
- DeclareMatch(if_, ast, If);
- ast_t *condition = if_->condition;
- if (condition->tag == Declare) {
- if (Match(condition, Declare)->value == NULL) code_err(condition, "This declaration must have a value");
- env_t *truthy_scope = fresh_scope(env);
- Text_t code = Texts("IF_DECLARE(", compile_statement(truthy_scope, condition), ", ");
- bind_statement(truthy_scope, condition);
- ast_t *var = Match(condition, Declare)->var;
- code = Texts(code, compile_condition(truthy_scope, var), ", ");
- type_t *cond_t = get_type(truthy_scope, var);
- if (cond_t->tag == OptionalType) {
- set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type,
- optional_into_nonnone(cond_t, compile(truthy_scope, var)));
- }
- code = Texts(code, compile_statement(truthy_scope, if_->body), ")");
- if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
- return code;
- } else {
- Text_t code = Texts("if (", compile_condition(env, condition), ")");
- env_t *truthy_scope = env;
- type_t *cond_t = get_type(env, condition);
- if (condition->tag == Var && cond_t->tag == OptionalType) {
- truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name, Match(cond_t, OptionalType)->type,
- optional_into_nonnone(cond_t, compile(truthy_scope, condition)));
- }
- code = Texts(code, compile_statement(truthy_scope, if_->body));
- if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
- return code;
- }
- }
+ case If: return compile_if_statement(env, ast);
case Block: {
return compile_block(env, ast);
}
diff --git a/src/compile/statements.h b/src/compile/statements.h
index 41b1d8f4..4284a61c 100644
--- a/src/compile/statements.h
+++ b/src/compile/statements.h
@@ -5,6 +5,5 @@
#include "../environment.h"
#include "../stdlib/datatypes.h"
-Text_t compile_condition(env_t *env, ast_t *ast);
Text_t compile_statement(env_t *env, ast_t *ast);
Text_t with_source_info(env_t *env, ast_t *ast, Text_t code);