@@ -51,6 +51,8 @@ static void v_fastc_println_bool(bool value) { puts(value ? "true" : "false"); }
5151static void v_fastc_println_char(char value) { fputc(value, stdout); fputc(10, stdout); }
5252static void v_fastc_println_signed(long long value) { printf("%lld\n", value); }
5353static void v_fastc_println_unsigned(unsigned long long value) { printf("%llu\n", value); }
54+ static bool builtin__string_eq(const char *left, const char *right) { return strcmp(left ? left : "", right ? right : "") == 0; }
55+ static bool builtin__string_lt(const char *left, const char *right) { return strcmp(left ? left : "", right ? right : "") < 0; }
5456
5557/* Float formatting belongs to the V strconv routines. Leaving float and double
5658 * unmatched makes TinyCC reject unsupported printing instead of silently
@@ -323,6 +325,11 @@ struct FastcComptimeBlock {
323325 tok token.Token
324326}
325327
328+ struct FastcLoopBlockResult {
329+ terminates bool
330+ has_reachable_break bool
331+ }
332+
326333struct Parser {
327334 prefs & pref.Preferences
328335 path string
366373 deferred_lines []string
367374 deferred_block_starts []int
368375 loop_defer_block_starts []int
376+ loop_has_breaks []bool
377+ statement_reachable bool
369378 last_expression_type string
370379 last_expression []FastcExpressionToken
371380 last_multi_return_types []string
@@ -496,6 +505,8 @@ fn generate_source_files(sources []FastcSourceFile, prefs &pref.Preferences) !st
496505 deferred_lines: []string {}
497506 deferred_block_starts: []int {}
498507 loop_defer_block_starts: []int {}
508+ loop_has_breaks: []bool {}
509+ statement_reachable: true
499510 }
500511 gen.s.init (file, source_file.source)
501512 generated := gen.run ()!
@@ -4151,6 +4162,8 @@ fn (mut g Parser) parse_function(enabled bool) ! {
41514162 previous_deferred_lines := g.deferred_lines.clone ()
41524163 previous_deferred_block_starts := g.deferred_block_starts.clone ()
41534164 previous_loop_defer_block_starts := g.loop_defer_block_starts.clone ()
4165+ previous_loop_has_breaks := g.loop_has_breaks.clone ()
4166+ previous_statement_reachable := g.statement_reachable
41544167 g.in_main = is_main
41554168 g.return_type = return_type
41564169 g.return_types = return_types.clone ()
@@ -4160,6 +4173,8 @@ fn (mut g Parser) parse_function(enabled bool) ! {
41604173 g.deferred_lines.clear ()
41614174 g.deferred_block_starts.clear ()
41624175 g.loop_defer_block_starts.clear ()
4176+ g.loop_has_breaks.clear ()
4177+ g.statement_reachable = true
41634178 terminates := g.parse_block_body ()!
41644179 g.in_main = previous_in_main
41654180 g.return_type = previous_return_type
@@ -4170,6 +4185,8 @@ fn (mut g Parser) parse_function(enabled bool) ! {
41704185 g.deferred_lines = previous_deferred_lines.clone ()
41714186 g.deferred_block_starts = previous_deferred_block_starts.clone ()
41724187 g.loop_defer_block_starts = previous_loop_defer_block_starts.clone ()
4188+ g.loop_has_breaks = previous_loop_has_breaks.clone ()
4189+ g.statement_reachable = previous_statement_reachable
41734190 if return_type != 'void' && ! terminates {
41744191 if ! g.selfhost {
41754192 return g.unsupported ('non-void function `${name }` that can fall through' )
@@ -4469,6 +4486,7 @@ fn fastc_all_true(values []bool) bool {
44694486
44704487fn (mut g Parser) parse_block_body () ! bool {
44714488 outer_locals := g.locals.clone ()
4489+ outer_statement_reachable := g.statement_reachable
44724490 deferred_line_start := g.deferred_lines.len
44734491 deferred_block_start := g.deferred_block_starts.len
44744492 mut terminates := false
@@ -4477,6 +4495,7 @@ fn (mut g Parser) parse_block_body() !bool {
44774495 if g.tok == .eof {
44784496 return g.unsupported ('unfinished block' )
44794497 }
4498+ g.statement_reachable = outer_statement_reachable && ! terminates
44804499 statement_terminates := g.parse_statement ()!
44814500 if statement_terminates {
44824501 terminates = true
@@ -4498,6 +4517,7 @@ fn (mut g Parser) parse_block_body() !bool {
44984517 g.deferred_lines.trim (deferred_line_start)
44994518 g.deferred_block_starts.trim (deferred_block_start)
45004519 g.locals = outer_locals.clone ()
4520+ g.statement_reachable = outer_statement_reachable
45014521 return terminates
45024522}
45034523
@@ -4527,9 +4547,12 @@ fn (mut g Parser) parse_statement() !bool {
45274547 if g.loop_defer_block_starts.len == 0 {
45284548 return g.unsupported ('`break` outside a loop' )
45294549 }
4550+ if g.statement_reachable && g.loop_has_breaks.len > 0 {
4551+ g.loop_has_breaks[g.loop_has_breaks.len - 1 ] = true
4552+ }
45304553 g.write_deferred_blocks_from (g.loop_defer_block_starts.last ())
45314554 g.write_line ('break;' )
4532- false
4555+ true
45334556 }
45344557 .key_continue {
45354558 g.next ()
@@ -4539,7 +4562,7 @@ fn (mut g Parser) parse_statement() !bool {
45394562 }
45404563 g.write_deferred_blocks_from (g.loop_defer_block_starts.last ())
45414564 g.write_line ('continue;' )
4542- false
4565+ true
45434566 }
45444567 .key_goto {
45454568 g.next ()
@@ -4641,11 +4664,17 @@ fn (mut g Parser) write_all_deferred_scopes() {
46414664 }
46424665}
46434666
4644- fn (mut g Parser) parse_loop_block_body () ! bool {
4667+ fn (mut g Parser) parse_loop_block_body () ! FastcLoopBlockResult {
46454668 g.loop_defer_block_starts << g.deferred_block_starts.len
4669+ g.loop_has_breaks << false
46464670 terminates := g.parse_block_body ()!
4671+ has_reachable_break := g.loop_has_breaks.last ()
4672+ g.loop_has_breaks.delete_last ()
46474673 g.loop_defer_block_starts.delete_last ()
4648- return terminates
4674+ return FastcLoopBlockResult{
4675+ terminates: terminates
4676+ has_reachable_break: has_reachable_break
4677+ }
46494678}
46504679
46514680fn (mut g Parser) parse_match_statement () ! bool {
@@ -4982,10 +5011,10 @@ fn (mut g Parser) parse_for() !bool {
49825011 g.next ()
49835012 g.write_line ('for (;;) {' )
49845013 g.indent++
4985- _ = g.parse_loop_block_body ()!
5014+ loop_result : = g.parse_loop_block_body ()!
49865015 g.indent--
49875016 g.write_line ('}' )
4988- return false
5017+ return ! loop_result.has_reachable_break
49895018 }
49905019 mut item_is_mut := false
49915020 if g.tok == .key_mut {
@@ -7672,6 +7701,11 @@ fn (g &Parser) render_special_expression(tokens []FastcExpressionToken, rendered
76727701 }
76737702 }
76747703 }
7704+ if ! g.selfhost {
7705+ if string_comparison := g.render_string_comparison_expression (tokens) {
7706+ return string_comparison
7707+ }
7708+ }
76757709 if g.selfhost {
76767710 if interface_cast := g.render_interface_cast_expression (tokens, rendered_expression) {
76777711 return interface_cast
@@ -10043,7 +10077,7 @@ fn (g &Parser) render_raw_expression_tokens(tokens []FastcExpressionToken) ?stri
1004310077 piece = item.source
1004410078 } else {
1004510079 literal := fastc_c_string (item.lit) or { return none }
10046- piece = '_S(${literal })'
10080+ piece = if g.selfhost { '_S(${literal })' } else { literal }
1004710081 }
1004810082 } else if item.tok == .char {
1004910083 piece = if item.lit.starts_with ('c:' ) {
0 commit comments