diff --git a/ast.c b/ast.c index 80681e1..25309e9 100644 --- a/ast.c +++ b/ast.c @@ -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 diff --git a/ast.h b/ast.h index 658f44c..1f0eb5a 100644 --- a/ast.h +++ b/ast.h @@ -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 diff --git a/compile.c b/compile.c index 335134e..0e23c94 100644 --- a/compile.c +++ b/compile.c @@ -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){