@@ -169,6 +169,18 @@ fn (mut g Gen) expr_type_to_c(e ast.Expr) string {
169169 ast.EmptyExpr {
170170 return 'void'
171171 }
172+ ast.Type {
173+ // Handle Option and Result types
174+ if e is ast.OptionType {
175+ // For ?T, we use the base type (simplified - no proper optional handling)
176+ return g.expr_type_to_c (e.base_type)
177+ }
178+ if e is ast.ResultType {
179+ // For !T, we use the base type (simplified - no proper result handling)
180+ return g.expr_type_to_c (e.base_type)
181+ }
182+ return 'int'
183+ }
172184 else {
173185 return 'int'
174186 }
@@ -665,6 +677,12 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
665677 return
666678 }
667679
680+ // Check if condition is an if-guard expression
681+ if node.cond is ast.IfGuardExpr {
682+ g.gen_if_guard (node, node.cond)
683+ return
684+ }
685+
668686 g.write_indent ()
669687 g.sb.write_string ('if (' )
670688 g.gen_expr (node.cond)
@@ -944,6 +962,36 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
944962 }
945963 g.sb.write_string ('})' )
946964 }
965+ ast.IfGuardExpr {
966+ // If-guard expression: `if x := opt() { ... }`
967+ // For cleanc, we generate the RHS expression and use it as condition
968+ // The variable binding is handled in the if-statement context
969+ if node.stmt.rhs.len > 0 {
970+ g.gen_expr (node.stmt.rhs[0 ])
971+ } else {
972+ g.sb.write_string ('0' )
973+ }
974+ }
975+ ast.Keyword {
976+ // Handle keywords like 'none'
977+ if node.tok == .key_none {
978+ g.sb.write_string ('0' ) // none is represented as 0/NULL
979+ } else if node.tok == .key_true {
980+ g.sb.write_string ('true' )
981+ } else if node.tok == .key_false {
982+ g.sb.write_string ('false' )
983+ } else {
984+ g.sb.write_string ('/* keyword: ${node .tok } */' )
985+ }
986+ }
987+ ast.Type {
988+ // Handle type expressions (e.g., in return statements)
989+ if node is ast.NoneType {
990+ g.sb.write_string ('0' ) // none
991+ } else {
992+ g.sb.write_string ('/* type expr */' )
993+ }
994+ }
947995 else {
948996 g.sb.write_string ('/* expr: ${node .type_name ()} */' )
949997 }
@@ -959,6 +1007,10 @@ fn (mut g Gen) write_indent() {
9591007// Check if an IfExpr can be converted to a C ternary operator
9601008// This is true when the branches contain simple value expressions (single ExprStmt)
9611009fn (g Gen) can_be_ternary (node ast.IfExpr) bool {
1010+ // If-guard expressions cannot be ternary (they need variable declarations)
1011+ if node.cond is ast.IfGuardExpr {
1012+ return false
1013+ }
9621014 // Must have both branches
9631015 if node.else_expr is ast.EmptyExpr {
9641016 return false
@@ -1043,6 +1095,94 @@ fn (mut g Gen) gen_else_value(else_expr ast.Expr) {
10431095 }
10441096}
10451097
1098+ // Generate if-guard statement: `if x := opt() { ... } else { ... }`
1099+ fn (mut g Gen) gen_if_guard (node ast.IfExpr, guard ast.IfGuardExpr) {
1100+ // For if-guard, we:
1101+ // 1. Declare the guard variable(s)
1102+ // 2. Assign the RHS to the variable(s)
1103+ // 3. Use the value as condition (non-zero = success)
1104+
1105+ // Get the variable name(s) from LHS
1106+ mut var_names := []string {}
1107+ for lhs_expr in guard.stmt.lhs {
1108+ if lhs_expr is ast.Ident {
1109+ var_names << lhs_expr.name
1110+ } else if lhs_expr is ast.ModifierExpr {
1111+ // Handle 'mut x'
1112+ if lhs_expr.expr is ast.Ident {
1113+ var_names << lhs_expr.expr.name
1114+ }
1115+ }
1116+ }
1117+
1118+ // Infer type from RHS
1119+ mut rhs_type := 'int'
1120+ if guard.stmt.rhs.len > 0 {
1121+ rhs_type = g.infer_type (guard.stmt.rhs[0 ])
1122+ }
1123+
1124+ // Generate: { type var = rhs; if (var) { ... } else { ... } }
1125+ g.sb.writeln ('{' )
1126+ g.indent++
1127+
1128+ // Declare and assign guard variable(s)
1129+ for i, var_name in var_names {
1130+ g.write_indent ()
1131+ g.var_types[var_name] = rhs_type
1132+ g.sb.write_string ('${rhs_type } ${var_name } = ' )
1133+ if i < guard.stmt.rhs.len {
1134+ g.gen_expr (guard.stmt.rhs[i])
1135+ } else if guard.stmt.rhs.len > 0 {
1136+ g.gen_expr (guard.stmt.rhs[0 ])
1137+ } else {
1138+ g.sb.write_string ('0' )
1139+ }
1140+ g.sb.writeln (';' )
1141+ }
1142+
1143+ // Generate the if statement using the first variable as condition
1144+ g.write_indent ()
1145+ if var_names.len > 0 {
1146+ g.sb.write_string ('if (${var_names [0 ]})' )
1147+ } else {
1148+ g.sb.write_string ('if (0)' )
1149+ }
1150+ g.sb.writeln (' {' )
1151+ g.indent++
1152+ g.gen_stmts (node.stmts)
1153+ g.indent--
1154+ g.write_indent ()
1155+ g.sb.write_string ('}' )
1156+
1157+ // Handle else branch
1158+ if node.else_expr ! is ast.EmptyExpr {
1159+ if node.else_expr is ast.IfExpr {
1160+ if node.else_expr.cond is ast.EmptyExpr {
1161+ // Pure else block
1162+ g.sb.writeln (' else {' )
1163+ g.indent++
1164+ g.gen_stmts (node.else_expr.stmts)
1165+ g.indent--
1166+ g.write_indent ()
1167+ g.sb.writeln ('}' )
1168+ } else {
1169+ // Else-if chain
1170+ g.sb.write_string (' else ' )
1171+ g.gen_expr (node.else_expr)
1172+ }
1173+ } else {
1174+ g.sb.write_string (' else ' )
1175+ g.gen_expr (node.else_expr)
1176+ }
1177+ } else {
1178+ g.sb.writeln ('' )
1179+ }
1180+
1181+ g.indent--
1182+ g.write_indent ()
1183+ g.sb.writeln ('}' )
1184+ }
1185+
10461186// Convert V string interpolation format to C printf format specifier
10471187fn (g Gen) get_printf_format (inter ast.StringInter) string {
10481188 base_fmt := match inter.format {
0 commit comments