@@ -2414,6 +2414,14 @@ static ExecResult exec_stmt(Interpreter* interp, Stmt* stmt, Env* env, LabelMap*
24142414 }
24152415
24162416 case STMT_RETURN : {
2417+ // RETURN is valid only inside a function. Detect function
2418+ // execution context by inspecting the trace stack: function
2419+ // call frames are pushed with has_call_location == 1.
2420+ if (interp -> trace_stack_count == 0 ||
2421+ interp -> trace_stack [interp -> trace_stack_count - 1 ].has_call_location == 0 ) {
2422+ return make_error ("RETURN used outside function" , stmt -> line , stmt -> column );
2423+ }
2424+
24172425 // Evaluate return expression and propagate as EXEC_RETURN
24182426 Value v = eval_expr (interp , stmt -> as .return_stmt .value , env );
24192427 if (interp -> error ) {
@@ -3308,3 +3316,37 @@ ExecResult exec_program_in_env(Interpreter* interp, Stmt* program, Env* env) {
33083316
33093317 return res ;
33103318}
3319+
3320+ // Execute a parsed function body (`program`) within an existing Interpreter
3321+ // and Env treating the execution as a function call frame so `RETURN` is
3322+ // permitted. `func_name` is used for traceback entries.
3323+ ExecResult exec_program_in_env_as_function (Interpreter * interp , Stmt * program , Env * env , const char * func_name ) {
3324+ if (!interp || !program || !env ) {
3325+ ExecResult r = make_error ("Internal: invalid args to exec_program_in_env_as_function" , 0 , 0 );
3326+ return r ;
3327+ }
3328+
3329+ // Ensure there's a call-like trace frame so RETURN is valid.
3330+ if (interp -> trace_stack_count == 0 ) {
3331+ (void )trace_push_frame (interp , func_name ? func_name : "<lambda>" , env , 0 , 0 , 1 );
3332+ } else {
3333+ if (trace_push_frame (interp , func_name ? func_name : "<lambda>" , env , 0 , 0 , 1 ) != 0 ) {
3334+ ExecResult r = make_error ("Out of memory" , 0 , 0 );
3335+ return r ;
3336+ }
3337+ }
3338+
3339+ LabelMap labels = {0 };
3340+ ExecResult res = exec_stmt_list (interp , & program -> as .block , env , & labels );
3341+
3342+ if (res .status == EXEC_ERROR ) {
3343+ char * tb = interpreter_format_traceback (interp , res .error , res .error_line , res .error_column );
3344+ free (res .error );
3345+ res .error = tb ;
3346+ }
3347+
3348+ for (size_t i = 0 ; i < labels .count ; i ++ ) value_free (labels .items [i ].key );
3349+ free (labels .items );
3350+
3351+ return res ;
3352+ }
0 commit comments