aboutsummaryrefslogtreecommitdiff
path: root/src/sema
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-31 17:55:16 +0200
committerhachem <im@hachem.wtf>2026-08-31 17:55:16 +0200
commitcbdb9073480c3e4d8a088b306c23406cf42e25c0 (patch)
tree39f3093654cc8f27ea701ed1338cac84d93f42eb /src/sema
parent53aed3fadf1f7ad66dea9a8a0b46bf42eda921be (diff)
feat: hex/binary integer literals and constant-folding const expressions
Diffstat (limited to 'src/sema')
-rw-r--r--src/sema/sema.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/sema/sema.c b/src/sema/sema.c
index fb53bbf..85907e9 100644
--- a/src/sema/sema.c
+++ b/src/sema/sema.c
@@ -81,6 +81,65 @@ static bool check_entry_point(struct Source source, struct Program* program)
return false;
}
+static bool is_program_const(struct Program* program, struct Token name)
+{
+ for (size_t i = 0; i < program->const_count; i += 1)
+ if (names_equal(program->consts[i].name, name))
+ return true;
+
+ return false;
+}
+
+static struct Token first_token(struct Expr* expr)
+{
+ switch (expr->kind)
+ {
+ case EXPR_BINARY: return first_token(expr->binary.left);
+ case EXPR_MEMBER: return first_token(expr->member.object);
+ case EXPR_DEREF: return first_token(expr->deref.address);
+ default: return expr->primary.token;
+ }
+}
+
+static bool check_const_value(struct Source source, struct Program* program, struct Expr* expr)
+{
+ if (expr->kind == EXPR_BINARY)
+ {
+ bool left = check_const_value(source, program, expr->binary.left);
+ bool right = check_const_value(source, program, expr->binary.right);
+ return left && right;
+ }
+
+ if (expr->kind == EXPR_PRIMARY)
+ {
+ struct Token token = expr->primary.token;
+ if (token.type == TOKEN_INTEGER || token.type == TOKEN_CHAR)
+ return true;
+
+ if (token.type == TOKEN_IDENTIFIER && is_program_const(program, token))
+ return true;
+
+ char message[128];
+ snprintf(message, sizeof(message), "'%.*s' is not a constant",
+ (int)token.length, token.start);
+ report_error(source, token, message);
+ return false;
+ }
+
+ report_error(source, first_token(expr), "constant must be an integer expression");
+ return false;
+}
+
+static bool check_const_values(struct Source source, struct Program* program)
+{
+ bool ok = true;
+ for (size_t i = 0; i < program->const_count; i += 1)
+ if (!check_const_value(source, program, program->consts[i].value))
+ ok = false;
+
+ return ok;
+}
+
struct RefCheck
{
struct Source source;
@@ -335,6 +394,8 @@ bool analyze_program(struct Source source, struct Program* program)
ok = false;
if (!check_entry_point(source, program))
ok = false;
+ if (!check_const_values(source, program))
+ ok = false;
if (!check_references(source, program))
ok = false;