@@ -1201,8 +1201,13 @@ static void emit_range(Token *start, Token *end) {
12011201// Like emit_range but skips TK_PREP_DIR tokens (for generated expressions
12021202// where preprocessor directives would be invalid, e.g. inside if-conditions).
12031203static void emit_range_no_prep (Token * start , Token * end ) {
1204- for (Token * t = start ; t && t != end && t -> kind != TK_EOF ; t = tok_next (t ))
1205- if (t -> kind != TK_PREP_DIR ) emit_tok (t );
1204+ for (Token * t = start ; t && t != end && t -> kind != TK_EOF ; t = tok_next (t )) {
1205+ if (t -> kind == TK_PREP_DIR ) continue ;
1206+ if (match_ch (t , '(' ) && tok_next (t ) && match_ch (tok_next (t ), '{' ) && tok_match (t )) {
1207+ walk_balanced (t , true); t = tok_match (t ); continue ;
1208+ }
1209+ emit_tok (t );
1210+ }
12061211}
12071212
12081213// Like emit_range_no_prep but walks balanced () and [] groups through
@@ -1218,7 +1223,7 @@ static void emit_balanced_range(Token *start, Token *end) {
12181223}
12191224
12201225// Forward declarations — implementations below find_bare_orelse.
1221- static Token * emit_bare_orelse_impl (Token * t , Token * end , bool comma_term );
1226+ static Token * emit_bare_orelse_impl (Token * t , Token * end , bool comma_term , bool brace_wrap );
12221227static Token * emit_deferred_orelse (Token * t , Token * end );
12231228static void emit_deferred_range (Token * start , Token * end );
12241229
@@ -1230,9 +1235,10 @@ static void emit_defers_ex(DeferEmitMode mode, int stop_depth) {
12301235 check_defer_shadow_at_exit (mode , stop_depth );
12311236
12321237 int current_defer = defer_count - 1 ;
1238+ int curr_bd = ctx -> block_depth ;
12331239 for (int d = ctx -> scope_depth - 1 ; d >= 0 ; d -- ) {
12341240 if (scope_stack [d ].kind != SCOPE_BLOCK ) continue ;
1235- if (mode == DEFER_TO_DEPTH && d < stop_depth ) break ;
1241+ if (mode == DEFER_TO_DEPTH && curr_bd <= stop_depth ) break ;
12361242
12371243 ScopeNode * scope = & scope_stack [d ];
12381244 for (int i = current_defer ; i >= scope -> defer_start_idx ; i -- ) {
@@ -1241,6 +1247,7 @@ static void emit_defers_ex(DeferEmitMode mode, int stop_depth) {
12411247 out_char (';' );
12421248 }
12431249 current_defer = scope -> defer_start_idx - 1 ;
1250+ curr_bd -- ;
12441251
12451252 if (mode == DEFER_SCOPE ) break ;
12461253 if (mode == DEFER_BREAK && (scope -> is_loop || scope -> is_switch )) break ;
@@ -1249,10 +1256,12 @@ static void emit_defers_ex(DeferEmitMode mode, int stop_depth) {
12491256}
12501257
12511258static bool has_defers_for (DeferEmitMode mode , int stop_depth ) {
1259+ int curr_bd = ctx -> block_depth ;
12521260 for (int d = ctx -> scope_depth - 1 ; d >= 0 ; d -- ) {
12531261 if (scope_stack [d ].kind != SCOPE_BLOCK ) continue ;
1254- if (mode == DEFER_TO_DEPTH && d < stop_depth ) break ;
1262+ if (mode == DEFER_TO_DEPTH && curr_bd <= stop_depth ) break ;
12551263 if (defer_count > scope_stack [d ].defer_start_idx ) return true;
1264+ curr_bd -- ;
12561265 if (mode == DEFER_BREAK && (scope_stack [d ].is_loop || scope_stack [d ].is_switch ))
12571266 return false;
12581267 if (mode == DEFER_CONTINUE && scope_stack [d ].is_loop ) return false;
@@ -1486,11 +1495,13 @@ static void check_defer_shadow_at_exit(DeferEmitMode mode, int stop_depth) {
14861495 // Determine which defer indices will be pasted by this exit.
14871496 // Walk scopes the same way emit_defers_ex does, collecting the range.
14881497 int min_defer_idx = defer_count ; // exclusive upper bound not needed; just track min
1498+ int curr_bd = ctx -> block_depth ;
14891499 for (int d = ctx -> scope_depth - 1 ; d >= 0 ; d -- ) {
14901500 if (scope_stack [d ].kind != SCOPE_BLOCK ) continue ;
1491- if (mode == DEFER_TO_DEPTH && d < stop_depth ) break ;
1501+ if (mode == DEFER_TO_DEPTH && curr_bd <= stop_depth ) break ;
14921502 if (scope_stack [d ].defer_start_idx < min_defer_idx )
14931503 min_defer_idx = scope_stack [d ].defer_start_idx ;
1504+ curr_bd -- ;
14941505 if (mode == DEFER_BREAK &&
14951506 (scope_stack [d ].is_loop || scope_stack [d ].is_switch )) break ;
14961507 if (mode == DEFER_CONTINUE && scope_stack [d ].is_loop ) break ;
@@ -6028,7 +6039,7 @@ static bool orelse_has_chain(Token *start, bool comma_term) {
60286039// Returns the token after the statement, or NULL if no orelse was found.
60296040// `comma_term`: also treat ',' at depth 0 as statement terminator.
60306041// `end`: optional boundary (for deferred ranges).
6031- static Token * emit_bare_orelse_impl (Token * t , Token * end , bool comma_term ) {
6042+ static Token * emit_bare_orelse_impl (Token * t , Token * end , bool comma_term , bool brace_wrap ) {
60326043 Token * orelse_tok = find_bare_orelse (t );
60336044 if (!orelse_tok || (end && tok_loc (orelse_tok ) >= tok_loc (end )))
60346045 return NULL ;
@@ -6038,33 +6049,26 @@ static Token *emit_bare_orelse_impl(Token *t, Token *end, bool comma_term) {
60386049
60396050 #define BARE_IS_END (s ) (match_ch((s), ';') || (comma_term && match_ch((s), ',')))
60406051
6041- // Skip past depth-0 commas before orelse — the comma operator separates
6042- // independent sub-expressions and orelse only applies to the last one.
6043- // Emit prefix tokens as a separate statement (comma → semicolon) because
6044- // the orelse expansion may produce a block `{ ... }` which cannot appear
6045- // after the comma operator.
6052+ // Find last depth-0 comma before orelse (search only — don't emit yet).
6053+ // Need to check is_bare_fallback before emitting, because if it's not
6054+ // bare we return NULL and the caller handles it differently.
6055+ Token * last_comma = NULL ;
60466056 {
6047- Token * last_comma = NULL ;
60486057 int sd = 0 ;
60496058 for (Token * s = t ; s != orelse_tok ; s = tok_next (s )) {
60506059 if (s -> flags & TF_OPEN ) sd ++ ;
60516060 else if (s -> flags & TF_CLOSE ) sd -- ;
6052- else if (sd == 0 && match_ch (s , ',' )) last_comma = s ;
6053- }
6054- if (last_comma ) {
6055- for (Token * s = t ; s != last_comma ; s = tok_next (s ))
6056- emit_tok (s );
6057- out_char (';' ); // replace comma with semicolon
6058- t = tok_next (last_comma );
6061+ else if (sd == 0 && comma_term && match_ch (s , ',' )) last_comma = s ;
60596062 }
60606063 }
6064+ Token * post_comma_t = last_comma ? tok_next (last_comma ) : t ;
60616065
60626066 // Find assignment target (= at depth 0 before orelse)
6063- Token * bare_lhs_start = t ;
6067+ Token * bare_lhs_start = post_comma_t ;
60646068 Token * bare_assign_eq = NULL ;
60656069 {
60666070 int sd = 0 ;
6067- for (Token * s = t ; s != orelse_tok ; s = tok_next (s )) {
6071+ for (Token * s = post_comma_t ; s != orelse_tok ; s = tok_next (s )) {
60686072 if (s -> flags & TF_OPEN ) sd ++ ;
60696073 else if (s -> flags & TF_CLOSE ) sd -- ;
60706074 else if (sd == 0 && is_assignment_operator_token (s )) {
@@ -6097,6 +6101,21 @@ static Token *emit_bare_orelse_impl(Token *t, Token *end, bool comma_term) {
60976101 if (!is_bare_fallback )
60986102 return NULL ; // caller handles non-bare fallback
60996103
6104+ // Now we know this is bare — safe to emit.
6105+ // Wrap in braces for braceless control-flow bodies (if/for/while/else
6106+ // without braces) so the expansion stays as a single compound statement.
6107+ if (brace_wrap ) OUT_LIT (" {" );
6108+
6109+ // Emit comma prefix as a separate statement (comma → semicolon).
6110+ // The orelse expansion may produce a block which cannot appear after
6111+ // the comma operator.
6112+ if (last_comma ) {
6113+ for (Token * s = t ; s != last_comma ; s = tok_next (s ))
6114+ emit_tok (s );
6115+ out_char (';' );
6116+ t = post_comma_t ;
6117+ }
6118+
61006119 // Reject if the statement contains preprocessor conditionals (#ifdef/#else/etc.).
61016120 // emit_range_no_prep / emit_balanced_range skip TK_PREP_DIR tokens,
61026121 // producing concatenated code from ALL branches — silent miscompilation.
@@ -6263,6 +6282,7 @@ static Token *emit_bare_orelse_impl(Token *t, Token *end, bool comma_term) {
62636282 OUT_LIT (" }" );
62646283 }
62656284 if (match_ch (t , ';' ) || (comma_term && match_ch (t , ',' ))) t = tok_next (t );
6285+ if (brace_wrap ) OUT_LIT (" }" );
62666286 #undef BARE_IS_END
62676287 return t ;
62686288}
@@ -6284,7 +6304,7 @@ static Token *emit_orelse_condition_wrap(Token *t, Token *orelse_tok) {
62846304// Wrapper for defer blocks: handles both bare and non-bare orelse.
62856305// Returns the token after the statement, or NULL if no orelse was found.
62866306static Token * emit_deferred_orelse (Token * t , Token * end ) {
6287- Token * result = emit_bare_orelse_impl (t , end , false);
6307+ Token * result = emit_bare_orelse_impl (t , end , false, false );
62886308 if (result ) return result ;
62896309
62906310 // Check for non-bare orelse (block/control-flow action)
@@ -8370,8 +8390,14 @@ static int transpile_tokens(Token *tok, FILE *fp) {
83708390 tok = label_end ;
83718391 }
83728392
8393+ // Braceless control flow: bare orelse can emit multiple
8394+ // statements (comma split + assignment), so needs braces.
8395+ // Non-bare (control-flow/block action) already wraps in
8396+ // { if (!(...)) ... } which is a single compound statement.
8397+ bool brace_wrap = ctrl_state .pending && ctrl_state .parens_just_closed ;
8398+
83738399 // Try bare-fallback path (handled by shared impl)
8374- Token * next = emit_bare_orelse_impl (tok , NULL , true);
8400+ Token * next = emit_bare_orelse_impl (tok , NULL , true, brace_wrap );
83758401 if (next ) {
83768402 tok = next ;
83778403 end_statement_after_semicolon ();
0 commit comments