Fix corecursive functions and global variables

This commit is contained in:
Bruce Hill 2024-04-10 11:49:43 -04:00
parent 438edf45c2
commit 4f514378ac
3 changed files with 46 additions and 4 deletions

23
ast.c
View File

@ -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

1
ast.h
View File

@ -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

View File

@ -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){