@@ -5409,29 +5409,150 @@ static Value builtin_signature(Interpreter* interp, Value* args, int argc, Expr*
54095409
54105410static Value builtin_del (Interpreter * interp , Value * args , int argc , Expr * * arg_nodes , Env * env , int line , int col ) {
54115411 (void )args ;
5412-
5413- if (argc != 1 || arg_nodes [0 ]-> type != EXPR_IDENT ) {
5412+ if (argc != 1 ) {
54145413 RUNTIME_ERROR (interp , "DEL expects an identifier" , line , col );
54155414 }
5416-
5417- const char * name = arg_nodes [0 ]-> as .ident ;
5418- EnvEntry * entry = env_get_entry (env , name );
5419- if (!entry || !entry -> initialized ) {
5420- char buf [128 ];
5421- snprintf (buf , sizeof (buf ), "Cannot delete undefined identifier '%s'" , name );
5422- RUNTIME_ERROR (interp , buf , line , col );
5423- }
5424- if (entry -> frozen || entry -> permafrozen ) {
5425- char buf [128 ];
5426- snprintf (buf , sizeof (buf ), "Cannot delete frozen identifier '%s'" , name );
5427- RUNTIME_ERROR (interp , buf , line , col );
5415+
5416+ Expr * target = arg_nodes [0 ];
5417+
5418+ /* Case 1: plain identifier – delete the binding */
5419+ if (target -> type == EXPR_IDENT ) {
5420+ const char * name = target -> as .ident ;
5421+ EnvEntry * entry = env_get_entry (env , name );
5422+ if (!entry || !entry -> initialized ) {
5423+ char buf [128 ];
5424+ snprintf (buf , sizeof (buf ), "Cannot delete undefined identifier '%s'" , name );
5425+ RUNTIME_ERROR (interp , buf , line , col );
5426+ }
5427+ if (entry -> frozen || entry -> permafrozen ) {
5428+ char buf [128 ];
5429+ snprintf (buf , sizeof (buf ), "Cannot delete frozen identifier '%s'" , name );
5430+ RUNTIME_ERROR (interp , buf , line , col );
5431+ }
5432+ if (!env_delete (env , name )) {
5433+ char buf [128 ];
5434+ snprintf (buf , sizeof (buf ), "Cannot delete identifier '%s'" , name );
5435+ RUNTIME_ERROR (interp , buf , line , col );
5436+ }
5437+ return value_int (0 );
54285438 }
5429- if (!env_delete (env , name )) {
5430- char buf [128 ];
5431- snprintf (buf , sizeof (buf ), "Cannot delete identifier '%s'" , name );
5432- RUNTIME_ERROR (interp , buf , line , col );
5439+
5440+ /* Case 2: indexed expression – support deleting map entries like DEL(m<k>) or DEL(m<k1,k2>) */
5441+ if (target -> type == EXPR_INDEX ) {
5442+ /* collect chain of index nodes (possibly nested) */
5443+ size_t chain_len = 0 ;
5444+ Expr * walker = target ;
5445+ while (walker && walker -> type == EXPR_INDEX ) {
5446+ chain_len ++ ;
5447+ walker = walker -> as .index .target ;
5448+ }
5449+ if (!walker || walker -> type != EXPR_IDENT ) {
5450+ RUNTIME_ERROR (interp , "DEL expects an identifier or indexed identifier" , line , col );
5451+ }
5452+
5453+ const char * base_name = walker -> as .ident ;
5454+ Value base_val = value_null ();
5455+ DeclType base_type = TYPE_UNKNOWN ;
5456+ bool base_initialized = false;
5457+ if (!env_get (env , base_name , & base_val , & base_type , & base_initialized ) || !base_initialized ) {
5458+ char buf [128 ];
5459+ snprintf (buf , sizeof (buf ), "Cannot delete mapping from undefined identifier '%s'" , base_name );
5460+ RUNTIME_ERROR (interp , buf , line , col );
5461+ }
5462+
5463+ Expr * * nodes = malloc (sizeof (Expr * ) * (chain_len ? chain_len : 1 ));
5464+ if (!nodes ) {
5465+ value_free (base_val );
5466+ RUNTIME_ERROR (interp , "Out of memory" , line , col );
5467+ }
5468+ walker = target ;
5469+ for (size_t i = 0 ; i < chain_len ; i ++ ) {
5470+ nodes [i ] = walker ;
5471+ walker = walker -> as .index .target ;
5472+ }
5473+
5474+ /* operate on the in-memory copy and write back at end */
5475+ Value * cur = & base_val ;
5476+
5477+ for (int ni = (int )chain_len - 1 ; ni >= 0 ; ni -- ) {
5478+ Expr * node = nodes [ni ];
5479+ ExprList * indices = & node -> as .index .indices ;
5480+ if (indices -> count == 0 ) {
5481+ free (nodes );
5482+ value_free (base_val );
5483+ RUNTIME_ERROR (interp , "Empty index list" , line , col );
5484+ }
5485+
5486+ if (cur -> type != VAL_MAP ) {
5487+ free (nodes );
5488+ value_free (base_val );
5489+ RUNTIME_ERROR (interp , "Attempted map deletion on non-map value" , node -> line , node -> column );
5490+ }
5491+
5492+ for (size_t i = 0 ; i < indices -> count ; i ++ ) {
5493+ Expr * it = indices -> items [i ];
5494+ Value key = eval_expr (interp , it , env );
5495+ if (interp -> error ) {
5496+ /* propagate evaluation error */
5497+ char * em = interp -> error ;
5498+ int el = interp -> error_line ;
5499+ int ec = interp -> error_col ;
5500+ clear_error (interp );
5501+ free (nodes );
5502+ value_free (base_val );
5503+ RUNTIME_ERROR (interp , em , el , ec );
5504+ }
5505+ if (!(key .type == VAL_INT || key .type == VAL_STR || key .type == VAL_FLT )) {
5506+ value_free (key );
5507+ free (nodes );
5508+ value_free (base_val );
5509+ RUNTIME_ERROR (interp , "Map index must be INT, FLT or STR" , it -> line , it -> column );
5510+ }
5511+
5512+ bool last_key_in_node = (i + 1 == indices -> count );
5513+ bool last_node_in_chain = (ni == 0 );
5514+
5515+ if (last_node_in_chain && last_key_in_node ) {
5516+ /* final key: perform deletion on current map */
5517+ value_map_delete (cur , key );
5518+ value_free (key );
5519+ /* write back modified base into environment */
5520+ if (!env_assign (env , base_name , base_val , TYPE_UNKNOWN , false)) {
5521+ free (nodes );
5522+ value_free (base_val );
5523+ RUNTIME_ERROR (interp , "Cannot write back to identifier (frozen?)" , line , col );
5524+ }
5525+ free (nodes );
5526+ value_free (base_val );
5527+ return value_int (0 );
5528+ }
5529+
5530+ /* descend into child slot without creating missing entries */
5531+ Value * slot = value_map_get_ptr (cur , key , false);
5532+ value_free (key );
5533+ if (!slot ) {
5534+ /* intermediate missing -> nothing to delete (no-op) */
5535+ free (nodes );
5536+ value_free (base_val );
5537+ return value_int (0 );
5538+ }
5539+ if (slot -> type != VAL_MAP ) {
5540+ free (nodes );
5541+ value_free (base_val );
5542+ RUNTIME_ERROR (interp , "Attempted nested map indexing on non-map value" , it -> line , it -> column );
5543+ }
5544+ /* descend */
5545+ cur = slot ;
5546+ }
5547+ }
5548+
5549+ /* unreachable, but keep cleanup */
5550+ free (nodes );
5551+ value_free (base_val );
5552+ return value_int (0 );
54335553 }
5434- return value_int (0 );
5554+
5555+ RUNTIME_ERROR (interp , "DEL expects an identifier" , line , col );
54355556}
54365557
54375558static Value builtin_freeze (Interpreter * interp , Value * args , int argc , Expr * * arg_nodes , Env * env , int line , int col ) {
0 commit comments