From eed806962db3bc0cc1b11dd0c79089fc4afc11f2 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 4 Jan 2025 00:26:21 +0100 Subject: [PATCH] Allow compile time `$foreach` iteration over constant Strings and bytes. --- releasenotes.md | 1 + src/compiler/sema_stmts.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index b96a1cffd..112a5ce5c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -16,6 +16,7 @@ - Support experimental `@operator(construct)` operator overload. - Allow using 'var' to declare lambdas in functions. - Add 'validation' setting and make dead code a warning. +- Allow compile time `$foreach` iteration over constant Strings and bytes. ### Fixes - Fix case trying to initialize a `char[*]*` from a String. diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index a8851fa4a..8b685feac 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2648,7 +2648,8 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state unsigned ct_context = sema_context_push_ct_stack(context); Expr *collection = exprptr(statement->ct_foreach_stmt.expr); if (!sema_analyse_ct_expr(context, collection)) return false; - if (!expr_is_const_untyped_list(collection) && !expr_is_const_initializer(collection)) + if (!expr_is_const_untyped_list(collection) && !expr_is_const_initializer(collection) + && !expr_is_const_string(collection) && !expr_is_const_bytes(collection)) { SEMA_ERROR(collection, "Expected a list to iterate over"); goto FAILED; @@ -2657,6 +2658,8 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state ConstInitializer *initializer = NULL; Expr **expressions = NULL; Type *const_list_type = NULL; + const char *bytes = NULL; + Type *bytes_type; if (expr_is_const_initializer(collection)) { initializer = collection->const_expr.initializer; @@ -2683,11 +2686,17 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state count = vec_size(initializer->init_array_full); } } - else + else if (expr_is_const_untyped_list(collection)) { expressions = collection->const_expr.untyped_list; count = vec_size(expressions); } + else + { + bytes = collection->const_expr.bytes.ptr; + count = collection->const_expr.bytes.len; + bytes_type = type_get_indexed_type(collection->type); + } Decl *index = declptrzero(statement->ct_foreach_stmt.index); AstId start = 0; @@ -2710,6 +2719,11 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state { value->var.init_expr = expressions[i]; } + else if (bytes) + { + value->var.init_expr = expr_new(EXPR_CONST, collection->span); + expr_rewrite_const_int(value->var.init_expr, bytes_type, bytes[i]); + } else { Expr *expr = expr_new(EXPR_CONST, collection->span);