aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-04-23 12:50:30 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-04-23 12:50:30 -0400
commitfbb25decf062349b0f28b3027d6be34a11f2a812 (patch)
treeecbbf62e677833fcaff5e4033d92f43099fa6049
parent803995aea2b1012355c929a7e148d500cd253997 (diff)
Support struct literals as constants
-rw-r--r--ast.c24
-rw-r--r--ast.h1
-rw-r--r--compile.c4
-rw-r--r--typecheck.c36
-rw-r--r--typecheck.h1
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