From fbb25decf062349b0f28b3027d6be34a11f2a812 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 23 Apr 2024 12:50:30 -0400 Subject: Support struct literals as constants --- ast.c | 24 ------------------------ ast.h | 1 - compile.c | 4 ++-- typecheck.c | 36 ++++++++++++++++++++++++++++++++++++ typecheck.h | 1 + 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/ast.c b/ast.c index 64464dc9..80681e10 100644 --- a/ast.c +++ b/ast.c @@ -196,28 +196,4 @@ 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 || !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); - } - } - case Use: return true; - 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 34c3ffa4..17ab7274 100644 --- a/ast.h +++ b/ast.h @@ -279,6 +279,5 @@ 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 f8f2dfe2..09507212 100644 --- a/compile.c +++ b/compile.c @@ -1867,7 +1867,7 @@ void compile_namespace(env_t *env, const char *ns_name, ast_t *block) auto decl = Match(ast, Declare); type_t *t = get_type(ns_env, decl->value); - if (!is_constant(decl->value)) + if (!is_constant(env, decl->value)) code_err(decl->value, "This value is supposed to be a compile-time constant, but I can't figure out how to make it one"); CORD var_decl = CORD_all(compile_type(env, t), " ", compile(ns_env, decl->var), " = ", compile(ns_env, decl->value), ";\n"); env->code->staticdefs = CORD_cat(env->code->staticdefs, var_decl); @@ -2117,7 +2117,7 @@ module_code_t compile_file(ast_t *ast) 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)) + if (!is_constant(env, decl->value)) code_err(decl->value, "This value is not a valid constant initializer."); if (is_private) { diff --git a/typecheck.c b/typecheck.c index 72551d97..38071c21 100644 --- a/typecheck.c +++ b/typecheck.c @@ -953,4 +953,40 @@ type_t *parse_type_string(env_t *env, const char *str) return ast ? parse_type_ast(env, ast) : NULL; } +bool is_constant(env_t *env, 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 || !text->children->next; + } + case Not: return is_constant(env, Match(ast, Not)->value); + case Negative: return is_constant(env, 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(env, binop->lhs) && is_constant(env, binop->rhs); + } + } + case Use: return true; + case FunctionCall: { + // Constructors are allowed: + auto call = Match(ast, FunctionCall); + if (call->fn->tag != Var) return false; + binding_t *b = get_binding(env, Match(call->fn, Var)->name); + if (b == NULL || b->type->tag != TypeInfoType) return false; + for (arg_ast_t *arg = call->args; arg; arg = arg->next) { + if (!is_constant(env, arg->value)) + return false; + } + return true; + } + default: return false; + } +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/typecheck.h b/typecheck.h index 295ac605..fd9f1f73 100644 --- a/typecheck.h +++ b/typecheck.h @@ -23,5 +23,6 @@ type_t *get_arg_ast_type(env_t *env, arg_ast_t *arg); bool can_be_mutated(env_t *env, ast_t *ast); type_t *parse_type_string(env_t *env, const char *str); type_t *get_method_type(env_t *env, ast_t *self, const char *name); +bool is_constant(env_t *env, ast_t *ast); // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 -- cgit v1.2.3