@@ -406,6 +406,69 @@ static int builtin_param_index(BuiltinFunction* builtin, const char* kw) {
406406 return -1 ;
407407}
408408
409+ static int should_defer_async_argument_for_call (const char * func_name , int arg_index , Expr * arg_expr ) {
410+ if (!func_name || !arg_expr ) return 0 ;
411+ if (arg_index != 0 ) return 0 ;
412+ if (arg_expr -> type != EXPR_ASYNC ) return 0 ;
413+ return strcmp (func_name , "STOP" ) == 0 || strcmp (func_name , "PAUSE" ) == 0 ;
414+ }
415+
416+ static Value make_deferred_async_handle (Expr * async_expr , Env * env ) {
417+ Value thr_val = value_thr_new ();
418+ if (thr_val .type == VAL_THR && thr_val .as .thr ) {
419+ thr_val .as .thr -> body = async_expr -> as .async .block ;
420+ thr_val .as .thr -> env = env ;
421+ }
422+ return thr_val ;
423+ }
424+
425+ static int start_deferred_async_handle (Interpreter * interp , Value thr_val , int line , int col ) {
426+ if (thr_val .type != VAL_THR || !thr_val .as .thr ) return 0 ;
427+ if (value_thr_get_finished (thr_val ) || value_thr_get_started (thr_val )) return 0 ;
428+
429+ if (!thr_val .as .thr -> body || !thr_val .as .thr -> env ) {
430+ if (interp && !interp -> error ) {
431+ interp -> error = strdup ("Cannot start deferred ASYNC: missing body or environment" );
432+ interp -> error_line = line ;
433+ interp -> error_col = col ;
434+ }
435+ return -1 ;
436+ }
437+
438+ ThrStart * start = safe_malloc (sizeof (ThrStart ));
439+ Interpreter * thr_interp = safe_malloc (sizeof (Interpreter ));
440+ * thr_interp = (Interpreter ){0 };
441+ thr_interp -> global_env = interp -> global_env ;
442+ thr_interp -> loop_depth = 0 ;
443+ thr_interp -> error = NULL ;
444+ thr_interp -> error_line = 0 ;
445+ thr_interp -> error_col = 0 ;
446+ thr_interp -> in_try_block = false;
447+ thr_interp -> modules = interp -> modules ;
448+ thr_interp -> shushed = interp -> shushed ;
449+
450+ start -> interp = thr_interp ;
451+ start -> env = thr_val .as .thr -> env ;
452+ start -> body = thr_val .as .thr -> body ;
453+ start -> thr_val = value_copy (thr_val );
454+
455+ if (thrd_create (& thr_val .as .thr -> thread , thr_worker , start ) != thrd_success ) {
456+ value_thr_set_finished (thr_val , 1 );
457+ value_free (start -> thr_val );
458+ free (thr_interp );
459+ free (start );
460+ if (interp && !interp -> error ) {
461+ interp -> error = strdup ("Failed to start deferred ASYNC" );
462+ interp -> error_line = line ;
463+ interp -> error_col = col ;
464+ }
465+ return -1 ;
466+ }
467+
468+ value_thr_set_started (thr_val , 1 );
469+ return 0 ;
470+ }
471+
409472static void label_map_add (LabelMap * map , Value key , int index ) {
410473 if (map -> count + 1 > map -> capacity ) {
411474 size_t new_cap = map -> capacity == 0 ? 8 : map -> capacity * 2 ;
@@ -828,6 +891,7 @@ Value eval_expr(Interpreter* interp, Expr* expr, Env* env) {
828891 int kwc = (int )expr -> as .call .kw_count ;
829892 Value * args = NULL ;
830893 Expr * * arg_nodes = NULL ;
894+ bool deferred_async_arg0 = false;
831895
832896 // For builtins, keywords are supported only if the builtin declares param names.
833897 if (kwc > 0 && (!builtin -> param_names || builtin -> param_count <= 0 )) {
@@ -875,13 +939,19 @@ Value eval_expr(Interpreter* interp, Expr* expr, Env* env) {
875939
876940 // Evaluate positional args
877941 for (int i = 0 ; i < pos_argc ; i ++ ) {
878- arg_nodes [i ] = expr -> as .call .args .items [i ];
942+ Expr * arg_expr = expr -> as .call .args .items [i ];
943+ arg_nodes [i ] = arg_expr ;
944+ if (should_defer_async_argument_for_call (func_name , i , arg_expr )) {
945+ args [i ] = make_deferred_async_handle (arg_expr , env );
946+ deferred_async_arg0 = true;
947+ continue ;
948+ }
879949 if (((strcmp (func_name , "DEL" ) == 0 || strcmp (func_name , "EXIST" ) == 0 || strcmp (func_name , "IMPORT" ) == 0 || strcmp (func_name , "ASSIGN" ) == 0 ) && i == 0 )
880950 || ((strcmp (func_name , "IMPORT" ) == 0 || strcmp (func_name , "IMPORT_PATH" ) == 0 ) && i == 1 )) {
881951 // leave as null placeholder
882952 continue ;
883953 }
884- args [i ] = eval_expr (interp , expr -> as . call . args . items [ i ] , env );
954+ args [i ] = eval_expr (interp , arg_expr , env );
885955 if (interp -> error ) {
886956 for (int j = 0 ; j <= i ; j ++ ) value_free (args [j ]);
887957 free (args );
@@ -915,12 +985,18 @@ Value eval_expr(Interpreter* interp, Expr* expr, Env* env) {
915985 return value_null ();
916986 }
917987 // Evaluate kw expr in caller env (left-to-right preserved)
918- Value v = eval_expr (interp , valnode , env );
919- if (interp -> error ) {
920- for (int j = 0 ; j < max_slot ; j ++ ) value_free (args [j ]);
921- free (args );
922- free (arg_nodes );
923- return value_null ();
988+ Value v ;
989+ if (should_defer_async_argument_for_call (func_name , idx , valnode )) {
990+ v = make_deferred_async_handle (valnode , env );
991+ deferred_async_arg0 = true;
992+ } else {
993+ v = eval_expr (interp , valnode , env );
994+ if (interp -> error ) {
995+ for (int j = 0 ; j < max_slot ; j ++ ) value_free (args [j ]);
996+ free (args );
997+ free (arg_nodes );
998+ return value_null ();
999+ }
9241000 }
9251001 // assign into slot
9261002 if (idx >= max_slot ) {
@@ -978,6 +1054,17 @@ Value eval_expr(Interpreter* interp, Expr* expr, Env* env) {
9781054 // Call builtin
9791055 Value result = builtin -> impl (interp , args , effective_argc , arg_nodes , env , expr -> line , expr -> column );
9801056
1057+ // Start deferred STOP/PAUSE ASYNC argument only after the builtin call completes.
1058+ if (deferred_async_arg0 && args && max_slot > 0 ) {
1059+ if (start_deferred_async_handle (interp , args [0 ], expr -> line , expr -> column ) != 0 ) {
1060+ value_free (result );
1061+ for (int i = 0 ; i < max_slot ; i ++ ) value_free (args [i ]);
1062+ free (args );
1063+ free (arg_nodes );
1064+ return value_null ();
1065+ }
1066+ }
1067+
9811068 // Clean up
9821069 if (args ) {
9831070 for (int i = 0 ; i < max_slot ; i ++ ) value_free (args [i ]);
0 commit comments