diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-09-06 14:46:15 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-09-06 14:46:15 -0400 |
| commit | d8a48f64111f542f3afeb5d6e47ff092f9278d9f (patch) | |
| tree | 07c364503025bb2a26edd7b26f1ba9e8d25340f6 /src/compile | |
| parent | 12345a85d9c7d7a56ddf323247a4bdf347021b73 (diff) | |
| parent | 73246764f88f6f652316ee0c138a990d836698a7 (diff) | |
Merge branch 'main' into optional-list-indexing
Diffstat (limited to 'src/compile')
| -rw-r--r-- | src/compile/binops.c | 2 | ||||
| -rw-r--r-- | src/compile/comparisons.c | 14 | ||||
| -rw-r--r-- | src/compile/expressions.c | 5 | ||||
| -rw-r--r-- | src/compile/files.c | 45 | ||||
| -rw-r--r-- | src/compile/functions.c | 20 | ||||
| -rw-r--r-- | src/compile/reductions.c | 7 | ||||
| -rw-r--r-- | src/compile/statements.c | 71 |
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;"); } } |
