aboutsummaryrefslogtreecommitdiff
path: root/src/compile
diff options
context:
space:
mode:
Diffstat (limited to 'src/compile')
-rw-r--r--src/compile/binops.c2
-rw-r--r--src/compile/comparisons.c14
-rw-r--r--src/compile/expressions.c5
-rw-r--r--src/compile/files.c45
-rw-r--r--src/compile/functions.c20
-rw-r--r--src/compile/reductions.c7
-rw-r--r--src/compile/statements.c71
7 files changed, 80 insertions, 84 deletions
diff --git a/src/compile/binops.c b/src/compile/binops.c
index 87fd2c7a..ed4aaeba 100644
--- a/src/compile/binops.c
+++ b/src/compile/binops.c
@@ -67,7 +67,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) {
}
}
} else if ((ast->tag == Divide || ast->tag == Mod || ast->tag == Mod1) && is_numeric_type(rhs_t)) {
- b = get_namespace_binding(env, binop.lhs, binop_method_name(ast->tag));
+ b = get_namespace_binding(env, binop.lhs, binop_info[ast->tag].method_name);
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
diff --git a/src/compile/comparisons.c b/src/compile/comparisons.c
index d73664de..d7531261 100644
--- a/src/compile/comparisons.c
+++ b/src/compile/comparisons.c
@@ -7,6 +7,18 @@
#include "../typecheck.h"
#include "compilation.h"
+static CONSTFUNC const char *comparison_operator(ast_e tag) {
+ switch (tag) {
+ case Equals: return "==";
+ case NotEquals: return "!=";
+ case LessThan: return "<";
+ case LessThanOrEquals: return "<=";
+ case GreaterThan: return ">";
+ case GreaterThanOrEquals: return ">=";
+ default: return NULL;
+ }
+}
+
Text_t compile_comparison(env_t *env, ast_t *ast) {
switch (ast->tag) {
@@ -75,7 +87,7 @@ Text_t compile_comparison(env_t *env, ast_t *ast) {
if (ast->tag == Compare)
return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
- const char *op = binop_operator(ast->tag);
+ const char *op = comparison_operator(ast->tag);
switch (operand_t->tag) {
case BigIntType: return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)");
case BoolType:
diff --git a/src/compile/expressions.c b/src/compile/expressions.c
index e21ee263..e888ce16 100644
--- a/src/compile/expressions.c
+++ b/src/compile/expressions.c
@@ -152,7 +152,7 @@ Text_t compile(env_t *env, ast_t *ast) {
ast_t *key = ast->tag == Min ? Match(ast, Min)->key : Match(ast, Max)->key;
ast_t *lhs = ast->tag == Min ? Match(ast, Min)->lhs : Match(ast, Max)->lhs;
ast_t *rhs = ast->tag == Min ? Match(ast, Min)->rhs : Match(ast, Max)->rhs;
- const char *key_name = "$";
+ const char *key_name = ast->tag == Min ? "_min_" : "_max_";
if (key == NULL) key = FakeAST(Var, key_name);
env_t *expr_env = fresh_scope(env);
@@ -237,7 +237,8 @@ Text_t compile(env_t *env, ast_t *ast) {
case Index: return compile_indexing(env, ast, false);
case InlineCCode: {
type_t *t = get_type(env, ast);
- if (t->tag == VoidType) return Texts("{\n", compile_statement(env, ast), "\n}");
+ if (Match(ast, InlineCCode)->type_ast != NULL) return Texts("({", compile_statement(env, ast), "; })");
+ else if (t->tag == VoidType) return Texts("{\n", compile_statement(env, ast), "\n}");
else return compile_statement(env, ast);
}
case Use: code_err(ast, "Compiling 'use' as expression!");
diff --git a/src/compile/files.c b/src/compile/files.c
index a6af2300..4d6fb1a8 100644
--- a/src/compile/files.c
+++ b/src/compile/files.c
@@ -12,7 +12,16 @@
#include "../types.h"
#include "compilation.h"
-static void initialize_vars_and_statics(env_t *env, ast_t *ast) {
+static void initialize_vars_and_statics(env_t *env, ast_t *ast);
+static void initialize_namespace(env_t *env, const char *name, ast_t *namespace);
+static Text_t compile_top_level_code(env_t *env, ast_t *ast);
+static Text_t compile_namespace(env_t *env, const char *name, ast_t *namespace);
+
+void initialize_namespace(env_t *env, const char *name, ast_t *namespace) {
+ initialize_vars_and_statics(namespace_env(env, name), namespace);
+}
+
+void initialize_vars_and_statics(env_t *env, ast_t *ast) {
if (!ast) return;
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
@@ -34,17 +43,13 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast) {
Texts(full_name, " = ", val_code, ",\n", initialized_name, " = true;\n")));
}
} else if (stmt->ast->tag == StructDef) {
- initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, StructDef)->name),
- Match(stmt->ast, StructDef)->namespace);
+ initialize_namespace(env, Match(stmt->ast, StructDef)->name, Match(stmt->ast, StructDef)->namespace);
} else if (stmt->ast->tag == EnumDef) {
- initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, EnumDef)->name),
- Match(stmt->ast, EnumDef)->namespace);
+ initialize_namespace(env, Match(stmt->ast, EnumDef)->name, Match(stmt->ast, EnumDef)->namespace);
} else if (stmt->ast->tag == LangDef) {
- initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, LangDef)->name),
- Match(stmt->ast, LangDef)->namespace);
+ initialize_namespace(env, Match(stmt->ast, LangDef)->name, Match(stmt->ast, LangDef)->namespace);
} else if (stmt->ast->tag == Extend) {
- initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, Extend)->name),
- Match(stmt->ast, Extend)->body);
+ initialize_namespace(env, Match(stmt->ast, Extend)->name, Match(stmt->ast, Extend)->body);
} else if (stmt->ast->tag == Use) {
continue;
} else {
@@ -54,7 +59,12 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast) {
}
}
-static Text_t compile_top_level_code(env_t *env, ast_t *ast) {
+Text_t compile_namespace(env_t *env, const char *name, ast_t *namespace) {
+ env_t *ns_env = namespace_env(env, name);
+ return namespace ? compile_top_level_code(ns_env, namespace) : EMPTY_TEXT;
+}
+
+Text_t compile_top_level_code(env_t *env, ast_t *ast) {
if (!ast) return EMPTY_TEXT;
switch (ast->tag) {
@@ -95,13 +105,13 @@ static Text_t compile_top_level_code(env_t *env, ast_t *ast) {
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case ConvertDef: {
- type_t *type = get_function_def_type(env, ast);
- const char *name = get_type_name(Match(type, FunctionType)->ret);
+ type_t *type = get_function_return_type(env, ast);
+ const char *name = get_type_name(type);
if (!name)
code_err(ast,
"Conversions are only supported for text, struct, and enum "
"types, not ",
- type_to_str(Match(type, FunctionType)->ret));
+ type_to_str(type));
Text_t name_code =
namespace_name(env, env->namespace, Texts(name, "$", get_line_number(ast->file, ast->start)));
return compile_function(env, name_code, ast, &env->code->staticdefs);
@@ -111,15 +121,13 @@ static Text_t compile_top_level_code(env_t *env, ast_t *ast) {
type_t *t = Table$str_get(*env->types, def->name);
assert(t && t->tag == StructType);
Text_t code = compile_struct_typeinfo(env, t, def->name, def->fields, def->secret, def->opaque);
- env_t *ns_env = namespace_env(env, def->name);
- return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT);
+ return Texts(code, compile_namespace(env, def->name, def->namespace));
}
case EnumDef: {
DeclareMatch(def, ast, EnumDef);
Text_t code = compile_enum_typeinfo(env, ast);
code = Texts(code, compile_enum_constructors(env, ast));
- env_t *ns_env = namespace_env(env, def->name);
- return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT);
+ return Texts(code, compile_namespace(env, def->name, def->namespace));
}
case LangDef: {
DeclareMatch(def, ast, LangDef);
@@ -127,8 +135,7 @@ static Text_t compile_top_level_code(env_t *env, ast_t *ast) {
Texts("public const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, "$$info")), " = {",
(int64_t)sizeof(Text_t), ", ", (int64_t)__alignof__(Text_t),
", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", quoted_str(def->name), "}};\n");
- env_t *ns_env = namespace_env(env, def->name);
- return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT);
+ return Texts(code, compile_namespace(env, def->name, def->namespace));
}
case Extend: {
DeclareMatch(extend, ast, Extend);
diff --git a/src/compile/functions.c b/src/compile/functions.c
index 6caefa8b..f04a3b59 100644
--- a/src/compile/functions.c
+++ b/src/compile/functions.c
@@ -256,18 +256,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) {
set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name));
}
- type_t *ret_t = get_type(body_scope, lambda->body);
- if (ret_t->tag == ReturnType) ret_t = Match(ret_t, ReturnType)->ret;
-
- if (lambda->ret_type) {
- type_t *declared = parse_type_ast(env, lambda->ret_type);
- if (can_promote(ret_t, declared)) ret_t = declared;
- else
- code_err(ast, "This function was declared to return a value of type ", type_to_str(declared),
- ", but actually returns a value of type ", type_to_str(ret_t));
- }
-
- body_scope->fn_ret = ret_t;
+ body_scope->fn = ast;
Table_t closed_vars = get_closed_vars(env, lambda->args, ast);
if (Table$length(closed_vars) > 0) { // Create a typedef for the lambda's closure userdata
@@ -289,6 +278,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) {
env->code->local_typedefs = Texts(env->code->local_typedefs, def);
}
+ type_t *ret_t = get_function_return_type(env, ast);
Text_t code = Texts("static ", compile_type(ret_t), " ", name, "(");
for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
@@ -623,7 +613,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
bool is_private = false;
const char *function_name;
arg_ast_t *args;
- type_t *ret_t;
+ type_t *ret_t = get_function_return_type(env, ast);
ast_t *body;
ast_t *cache;
bool is_inline;
@@ -632,14 +622,12 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
function_name = Match(fndef->name, Var)->name;
is_private = function_name[0] == '_';
args = fndef->args;
- ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType);
body = fndef->body;
cache = fndef->cache;
is_inline = fndef->is_inline;
} else {
DeclareMatch(convertdef, ast, ConvertDef);
args = convertdef->args;
- ret_t = convertdef->ret_type ? parse_type_ast(env, convertdef->ret_type) : Type(VoidType);
function_name = get_type_name(ret_t);
if (!function_name)
code_err(ast,
@@ -689,7 +677,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name));
}
- body_scope->fn_ret = ret_t;
+ body_scope->fn = ast;
type_t *body_type = get_type(body_scope, body);
if (ret_t->tag == AbortType) {
diff --git a/src/compile/reductions.c b/src/compile/reductions.c
index e0477a9c..438e072b 100644
--- a/src/compile/reductions.c
+++ b/src/compile/reductions.c
@@ -12,6 +12,7 @@ public
Text_t compile_reduction(env_t *env, ast_t *ast) {
DeclareMatch(reduction, ast, Reduction);
ast_e op = reduction->op;
+ const char *op_str = binop_info[op].operator;
type_t *iter_t = get_type(env, reduction->iter);
type_t *item_t = get_iterated_type(iter_t);
@@ -29,7 +30,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) {
type_t *item_value_type = item_t;
ast_t *item_value = item;
if (reduction->key) {
- set_binding(body_scope, "$", item_t, compile(body_scope, item));
+ set_binding(body_scope, op_str, item_t, compile(body_scope, item));
item_value = reduction->key;
item_value_type = get_type(body_scope, reduction->key);
}
@@ -67,7 +68,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) {
ast_e cmp_op = op == Min ? LessThan : GreaterThan;
if (reduction->key) {
env_t *key_scope = fresh_scope(env);
- set_binding(key_scope, "$", item_t, item_code);
+ set_binding(key_scope, op_str, item_t, item_code);
type_t *key_type = get_type(key_scope, reduction->key);
Text_t superlative_key = op == Min ? Text("min_key") : Text("max_key");
code = Texts(code, compile_declaration(key_type, superlative_key), ";\n");
@@ -111,7 +112,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) {
type_t *reduction_type = Match(get_type(env, ast), OptionalType)->type;
ast_t *item_value = item;
if (reduction->key) {
- set_binding(body_scope, "$", item_t, compile(body_scope, item));
+ set_binding(body_scope, op_str, item_t, compile(body_scope, item));
item_value = reduction->key;
}
diff --git a/src/compile/statements.c b/src/compile/statements.c
index a7c5214a..bde9ae36 100644
--- a/src/compile/statements.c
+++ b/src/compile/statements.c
@@ -25,6 +25,14 @@ Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) {
return Texts("\n#line ", line, "\n", code);
}
+static Text_t compile_simple_update_assignment(env_t *env, ast_t *ast, const char *op) {
+ binary_operands_t update = BINARY_OPERANDS(ast);
+ type_t *lhs_t = get_type(env, update.lhs);
+ if (is_idempotent(update.lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType))
+ return Texts(compile_lvalue(env, update.lhs), " ", op, "= ", compile_to_type(env, update.rhs, lhs_t), ";");
+ return compile_update_assignment(env, ast);
+}
+
static Text_t _compile_statement(env_t *env, ast_t *ast) {
switch (ast->tag) {
case When: return compile_when_statement(env, ast);
@@ -47,41 +55,12 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) {
}
}
case Assign: return compile_assignment_statement(env, ast);
- case PlusUpdate: {
- DeclareMatch(update, ast, PlusUpdate);
- type_t *lhs_t = get_type(env, update->lhs);
- if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType))
- return Texts(compile_lvalue(env, update->lhs), " += ", compile_to_type(env, update->rhs, lhs_t), ";");
- return compile_update_assignment(env, ast);
- }
- case MinusUpdate: {
- DeclareMatch(update, ast, MinusUpdate);
- type_t *lhs_t = get_type(env, update->lhs);
- if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType))
- return Texts(compile_lvalue(env, update->lhs), " -= ", compile_to_type(env, update->rhs, lhs_t), ";");
- return compile_update_assignment(env, ast);
- }
- case MultiplyUpdate: {
- DeclareMatch(update, ast, MultiplyUpdate);
- type_t *lhs_t = get_type(env, update->lhs);
- if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType))
- return Texts(compile_lvalue(env, update->lhs), " *= ", compile_to_type(env, update->rhs, lhs_t), ";");
- return compile_update_assignment(env, ast);
- }
- case DivideUpdate: {
- DeclareMatch(update, ast, DivideUpdate);
- type_t *lhs_t = get_type(env, update->lhs);
- if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType))
- return Texts(compile_lvalue(env, update->lhs), " /= ", compile_to_type(env, update->rhs, lhs_t), ";");
- return compile_update_assignment(env, ast);
- }
- case ModUpdate: {
- DeclareMatch(update, ast, ModUpdate);
- type_t *lhs_t = get_type(env, update->lhs);
- if (is_idempotent(update->lhs) && (lhs_t->tag == IntType || lhs_t->tag == NumType || lhs_t->tag == ByteType))
- return Texts(compile_lvalue(env, update->lhs), " %= ", compile_to_type(env, update->rhs, lhs_t), ";");
- return compile_update_assignment(env, ast);
- }
+ case PlusUpdate: return compile_simple_update_assignment(env, ast, "+");
+ case MinusUpdate: return compile_simple_update_assignment(env, ast, "-");
+ case MultiplyUpdate: return compile_simple_update_assignment(env, ast, "*");
+ case DivideUpdate: return compile_simple_update_assignment(env, ast, "/");
+ case ModUpdate: return compile_simple_update_assignment(env, ast, "%");
+
case PowerUpdate:
case Mod1Update:
case ConcatUpdate:
@@ -131,7 +110,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) {
return code;
}
case Return: {
- if (!env->fn_ret) code_err(ast, "This return statement is not inside any function");
+ if (!env->fn) code_err(ast, "This return statement is not inside any function");
ast_t *ret = Match(ast, Return)->value;
Text_t code = EMPTY_TEXT;
@@ -139,22 +118,30 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) {
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
}
+ type_t *ret_type = get_function_return_type(env, env->fn);
if (ret) {
- if (env->fn_ret->tag == VoidType || env->fn_ret->tag == AbortType)
+ if (ret_type->tag == VoidType || ret_type->tag == AbortType)
code_err(ast, "This function is not supposed to return any values, "
"according to its type signature");
- env = with_enum_scope(env, env->fn_ret);
- Text_t value = compile_to_type(env, ret, env->fn_ret);
+ env = with_enum_scope(env, ret_type);
+ if (env->fn->tag == ConvertDef) {
+ type_t *value_type = get_type(env, ret);
+ if (!type_eq(value_type, ret_type)) {
+ code_err(ret, "This value is a ", type_to_text(value_type),
+ " but this conversion needs an explicit ", type_to_text(ret_type));
+ }
+ }
+ Text_t value = compile_to_type(env, ret, ret_type);
if (env->deferred) {
- code = Texts(compile_declaration(env->fn_ret, Text("ret")), " = ", value, ";\n", code);
+ code = Texts(compile_declaration(ret_type, Text("ret")), " = ", value, ";\n", code);
value = Text("ret");
}
return Texts(code, "return ", value, ";");
} else {
- if (env->fn_ret->tag != VoidType)
- code_err(ast, "This function expects you to return a ", type_to_str(env->fn_ret), " value");
+ if (ret_type->tag != VoidType)
+ code_err(ast, "This function expects you to return a ", type_to_text(ret_type), " value");
return Texts(code, "return;");
}
}