mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
CT variables now follow CT scopes. It's now allowed to mutate CT variables in deeper runtime scopes.
This commit is contained in:
committed by
Christoffer Lerno
parent
f7659776fc
commit
1ea5625183
@@ -35,6 +35,13 @@ Decl *decl_new(DeclKind decl_kind, const char *name, SourceSpan span, Visibility
|
||||
return decl;
|
||||
}
|
||||
|
||||
bool decl_is_ct_var(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind != DECL_VAR) return false;
|
||||
return decl_var_kind_is_ct(decl->var.kind);
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type, Visibility visibility)
|
||||
{
|
||||
Decl *decl = decl_calloc();
|
||||
|
||||
@@ -441,7 +441,6 @@ typedef struct VarDecl_
|
||||
struct SemaContext_ *context;
|
||||
SourceSpan span;
|
||||
} hash_var;
|
||||
unsigned scope_depth; // CT var
|
||||
struct
|
||||
{
|
||||
void *backend_debug_ref;
|
||||
@@ -1627,6 +1626,7 @@ typedef struct SemaContext_
|
||||
Ast **returns_cache;
|
||||
Expr **macro_varargs;
|
||||
Decl **macro_params;
|
||||
Decl** ct_locals;
|
||||
};
|
||||
Type *rtype;
|
||||
struct SemaContext_ *yield_context;
|
||||
@@ -2082,6 +2082,7 @@ INLINE const char *decl_get_extname(Decl *decl);
|
||||
static inline Decl *decl_raw(Decl *decl);
|
||||
static inline DeclKind decl_from_token(TokenType type);
|
||||
static inline bool decl_is_local(Decl *decl);
|
||||
bool decl_is_ct_var(Decl *decl);
|
||||
Decl *decl_find_enum_constant(Decl *decl, const char *name);
|
||||
AlignSize decl_find_member_offset(Decl *decl, Decl *member);
|
||||
|
||||
@@ -3162,6 +3163,11 @@ INLINE bool expr_is_const(Expr *expr)
|
||||
return expr->expr_kind == EXPR_CONST;
|
||||
}
|
||||
|
||||
INLINE bool decl_var_kind_is_ct(VarDeclKind kind)
|
||||
{
|
||||
return kind >= VARDECL_FIRST_CT && kind <= VARDECL_LAST_CT;
|
||||
}
|
||||
|
||||
static inline bool decl_is_local(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind != DECL_VAR) return false;
|
||||
|
||||
@@ -702,15 +702,17 @@ typedef enum
|
||||
VARDECL_PARAM,
|
||||
VARDECL_MEMBER,
|
||||
VARDECL_BITMEMBER,
|
||||
VARDECL_PARAM_CT,
|
||||
VARDECL_PARAM_CT_TYPE,
|
||||
VARDECL_PARAM_REF,
|
||||
VARDECL_PARAM_EXPR,
|
||||
VARDECL_LOCAL_CT,
|
||||
VARDECL_LOCAL_CT_TYPE,
|
||||
VARDECL_UNWRAPPED,
|
||||
VARDECL_ERASE,
|
||||
VARDECL_REWRAPPED,
|
||||
VARDECL_PARAM_CT,
|
||||
VARDECL_PARAM_CT_TYPE,
|
||||
VARDECL_LOCAL_CT,
|
||||
VARDECL_LOCAL_CT_TYPE,
|
||||
VARDECL_FIRST_CT = VARDECL_PARAM_CT,
|
||||
VARDECL_LAST_CT = VARDECL_LOCAL_CT_TYPE,
|
||||
} VarDeclKind;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -2365,10 +2365,8 @@ bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
decl->var.scope_depth = context->active_scope.depth;
|
||||
return sema_add_local(context, decl);
|
||||
FAIL:
|
||||
decl->var.scope_depth = context->active_scope.depth;
|
||||
sema_add_local(context, decl);
|
||||
return decl_poison(decl);
|
||||
}
|
||||
|
||||
@@ -1641,10 +1641,6 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
}
|
||||
param->var.init_expr = args[i];
|
||||
VarDeclKind kind = param->var.kind;
|
||||
if (kind == VARDECL_PARAM_CT_TYPE || kind == VARDECL_PARAM_CT)
|
||||
{
|
||||
param->var.scope_depth = context->active_scope.depth + 1;
|
||||
}
|
||||
}
|
||||
|
||||
Decl **body_params = call_expr->call_expr.body_arguments;
|
||||
@@ -3928,11 +3924,6 @@ static inline bool sema_binary_analyse_ct_identifier_lvalue(SemaContext *context
|
||||
return expr_poison(expr);
|
||||
}
|
||||
|
||||
if (decl->var.scope_depth < context->active_scope.depth)
|
||||
{
|
||||
SEMA_ERROR(expr, "Cannot modify '%s' inside of a runtime scope.", decl->name);
|
||||
return false;
|
||||
}
|
||||
expr->ct_ident_expr.decl = decl;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
@@ -5367,12 +5358,6 @@ static inline bool sema_expr_analyse_ct_incdec(SemaContext *context, Expr *expr,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (var->var.scope_depth < context->active_scope.depth)
|
||||
{
|
||||
SEMA_ERROR(expr, "Cannot modify '%s' inside of a runtime scope.", var->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
Expr *end_value = expr_copy(start_value);
|
||||
|
||||
// Make the change.
|
||||
|
||||
@@ -54,6 +54,8 @@ TokenType sema_splitpathref(const char *string, ArraySize len, Path **path_ref,
|
||||
|
||||
void sema_context_init(SemaContext *context, CompilationUnit *unit);
|
||||
void sema_context_destroy(SemaContext *context);
|
||||
unsigned sema_context_push_ct_stack(SemaContext *context);
|
||||
void sema_context_pop_ct_stack(SemaContext *context, unsigned old_state);
|
||||
|
||||
bool sema_analyse_function_body(SemaContext *context, Decl *func);
|
||||
bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts);
|
||||
|
||||
@@ -385,8 +385,18 @@ static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_re
|
||||
return decl ? decl : sema_find_decl_in_global_new(unit, &global_context.symbols, global_context.module_list, name_resolve, false);
|
||||
}
|
||||
|
||||
static inline Decl *sema_find_ct_local(SemaContext *context, const char *symbol)
|
||||
{
|
||||
Decl **locals = context->ct_locals;
|
||||
FOREACH_BEGIN(Decl *cur, locals)
|
||||
if (cur->name == symbol) return cur;
|
||||
FOREACH_END();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline Decl *sema_find_local(SemaContext *context, const char *symbol)
|
||||
{
|
||||
if (symbol[0] == '$') return sema_find_ct_local(context, symbol);
|
||||
Decl **locals = context->locals;
|
||||
if (!locals || !context->active_scope.current_local) return NULL;
|
||||
int64_t first = 0;
|
||||
@@ -793,6 +803,7 @@ Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path,
|
||||
|
||||
static inline void sema_append_local(SemaContext *context, Decl *decl)
|
||||
{
|
||||
assert(!decl_is_ct_var(decl));
|
||||
Decl ***locals = &context->locals;
|
||||
size_t locals_size = vec_size(*locals);
|
||||
size_t current_local = context->active_scope.current_local;
|
||||
@@ -811,13 +822,32 @@ static inline void sema_append_local(SemaContext *context, Decl *decl)
|
||||
context->active_scope.current_local++;
|
||||
}
|
||||
|
||||
INLINE bool sema_add_ct_local(SemaContext *context, Decl *decl)
|
||||
{
|
||||
assert(decl_is_ct_var(decl));
|
||||
|
||||
Decl *other = sema_find_ct_local(context, decl->name);
|
||||
if (other)
|
||||
{
|
||||
sema_shadow_error(decl, other);
|
||||
decl_poison(decl);
|
||||
decl_poison(other);
|
||||
return false;
|
||||
}
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
vec_add(context->ct_locals, decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sema_add_local(SemaContext *context, Decl *decl)
|
||||
{
|
||||
CompilationUnit *current_unit = decl->unit = context->unit;
|
||||
|
||||
// Ignore synthetic locals.
|
||||
if (!decl->name) return true;
|
||||
if (decl->decl_kind == DECL_VAR && decl->var.shadow) goto ADD_VAR;
|
||||
bool is_var = decl->decl_kind == DECL_VAR;
|
||||
if (is_var && decl_var_kind_is_ct(decl->var.kind)) return sema_add_ct_local(context, decl);
|
||||
if (is_var && decl->var.shadow) goto ADD_VAR;
|
||||
|
||||
Decl *other = sema_find_local(context, decl->name);
|
||||
assert(!other || other->unit->module);
|
||||
@@ -834,6 +864,7 @@ ADD_VAR:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void sema_unwrap_var(SemaContext *context, Decl *decl)
|
||||
{
|
||||
Decl *alias = decl_copy(decl);
|
||||
|
||||
@@ -1829,9 +1829,14 @@ static inline bool sema_analyse_then_overwrite(SemaContext *context, Ast *statem
|
||||
|
||||
static inline bool sema_analyse_ct_if_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
unsigned ct_context = sema_context_push_ct_stack(context);
|
||||
int res = sema_check_comp_time_bool(context, statement->ct_if_stmt.expr);
|
||||
if (res == -1) return false;
|
||||
if (res) return sema_analyse_then_overwrite(context, statement, statement->ct_if_stmt.then);
|
||||
if (res == -1) goto FAILED;
|
||||
if (res)
|
||||
{
|
||||
if (sema_analyse_then_overwrite(context, statement, statement->ct_if_stmt.then)) goto SUCCESS;
|
||||
goto FAILED;
|
||||
}
|
||||
Ast *elif = astptrzero(statement->ct_if_stmt.elif);
|
||||
while (1)
|
||||
{
|
||||
@@ -1839,20 +1844,31 @@ static inline bool sema_analyse_ct_if_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
// Turn into NOP!
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
return true;
|
||||
goto SUCCESS;
|
||||
}
|
||||
// We found else, then just replace with that.
|
||||
if (elif->ast_kind == AST_CT_ELSE_STMT)
|
||||
{
|
||||
return sema_analyse_then_overwrite(context, statement, elif->ct_else_stmt);
|
||||
if (sema_analyse_then_overwrite(context, statement, elif->ct_else_stmt)) goto SUCCESS;
|
||||
goto FAILED;
|
||||
}
|
||||
assert(elif->ast_kind == AST_CT_IF_STMT);
|
||||
|
||||
res = sema_check_comp_time_bool(context, elif->ct_if_stmt.expr);
|
||||
if (res == -1) return false;
|
||||
if (res) return sema_analyse_then_overwrite(context, statement, elif->ct_if_stmt.then);
|
||||
if (res == -1) goto FAILED;
|
||||
if (res)
|
||||
{
|
||||
if (sema_analyse_then_overwrite(context, statement, elif->ct_if_stmt.then)) goto SUCCESS;
|
||||
goto FAILED;
|
||||
}
|
||||
elif = astptrzero(elif->ct_if_stmt.elif);
|
||||
}
|
||||
SUCCESS:
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
return true;
|
||||
FAILED:
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_compound_statement_no_scope(SemaContext *context, Ast *compound_statement)
|
||||
@@ -2083,9 +2099,10 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc
|
||||
|
||||
static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
unsigned ct_context = sema_context_push_ct_stack(context);
|
||||
// Evaluate the switch statement
|
||||
Expr *cond = exprptr(statement->ct_switch_stmt.cond);
|
||||
if (!sema_analyse_ct_expr(context, cond)) return false;
|
||||
if (!sema_analyse_ct_expr(context, cond)) goto FAILED;
|
||||
|
||||
// If we have a type, then we do different evaluation
|
||||
// compared to when it is a value.
|
||||
@@ -2105,7 +2122,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
SEMA_ERROR(cond, "Only types, strings, integers, floats and booleans may be used with '$switch'.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
|
||||
ExprConst *switch_expr_const = &cond->const_expr;
|
||||
@@ -2132,39 +2149,39 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
||||
if (!type_is_integer(type) && !type_is_float(type))
|
||||
{
|
||||
SEMA_ERROR(to_expr, "$case ranges are only allowed for floats and integers.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
if (is_type)
|
||||
{
|
||||
if (!sema_analyse_ct_expr(context, expr)) return false;
|
||||
if (!sema_analyse_ct_expr(context, expr)) goto FAILED;
|
||||
if (expr->type != type_typeid)
|
||||
{
|
||||
SEMA_ERROR(expr, "A type was expected here not %s.", type_quoted_error_string(expr->type));
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr_rhs(context, type, expr, false)) return false;
|
||||
if (to_expr && !sema_analyse_expr_rhs(context, type, to_expr, false)) return false;
|
||||
if (!sema_analyse_expr_rhs(context, type, expr, false)) goto FAILED;
|
||||
if (to_expr && !sema_analyse_expr_rhs(context, type, to_expr, false)) goto FAILED;
|
||||
}
|
||||
if (!expr_is_const(expr))
|
||||
{
|
||||
SEMA_ERROR(expr, "The $case must have a constant expression.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
if (to_expr && !expr_is_const(to_expr))
|
||||
{
|
||||
SEMA_ERROR(to_expr, "The $case must have a constant expression.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
ExprConst *const_expr = &expr->const_expr;
|
||||
ExprConst *const_to_expr = to_expr ? &to_expr->const_expr : const_expr;
|
||||
if (to_expr && expr_const_compare(const_expr, const_to_expr, BINARYOP_GT))
|
||||
{
|
||||
SEMA_ERROR(to_expr, "The end of a range must be less or equal to the beginning.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
// Check that it is unique.
|
||||
for (unsigned j = 0; j < i; j++)
|
||||
@@ -2177,7 +2194,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
||||
{
|
||||
SEMA_ERROR(stmt, "'%s' appears more than once.", expr_const_to_error_string(const_expr));
|
||||
SEMA_NOTE(cases[j]->case_stmt.expr, "The previous $case was here.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
if (expr_const_in_range(switch_expr_const, const_expr, const_to_expr))
|
||||
@@ -2191,7 +2208,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
||||
{
|
||||
SEMA_ERROR(stmt, "More than one $default is not allowed.");
|
||||
SEMA_NOTE(cases[default_case], "The previous $default was here.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
default_case = (int)i;
|
||||
continue;
|
||||
@@ -2211,20 +2228,27 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
||||
if (!body)
|
||||
{
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
return true;
|
||||
goto SUCCESS;
|
||||
}
|
||||
return sema_analyse_then_overwrite(context, statement, body->compound_stmt.first_stmt);
|
||||
if (!sema_analyse_then_overwrite(context, statement, body->compound_stmt.first_stmt)) goto FAILED;
|
||||
SUCCESS:
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
return true;
|
||||
FAILED:
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
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))
|
||||
{
|
||||
SEMA_ERROR(collection, "Expected a list to iterate over");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
unsigned count;
|
||||
ConstInitializer *initializer = NULL;
|
||||
@@ -2242,11 +2266,15 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state
|
||||
else
|
||||
{
|
||||
// Empty list
|
||||
if (init_type == CONST_INIT_ZERO) return true;
|
||||
if (init_type == CONST_INIT_ZERO)
|
||||
{
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
return true;
|
||||
}
|
||||
if (init_type != CONST_INIT_ARRAY_FULL)
|
||||
{
|
||||
SEMA_ERROR(collection, "Only regular arrays are allowed here.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
count = vec_size(initializer->init_array_full);
|
||||
}
|
||||
@@ -2260,48 +2288,52 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state
|
||||
const char *index_name = statement->ct_foreach_stmt.index_name;
|
||||
|
||||
AstId start = 0;
|
||||
SCOPE_START;
|
||||
if (index_name)
|
||||
if (index_name)
|
||||
{
|
||||
index = decl_new_var(index_name, statement->ct_foreach_stmt.index_span, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL);
|
||||
index->type = type_int;
|
||||
if (!sema_add_local(context, index)) goto FAILED;
|
||||
}
|
||||
Decl *value = decl_new_var(statement->ct_foreach_stmt.value_name, statement->ct_foreach_stmt.value_span, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL);
|
||||
if (!sema_add_local(context, value)) goto FAILED;
|
||||
// Get the body
|
||||
Ast *body = astptr(statement->ct_foreach_stmt.body);
|
||||
AstId *current = &start;
|
||||
unsigned loop_context = sema_context_push_ct_stack(context);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
sema_context_pop_ct_stack(context, loop_context);
|
||||
Ast *compound_stmt = copy_ast_single(body);
|
||||
if (expressions)
|
||||
{
|
||||
index = decl_new_var(index_name, statement->ct_foreach_stmt.index_span, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL);
|
||||
value->var.init_expr = expressions[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
Expr *expr = expr_new(EXPR_CONST, collection->span);
|
||||
if (!expr_rewrite_to_const_initializer_index(const_list_type, initializer, expr, i))
|
||||
{
|
||||
SEMA_ERROR(collection, "Complex expressions are not allowed.");
|
||||
goto FAILED;
|
||||
}
|
||||
value->var.init_expr = expr;
|
||||
}
|
||||
if (index)
|
||||
{
|
||||
index->var.init_expr = expr_new_const_int(index->span, type_int, i, true);
|
||||
index->type = type_int;
|
||||
if (!sema_add_local(context, index)) return SCOPE_POP_ERROR();
|
||||
}
|
||||
Decl *value = decl_new_var(statement->ct_foreach_stmt.value_name, statement->ct_foreach_stmt.value_span, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL);
|
||||
if (!sema_add_local(context, value)) return SCOPE_POP_ERROR();
|
||||
// Get the body
|
||||
Ast *body = astptr(statement->ct_foreach_stmt.body);
|
||||
AstId *current = &start;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
Ast *compound_stmt = copy_ast_single(body);
|
||||
if (expressions)
|
||||
{
|
||||
value->var.init_expr = expressions[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
Expr *expr = expr_new(EXPR_CONST, collection->span);
|
||||
if (!expr_rewrite_to_const_initializer_index(const_list_type, initializer, expr, i))
|
||||
{
|
||||
SEMA_ERROR(collection, "Complex expressions are not allowed.");
|
||||
return false;
|
||||
}
|
||||
value->var.init_expr = expr;
|
||||
}
|
||||
if (index)
|
||||
{
|
||||
index->var.init_expr = expr_new_const_int(index->span, type_int, i, true);
|
||||
index->type = type_int;
|
||||
}
|
||||
if (!sema_analyse_compound_stmt(context, compound_stmt)) return SCOPE_POP_ERROR();
|
||||
*current = astid(compound_stmt);
|
||||
current = &compound_stmt->next;
|
||||
}
|
||||
SCOPE_END;
|
||||
if (!sema_analyse_compound_stmt(context, compound_stmt)) goto FAILED;
|
||||
*current = astid(compound_stmt);
|
||||
current = &compound_stmt->next;
|
||||
}
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
statement->ast_kind = AST_COMPOUND_STMT;
|
||||
statement->compound_stmt.first_stmt = start;
|
||||
return true;
|
||||
FAILED:
|
||||
sema_context_pop_ct_stack(context, ct_context);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement)
|
||||
@@ -2411,6 +2443,7 @@ bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement)
|
||||
*/
|
||||
static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
unsigned for_context = sema_context_push_ct_stack(context);
|
||||
bool success = false;
|
||||
ExprId init;
|
||||
if ((init = statement->for_stmt.init))
|
||||
@@ -2427,13 +2460,13 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
if (decl->decl_kind != DECL_VAR || (decl->var.kind != VARDECL_LOCAL_CT && decl->var.kind != VARDECL_LOCAL_CT_TYPE))
|
||||
{
|
||||
SEMA_ERROR(expr, "Only 'var $foo' and 'var $Type' declarations are allowed in '$for'");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
if (!sema_analyse_var_decl_ct(context, decl)) return false;
|
||||
if (!sema_analyse_var_decl_ct(context, decl)) goto FAILED;
|
||||
continue;
|
||||
}
|
||||
// If expression evaluate it and make sure it is constant.
|
||||
if (!sema_analyse_ct_expr(context, expr)) return false;
|
||||
if (!sema_analyse_ct_expr(context, expr)) goto FAILED;
|
||||
FOREACH_END();
|
||||
}
|
||||
ExprId condition = statement->for_stmt.cond;
|
||||
@@ -2445,16 +2478,18 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
assert(condition);
|
||||
// We set a maximum of macro iterations.
|
||||
// we might consider reducing this.
|
||||
unsigned current_ct_scope = sema_context_push_ct_stack(context);
|
||||
for (int i = 0; i < MAX_MACRO_ITERATIONS; i++)
|
||||
{
|
||||
sema_context_pop_ct_stack(context, current_ct_scope);
|
||||
// First evaluate the cond, which we note that we *must* have.
|
||||
// we need to make a copy
|
||||
Expr *copy = copy_expr_single(exprptr(condition));
|
||||
if (!sema_analyse_cond_expr(context, copy)) return false;
|
||||
if (!sema_analyse_cond_expr(context, copy)) goto FAILED;
|
||||
if (!expr_is_const(copy))
|
||||
{
|
||||
SEMA_ERROR(copy, "Expected a value that can be evaluated at compile time.");
|
||||
return false;
|
||||
goto FAILED;
|
||||
}
|
||||
// This is simple, since we know we have a boolean, just break if we reached "false"
|
||||
if (!copy->const_expr.b) break;
|
||||
@@ -2463,7 +2498,7 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
Ast *compound_stmt = copy_ast_single(body);
|
||||
|
||||
// Analyse the body
|
||||
if (!sema_analyse_compound_statement_no_scope(context, compound_stmt)) return false;
|
||||
if (!sema_analyse_compound_statement_no_scope(context, compound_stmt)) goto FAILED;
|
||||
|
||||
// Append it.
|
||||
*current = astid(compound_stmt);
|
||||
@@ -2471,13 +2506,16 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
|
||||
// Copy and evaluate all the expressions in "incr"
|
||||
FOREACH_BEGIN(Expr *expr, incr_list)
|
||||
if (!sema_analyse_ct_expr(context, copy_expr_single(expr))) return false;
|
||||
if (!sema_analyse_ct_expr(context, copy_expr_single(expr))) goto FAILED;
|
||||
FOREACH_END();
|
||||
}
|
||||
// Analysis is done turn the generated statements into a compound statement for lowering.
|
||||
statement->ast_kind = AST_COMPOUND_STMT;
|
||||
statement->compound_stmt = (AstCompoundStmt) { .first_stmt = start };
|
||||
return true;
|
||||
FAILED:
|
||||
sema_context_pop_ct_stack(context, for_context);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2718,6 +2756,7 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
|
||||
.label_start = 0,
|
||||
.current_local = 0
|
||||
};
|
||||
vec_resize(context->ct_locals, 0);
|
||||
|
||||
// Clear returns
|
||||
vec_resize(context->returns, 0);
|
||||
|
||||
@@ -321,13 +321,26 @@ void sema_analysis_run(void)
|
||||
|
||||
void sema_context_init(SemaContext *context, CompilationUnit *unit)
|
||||
{
|
||||
*context = (SemaContext) { .unit = unit, .compilation_unit = unit, .locals = global_context_acquire_locals_list() };
|
||||
*context = (SemaContext) { .unit = unit, .compilation_unit = unit,
|
||||
.ct_locals = global_context_acquire_locals_list(),
|
||||
.locals = global_context_acquire_locals_list() };
|
||||
}
|
||||
|
||||
void sema_context_pop_ct_stack(SemaContext *context, unsigned old_state)
|
||||
{
|
||||
vec_resize(context->ct_locals, old_state);
|
||||
}
|
||||
|
||||
unsigned sema_context_push_ct_stack(SemaContext *context)
|
||||
{
|
||||
return vec_size(context->ct_locals);
|
||||
}
|
||||
|
||||
void sema_context_destroy(SemaContext *context)
|
||||
{
|
||||
if (!context->unit) return;
|
||||
generic_context_release_locals_list(context->locals);
|
||||
generic_context_release_locals_list(context->ct_locals);
|
||||
}
|
||||
|
||||
Decl **global_context_acquire_locals_list(void)
|
||||
@@ -338,6 +351,7 @@ Decl **global_context_acquire_locals_list(void)
|
||||
}
|
||||
Decl **result = VECLAST(global_context.locals_list);
|
||||
vec_pop(global_context.locals_list);
|
||||
vec_resize(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.109"
|
||||
#define COMPILER_VERSION "0.3.111"
|
||||
Reference in New Issue
Block a user