summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser.h5
-rw-r--r--src/parser/parser_expr.c208
-rw-r--r--src/parser/parser_stmt.c46
-rw-r--r--src/parser/parser_utils.c15
4 files changed, 257 insertions, 17 deletions
diff --git a/src/parser/parser.h b/src/parser/parser.h
index b3837eb..f82edf4 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -42,6 +42,7 @@ typedef struct Symbol
Token decl_token;
int is_const_value;
int const_int_val;
+ int is_moved;
struct Symbol *next;
} Symbol;
@@ -427,6 +428,10 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l);
ASTNode *parse_impl(ParserContext *ctx, Lexer *l);
ASTNode *parse_impl_trait(ParserContext *ctx, Lexer *l);
ASTNode *parse_test(ParserContext *ctx, Lexer *l);
+
+// Move semantics helpers
+int is_type_copy(Type *t);
+void check_move_usage(ParserContext *ctx, ASTNode *node, Token t);
ASTNode *parse_include(ParserContext *ctx, Lexer *l);
ASTNode *parse_import(ParserContext *ctx, Lexer *l);
ASTNode *parse_comptime(ParserContext *ctx, Lexer *l);
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index f7590e3..cc647c7 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -9,6 +9,65 @@
Type *get_field_type(ParserContext *ctx, Type *struct_type, const char *field_name);
+int is_type_copy(Type *t)
+{
+ if (!t)
+ {
+ return 1; // Default to Copy for unknown types to avoid annoyance
+ }
+
+ switch (t->kind)
+ {
+ case TYPE_INT:
+ case TYPE_I8:
+ case TYPE_I16:
+ case TYPE_I32:
+ case TYPE_I64:
+ case TYPE_U8:
+ case TYPE_U16:
+ case TYPE_U32:
+ case TYPE_U64:
+ case TYPE_F32:
+ case TYPE_F64:
+ case TYPE_BOOL:
+ case TYPE_CHAR:
+ case TYPE_VOID:
+ case TYPE_POINTER: // Pointers are Copy
+ case TYPE_FUNCTION:
+ case TYPE_ENUM: // Enums are integers
+ return 1;
+
+ case TYPE_STRUCT:
+ // Structs are MOVE by default
+ return 0;
+
+ case TYPE_ARRAY:
+ // Arrays decay or are fixed size context dependent, but usually not simplistic copy
+ // For Zen-C safety, let's treat them as Copy if they are treated as pointers,
+ // but if it's a value assignment, C doesn't support it anyway unless wrapped in struct.
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+void check_move_usage(ParserContext *ctx, ASTNode *node, Token t)
+{
+ if (!node)
+ {
+ return;
+ }
+ if (node->type == NODE_EXPR_VAR)
+ {
+ Symbol *sym = find_symbol_entry(ctx, node->var_ref.name);
+ if (sym && sym->is_moved)
+ {
+ zpanic_at(t, "Use of moved value '%s'", node->var_ref.name);
+ }
+ }
+}
+
static int type_is_unsigned(Type *t)
{
if (!t)
@@ -636,9 +695,6 @@ void analyze_lambda_captures(ParserContext *ctx, ASTNode *lambda)
for (int i = 0; i < num_refs; i++)
{
free(all_refs[i]);
- }
- if (all_refs)
- {
free(all_refs);
}
}
@@ -1758,6 +1814,31 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
ASTNode *arg = parse_expression(ctx, l);
+
+ // Move Semantics Logic (Added for known funcs)
+ check_move_usage(ctx, arg, arg ? arg->token : t1);
+ if (arg && arg->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, arg->var_ref.name);
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+
+ if (!is_type_copy(t))
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
if (!head)
{
head = arg;
@@ -1864,6 +1945,31 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
ASTNode *arg = parse_expression(ctx, l);
+
+ // Move Semantics Logic (Added)
+ check_move_usage(ctx, arg, arg ? arg->token : t1);
+ if (arg && arg->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, arg->var_ref.name);
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+
+ if (!is_type_copy(t))
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
if (!head)
{
head = arg;
@@ -2125,6 +2231,31 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
ASTNode *arg = parse_expression(ctx, l);
+
+ // Move Semantics Logic
+ check_move_usage(ctx, arg, arg ? arg->token : t1);
+ if (arg && arg->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, arg->var_ref.name);
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+
+ if (!is_type_copy(t))
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
if (!head)
{
head = arg;
@@ -3201,6 +3332,31 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
ASTNode *arg = parse_expression(ctx, l);
+
+ // Move Semantics Logic
+ check_move_usage(ctx, arg, arg ? arg->token : t1);
+ if (arg && arg->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, arg->var_ref.name);
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+
+ if (!is_type_copy(t))
+ {
+ Symbol *s = find_symbol_entry(ctx, arg->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
if (!head)
{
head = arg;
@@ -3577,6 +3733,52 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
bin->binary.left = lhs;
bin->binary.right = rhs;
+ // Move Semantics Logic
+ if (op.type == TOK_OP && is_token(op, "=")) // Assignment "="
+ {
+ // 1. RHS is being read: Check validity
+ check_move_usage(ctx, rhs, op);
+
+ // 2. Mark RHS as moved (Transfer ownership) if it's a Move type
+ if (rhs->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, rhs->var_ref.name);
+ // If type info not on var, try looking up symbol
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, rhs->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+
+ if (!is_type_copy(t))
+ {
+ Symbol *s = find_symbol_entry(ctx, rhs->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
+ // 3. LHS is being written: Resurrect (it is now valid)
+ if (lhs->type == NODE_EXPR_VAR)
+ {
+ Symbol *s = find_symbol_entry(ctx, lhs->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 0;
+ }
+ }
+ }
+ else // All other binary ops (including +=, -=, etc. which read LHS first)
+ {
+ check_move_usage(ctx, lhs, op);
+ check_move_usage(ctx, rhs, op);
+ }
+
if (op.type == TOK_LANGLE)
{
bin->binary.op = xstrdup("<");
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index db47d16..8fa0a1e 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -1235,6 +1235,29 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
n->var_decl.init_expr = init;
+ // Move Semantics Logic for Initialization
+ check_move_usage(ctx, init, init ? init->token : name_tok);
+ if (init && init->type == NODE_EXPR_VAR)
+ {
+ Type *t = find_symbol_type_info(ctx, init->var_ref.name);
+ if (!t)
+ {
+ Symbol *s = find_symbol_entry(ctx, init->var_ref.name);
+ if (s)
+ {
+ t = s->type_info;
+ }
+ }
+ if (!is_type_copy(t))
+ {
+ Symbol *s = find_symbol_entry(ctx, init->var_ref.name);
+ if (s)
+ {
+ s->is_moved = 1;
+ }
+ }
+ }
+
// Global detection: Either no scope (yet) OR root scope (no parent)
if (!ctx->current_scope || !ctx->current_scope->parent)
{
@@ -1483,6 +1506,11 @@ ASTNode *parse_return(ParserContext *ctx, Lexer *l)
else
{
n->ret.value = parse_expression(ctx, l);
+ check_move_usage(ctx, n->ret.value, n->ret.value ? n->ret.value->token : lexer_peek(l));
+
+ // Note: Returning a non-Copy variable effectively moves it out.
+ // We could mark it as moved, but scope ends anyway.
+ // The critical part is checking we aren't returning an ALREADY moved value.
}
}
@@ -1668,8 +1696,8 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
char *iter_method = "iterator";
// Check for reference iteration: for x in &vec
- if (obj_expr->type == NODE_EXPR_UNARY &&
- obj_expr->unary.op && strcmp(obj_expr->unary.op, "&") == 0)
+ if (obj_expr->type == NODE_EXPR_UNARY && obj_expr->unary.op &&
+ strcmp(obj_expr->unary.op, "&") == 0)
{
obj_expr = obj_expr->unary.operand;
iter_method = "iter_ref";
@@ -3403,14 +3431,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
// If target struct is generic, register this impl as a template
ASTNode *def = find_struct_def(ctx, name2);
- if (def && ((def->type == NODE_STRUCT && def->strct.is_template) ||
+ if (def && ((def->type == NODE_STRUCT && def->strct.is_template) ||
(def->type == NODE_ENUM && def->enm.is_template)))
{
- const char *gp = "T";
- if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0)
- gp = def->strct.generic_params[0];
- // TODO: Enum generic params support if needed
- register_impl_template(ctx, name2, gp, n);
+ const char *gp = "T";
+ if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0)
+ {
+ gp = def->strct.generic_params[0];
+ }
+ // TODO: Enum generic params support if needed
+ register_impl_template(ctx, name2, gp, n);
}
return n;
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index f96ed24..4973111 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1520,7 +1520,8 @@ ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char
break;
case NODE_IMPL_TRAIT:
new_node->impl_trait.trait_name = xstrdup(n->impl_trait.trait_name);
- new_node->impl_trait.target_type = replace_type_str(n->impl_trait.target_type, p, c, os, ns);
+ new_node->impl_trait.target_type =
+ replace_type_str(n->impl_trait.target_type, p, c, os, ns);
new_node->impl_trait.methods = copy_ast_replacing(n->impl_trait.methods, p, c, os, ns);
break;
default:
@@ -1884,13 +1885,15 @@ void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it,
it->struct_name, mangled_struct_name);
it->impl_node->next = backup_next; // Restore
-
ASTNode *meth = NULL;
- if (new_impl->type == NODE_IMPL) {
+ if (new_impl->type == NODE_IMPL)
+ {
new_impl->impl.struct_name = xstrdup(mangled_struct_name);
meth = new_impl->impl.methods;
- } else if (new_impl->type == NODE_IMPL_TRAIT) {
+ }
+ else if (new_impl->type == NODE_IMPL_TRAIT)
+ {
new_impl->impl_trait.target_type = xstrdup(mangled_struct_name);
meth = new_impl->impl_trait.methods;
}
@@ -2009,7 +2012,7 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg,
ASTNode *i = ast_create(NODE_STRUCT);
i->strct.name = xstrdup(m);
i->strct.is_template = 0;
-
+
// Copy type attributes (e.g. has_drop)
i->type_info = type_new(TYPE_STRUCT);
i->type_info->name = xstrdup(m);
@@ -2033,7 +2036,7 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg,
ASTNode *i = ast_create(NODE_ENUM);
i->enm.name = xstrdup(m);
i->enm.is_template = 0;
-
+
// Copy type attributes (e.g. has_drop)
i->type_info = type_new(TYPE_ENUM);
i->type_info->name = xstrdup(m);