@@ -8581,16 +8581,157 @@ typedef struct {
85818581 int * err_cols ;
85828582} ParallelStart ;
85838583
8584+ // Local copy of interpreter helper to map ValueType -> DeclType
8585+ static DeclType value_type_to_decl (ValueType vt ) {
8586+ switch (vt ) {
8587+ case VAL_BOOL : return TYPE_BOOL ;
8588+ case VAL_INT : return TYPE_INT ;
8589+ case VAL_FLT : return TYPE_FLT ;
8590+ case VAL_STR : return TYPE_STR ;
8591+ case VAL_TNS : return TYPE_TNS ;
8592+ case VAL_MAP : return TYPE_MAP ;
8593+ case VAL_FUNC : return TYPE_FUNC ;
8594+ case VAL_THR : return TYPE_THR ;
8595+ default : return TYPE_UNKNOWN ;
8596+ }
8597+ }
8598+
8599+ // Local coercion helper (mirrors interpreter.c behavior but is available
8600+ // in this translation unit). Returns true on success and sets *out_value.
8601+ static bool coerce_value_to_decl_type (Interpreter * interp ,
8602+ Value input ,
8603+ DeclType target ,
8604+ Env * env ,
8605+ int line ,
8606+ int col ,
8607+ Value * out_value ) {
8608+ if (!out_value ) return false;
8609+ * out_value = value_null ();
8610+
8611+ if (value_type_to_decl (input .type ) == target ) {
8612+ * out_value = value_copy (input );
8613+ return true;
8614+ }
8615+
8616+ const char * builtin_name = NULL ;
8617+ switch (target ) {
8618+ case TYPE_BOOL : builtin_name = "BOOL" ; break ;
8619+ case TYPE_INT : builtin_name = "INT" ; break ;
8620+ case TYPE_FLT : builtin_name = "FLT" ; break ;
8621+ case TYPE_STR : builtin_name = "STR" ; break ;
8622+ case TYPE_TNS : builtin_name = "TNS" ; break ;
8623+ default :
8624+ return false;
8625+ }
8626+
8627+ BuiltinFunction * builtin = builtin_lookup (builtin_name );
8628+ if (!builtin || !builtin -> impl ) return false;
8629+
8630+ Value args [1 ];
8631+ args [0 ] = input ;
8632+ Value converted = builtin -> impl (interp , args , 1 , NULL , env , line , col );
8633+ if (interp -> error ) {
8634+ return false;
8635+ }
8636+ if (value_type_to_decl (converted .type ) != target ) {
8637+ value_free (converted );
8638+ return false;
8639+ }
8640+
8641+ * out_value = converted ;
8642+ return true;
8643+ }
8644+
85848645static int parallel_worker (void * arg ) {
85858646 ParallelStart * ps = (ParallelStart * )arg ;
85868647 // Create a per-worker interpreter state similar to PARFOR
85878648 Interpreter * thr_interp = ps -> interp ;
85888649
8589- // Prepare a call environment from the function's closure
8650+ // Create a call environment from the function's closure and
8651+ // perform normal function parameter binding (no-arg call).
85908652 Env * call_env = env_create (ps -> func -> closure );
85918653
8592- // Execute the function body as if it were a function call so RETURN
8593- // statements inside the function body are allowed.
8654+ // Bind parameters as the interpreter would for a user-call with
8655+ // zero positional/keyword arguments. This ensures missing
8656+ // required parameters and default-evaluation errors become
8657+ // runtime errors (as mandated by the spec).
8658+ for (size_t i = 0 ; i < ps -> func -> params .count ; i ++ ) {
8659+ Param * param = & ps -> func -> params .items [i ];
8660+ Value arg_val = value_null ();
8661+ bool provided = false;
8662+
8663+ if (param -> default_value ) {
8664+ arg_val = eval_expr (thr_interp , param -> default_value , call_env );
8665+ if (thr_interp -> error ) {
8666+ // transfer ownership of interpreter error into shared slot
8667+ ps -> errors [ps -> index ] = thr_interp -> error ;
8668+ if (ps -> err_lines ) ps -> err_lines [ps -> index ] = thr_interp -> error_line ;
8669+ if (ps -> err_cols ) ps -> err_cols [ps -> index ] = thr_interp -> error_col ;
8670+ thr_interp -> error = NULL ;
8671+ // cleanup
8672+ env_free (call_env );
8673+ free (thr_interp );
8674+ free (ps );
8675+ return 0 ;
8676+ }
8677+ provided = true;
8678+ } else {
8679+ char buf [128 ];
8680+ snprintf (buf , sizeof (buf ), "Missing argument for parameter '%s'" , param -> name );
8681+ ps -> errors [ps -> index ] = strdup (buf );
8682+ if (ps -> err_lines ) ps -> err_lines [ps -> index ] = 0 ;
8683+ if (ps -> err_cols ) ps -> err_cols [ps -> index ] = 0 ;
8684+ env_free (call_env );
8685+ free (thr_interp );
8686+ free (ps );
8687+ return 0 ;
8688+ }
8689+
8690+ Value bind_val = arg_val ;
8691+ bool used_coercion = false;
8692+ if (value_type_to_decl (bind_val .type ) != param -> type && param -> coerced ) {
8693+ Value coerced = value_null ();
8694+ if (coerce_value_to_decl_type (thr_interp , arg_val , param -> type , call_env , 0 , 0 , & coerced )) {
8695+ bind_val = coerced ;
8696+ used_coercion = true;
8697+ }
8698+ }
8699+
8700+ if (value_type_to_decl (bind_val .type ) != param -> type ) {
8701+ char buf [128 ];
8702+ snprintf (buf , sizeof (buf ), "Type mismatch for parameter '%s'" , param -> name );
8703+ ps -> errors [ps -> index ] = strdup (buf );
8704+ if (ps -> err_lines ) ps -> err_lines [ps -> index ] = 0 ;
8705+ if (ps -> err_cols ) ps -> err_cols [ps -> index ] = 0 ;
8706+ if (used_coercion ) value_free (bind_val );
8707+ value_free (arg_val );
8708+ env_free (call_env );
8709+ free (thr_interp );
8710+ free (ps );
8711+ return 0 ;
8712+ }
8713+
8714+ env_define (call_env , param -> name , param -> type );
8715+ if (!env_assign (call_env , param -> name , bind_val , param -> type , true)) {
8716+ char buf [256 ];
8717+ snprintf (buf , sizeof (buf ), "Cannot assign to frozen identifier '%s'" , param -> name );
8718+ ps -> errors [ps -> index ] = strdup (buf );
8719+ if (ps -> err_lines ) ps -> err_lines [ps -> index ] = 0 ;
8720+ if (ps -> err_cols ) ps -> err_cols [ps -> index ] = 0 ;
8721+ if (used_coercion ) value_free (bind_val );
8722+ value_free (arg_val );
8723+ env_free (call_env );
8724+ free (thr_interp );
8725+ free (ps );
8726+ return 0 ;
8727+ }
8728+
8729+ // Release temporaries (env_assign copied value)
8730+ value_free (arg_val );
8731+ if (used_coercion ) value_free (bind_val );
8732+ }
8733+
8734+ // Execute the function body as a proper call frame so RETURN is allowed
85948735 ExecResult res = exec_program_in_env_as_function (thr_interp , ps -> func -> body , call_env , ps -> func -> name );
85958736
85968737 if (res .status == EXEC_ERROR && res .error ) {
0 commit comments