@@ -1452,21 +1452,34 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
14521452 return make_error ("Indexed assignment base must be an identifier" , stmt_line , stmt_col );
14531453 }
14541454
1455- EnvEntry * entry = env_get_entry (env , walker -> as .ident );
1456- if (!entry ) {
1455+ const char * base_name = walker -> as .ident ;
1456+ Value base_val = value_null ();
1457+ DeclType base_type = TYPE_UNKNOWN ;
1458+ bool base_initialized = false;
1459+
1460+ if (!env_get (env , base_name , & base_val , & base_type , & base_initialized )) {
14571461 char buf [256 ];
1458- snprintf (buf , sizeof (buf ), "Cannot assign to undeclared identifier '%s'" , walker -> as . ident );
1462+ snprintf (buf , sizeof (buf ), "Cannot assign to undeclared identifier '%s'" , base_name );
14591463 return make_error (buf , stmt_line , stmt_col );
14601464 }
14611465
1462- // If uninitialized, default to map (matches previous indexed-assignment behavior).
1463- if (!entry -> initialized ) {
1464- entry -> value = value_map_new ();
1465- entry -> initialized = true;
1466+ // If uninitialized (or NULL), default to MAP (matches previous behaviour),
1467+ // and persist that into the environment via env_assign.
1468+ if (!base_initialized || base_val .type == VAL_NULL ) {
1469+ Value nm = value_map_new ();
1470+ if (!env_assign (env , base_name , nm , TYPE_UNKNOWN , false)) {
1471+ value_free (nm );
1472+ value_free (base_val );
1473+ return make_error ("Cannot assign to identifier (frozen?)" , stmt_line , stmt_col );
1474+ }
1475+ value_free (base_val );
1476+ base_val = nm ;
1477+ base_initialized = true;
14661478 }
14671479
14681480 Expr * * nodes = malloc (sizeof (Expr * ) * (chain_len ? chain_len : 1 ));
14691481 if (!nodes ) {
1482+ value_free (base_val );
14701483 return make_error ("Out of memory" , stmt_line , stmt_col );
14711484 }
14721485
@@ -1476,15 +1489,16 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
14761489 walker = walker -> as .index .target ;
14771490 }
14781491
1479- Value * cur = & entry -> value ;
1492+ ExecResult out ;
1493+ Value * cur = & base_val ;
14801494
14811495 // Process from innermost -> outermost
14821496 for (int ni = (int )chain_len - 1 ; ni >= 0 ; ni -- ) {
14831497 Expr * node = nodes [ni ];
14841498 ExprList * indices = & node -> as .index .indices ;
14851499 if (indices -> count == 0 ) {
1486- free ( nodes );
1487- return make_error ( "Empty index list" , node -> line , node -> column ) ;
1500+ out = make_error ( "Empty index list" , node -> line , node -> column );
1501+ goto cleanup ;
14881502 }
14891503
14901504 // Auto-promote NULL to MAP when assigning through indexes.
@@ -1496,37 +1510,37 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
14961510 Tensor * t = cur -> as .tns ;
14971511 // Lvalue assignment only supports full integer indexing (no ranges/wildcards).
14981512 if (indices -> count != t -> ndim ) {
1499- free ( nodes );
1500- return make_error ( "Cannot assign through tensor slice" , node -> line , node -> column ) ;
1513+ out = make_error ( "Cannot assign through tensor slice" , node -> line , node -> column );
1514+ goto cleanup ;
15011515 }
15021516
15031517 size_t * idxs0 = malloc (sizeof (size_t ) * indices -> count );
15041518 if (!idxs0 ) {
1505- free ( nodes );
1506- return make_error ( "Out of memory" , stmt_line , stmt_col ) ;
1519+ out = make_error ( "Out of memory" , stmt_line , stmt_col );
1520+ goto cleanup ;
15071521 }
15081522
15091523 for (size_t i = 0 ; i < indices -> count ; i ++ ) {
15101524 Expr * it = indices -> items [i ];
15111525 if (it -> type == EXPR_WILDCARD || it -> type == EXPR_RANGE ) {
15121526 free (idxs0 );
1513- free ( nodes );
1514- return make_error ( "Cannot assign using ranges or wildcards" , it -> line , it -> column ) ;
1527+ out = make_error ( "Cannot assign using ranges or wildcards" , it -> line , it -> column );
1528+ goto cleanup ;
15151529 }
15161530
15171531 Value vi = eval_expr (interp , it , env );
15181532 if (interp -> error ) {
15191533 ExecResult err = make_error (interp -> error , interp -> error_line , interp -> error_col );
15201534 clear_error (interp );
15211535 free (idxs0 );
1522- free ( nodes ) ;
1523- return err ;
1536+ out = err ;
1537+ goto cleanup ;
15241538 }
15251539 if (vi .type != VAL_INT ) {
15261540 value_free (vi );
15271541 free (idxs0 );
1528- free ( nodes );
1529- return make_error ( "Index expression must evaluate to INT" , it -> line , it -> column ) ;
1542+ out = make_error ( "Index expression must evaluate to INT" , it -> line , it -> column );
1543+ goto cleanup ;
15301544 }
15311545
15321546 int64_t v = vi .as .i ;
@@ -1535,8 +1549,8 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
15351549 if (v < 1 || v > dim ) {
15361550 value_free (vi );
15371551 free (idxs0 );
1538- free ( nodes );
1539- return make_error ( "Index out of range" , it -> line , it -> column ) ;
1552+ out = make_error ( "Index out of range" , it -> line , it -> column );
1553+ goto cleanup ;
15401554 }
15411555 idxs0 [i ] = (size_t )(v - 1 );
15421556 value_free (vi );
@@ -1545,8 +1559,8 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
15451559 Value * elem = value_tns_get_ptr (* cur , idxs0 , indices -> count );
15461560 free (idxs0 );
15471561 if (!elem ) {
1548- free ( nodes );
1549- return make_error ( "Index out of range" , node -> line , node -> column ) ;
1562+ out = make_error ( "Index out of range" , node -> line , node -> column );
1563+ goto cleanup ;
15501564 }
15511565 cur = elem ;
15521566 continue ;
@@ -1559,13 +1573,13 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
15591573 if (interp -> error ) {
15601574 ExecResult err = make_error (interp -> error , interp -> error_line , interp -> error_col );
15611575 clear_error (interp );
1562- free ( nodes ) ;
1563- return err ;
1576+ out = err ;
1577+ goto cleanup ;
15641578 }
15651579 if (!(key .type == VAL_INT || key .type == VAL_STR || key .type == VAL_FLT )) {
15661580 value_free (key );
1567- free ( nodes );
1568- return make_error ( "Map index must be INT, FLT or STR" , it -> line , it -> column ) ;
1581+ out = make_error ( "Map index must be INT, FLT or STR" , it -> line , it -> column );
1582+ goto cleanup ;
15691583 }
15701584
15711585 bool last_key_in_node = (i + 1 == indices -> count );
@@ -1576,25 +1590,25 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
15761590 Value * slot = value_map_get_ptr (cur , key , true);
15771591 value_free (key );
15781592 if (!slot ) {
1579- free ( nodes );
1580- return make_error ( "Internal error assigning to map" , stmt_line , stmt_col ) ;
1593+ out = make_error ( "Internal error assigning to map" , stmt_line , stmt_col );
1594+ goto cleanup ;
15811595 }
15821596 if (slot -> type != VAL_NULL && value_type_to_decl (slot -> type ) != value_type_to_decl (rhs .type )) {
1583- free ( nodes );
1584- return make_error ( "Map entry type mismatch" , stmt_line , stmt_col ) ;
1597+ out = make_error ( "Map entry type mismatch" , stmt_line , stmt_col );
1598+ goto cleanup ;
15851599 }
15861600 value_free (* slot );
15871601 * slot = value_copy (rhs );
1588- free ( nodes );
1589- return make_ok ( value_null ()) ;
1602+ out = make_ok ( value_null () );
1603+ goto cleanup ;
15901604 }
15911605
15921606 // Descend into slot.
15931607 Value * slot = value_map_get_ptr (cur , key , true);
15941608 value_free (key );
15951609 if (!slot ) {
1596- free ( nodes );
1597- return make_error ( "Internal error indexing map" , stmt_line , stmt_col ) ;
1610+ out = make_error ( "Internal error indexing map" , stmt_line , stmt_col );
1611+ goto cleanup ;
15981612 }
15991613
16001614 if (slot -> type == VAL_NULL ) {
@@ -1608,21 +1622,26 @@ ExecResult assign_index_chain(Interpreter* interp, Env* env, Expr* idx_expr, Val
16081622 }
16091623
16101624 // Unsupported type for indexed assignment
1611- free ( nodes );
1612- return make_error ( "Indexing assignment is supported only on tensors and maps" , node -> line , node -> column ) ;
1625+ out = make_error ( "Indexing assignment is supported only on tensors and maps" , node -> line , node -> column );
1626+ goto cleanup ;
16131627 }
16141628
16151629 // If we get here, the chain ended after resolving to a tensor element (e.g. a<1> = rhs)
16161630 if (cur -> type != VAL_NULL && value_type_to_decl (cur -> type ) != value_type_to_decl (rhs .type )) {
1617- free ( nodes );
1618- return make_error ( "Element type mismatch" , stmt_line , stmt_col ) ;
1631+ out = make_error ( "Element type mismatch" , stmt_line , stmt_col );
1632+ goto cleanup ;
16191633 }
16201634 mtx_lock (& g_tns_lock );
16211635 value_free (* cur );
16221636 * cur = value_copy (rhs );
16231637 mtx_unlock (& g_tns_lock );
1638+
1639+ out = make_ok (value_null ());
1640+
1641+ cleanup :
16241642 free (nodes );
1625- return make_ok (value_null ());
1643+ value_free (base_val );
1644+ return out ;
16261645}
16271646
16281647static ExecResult exec_stmt (Interpreter * interp , Stmt * stmt , Env * env , LabelMap * labels ) {
0 commit comments