diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-04-10 11:49:43 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-04-10 11:49:43 -0400 |
| commit | 4f514378accd7a5ed8774d008761efa94f383148 (patch) | |
| tree | 1682ac995b84327bee6ac29cd379aea4f02fa5ae | |
| parent | 438edf45c27da9aa2503a5bcf50f34475c8bc63d (diff) | |
Fix corecursive functions and global variables
| -rw-r--r-- | ast.c | 23 | ||||
| -rw-r--r-- | ast.h | 1 | ||||
| -rw-r--r-- | compile.c | 26 |
3 files changed, 46 insertions, 4 deletions
@@ -196,4 +196,27 @@ bool is_idempotent(ast_t *ast) } } +bool is_constant(ast_t *ast) +{ + switch (ast->tag) { + case Bool: case Int: case Num: case Nil: case TextLiteral: return true; + case TextJoin: { + auto text = Match(ast, TextJoin); + return !text->children->next; + } + case Not: return is_constant(Match(ast, Not)->value); + case Negative: return is_constant(Match(ast, Negative)->value); + case BinaryOp: { + auto binop = Match(ast, BinaryOp); + switch (binop->op) { + case BINOP_UNKNOWN: case BINOP_POWER: case BINOP_CONCAT: case BINOP_MIN: case BINOP_MAX: case BINOP_CMP: + return false; + default: + return is_constant(binop->lhs) && is_constant(binop->rhs); + } + } + default: return false; + } +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -279,5 +279,6 @@ CORD type_ast_to_xml(type_ast_t *ast); int printf_ast(FILE *stream, const struct printf_info *info, const void *const args[]); ast_list_t *get_ast_children(ast_t *ast); bool is_idempotent(ast_t *ast); +bool is_constant(ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 @@ -443,7 +443,7 @@ CORD compile_statement(env_t *env, ast_t *ast) code = CORD_cat("public ", code); } - env_t *body_scope = global_scope(env); + env_t *body_scope = fresh_scope(env); for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) { type_t *arg_type = get_arg_ast_type(env, arg); set_binding(body_scope, arg->name, new(binding_t, .type=arg_type, .code=arg->name)); @@ -1887,9 +1887,27 @@ module_code_t compile_file(ast_t *ast) for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { bind_statement(env, stmt->ast); - CORD code = compile_statement(env, stmt->ast); - if (code) - CORD_appendf(&env->code->main, "%r\n", code); + } + for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) { + if (stmt->ast->tag == Declare) { + auto decl = Match(stmt->ast, Declare); + type_t *t = get_type(env, decl->value); + if (t->tag == AbortType || t->tag == VoidType) + code_err(stmt->ast, "You can't declare a variable with a %T value", t); + if (!is_constant(decl->value)) + code_err(decl->value, "This value is not a valid constant initializer."); + env->code->fndefs = CORD_all( + env->code->fndefs, + compile_declaration(env, t, Match(decl->var, Var)->name), ";\n"); + env->code->staticdefs = CORD_all( + env->code->staticdefs, + "extern ", compile_type(env, t), " ", Match(decl->var, Var)->name, " = ", + compile(env, decl->value), ";\n"); + } else { + CORD code = compile_statement(env, stmt->ast); + if (code) + CORD_appendf(&env->code->main, "%r\n", code); + } } return (module_code_t){ |
