Skip to content

Commit 12f6554

Browse files
committed
ssa: IfGuardExpr
1 parent 5715541 commit 12f6554

4 files changed

Lines changed: 407 additions & 0 deletions

File tree

‎cmd/tinyv/test.v‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,32 @@ fn nested_return(x int) int {
212212
}
213213
}
214214

215+
// ===================== IF-GUARD HELPERS =====================
216+
217+
// Returns the value if positive, none otherwise
218+
fn maybe_positive(x int) ?int {
219+
if x > 0 {
220+
return x
221+
}
222+
return none
223+
}
224+
225+
// Returns the doubled value if in range, none otherwise
226+
fn maybe_double(x int) ?int {
227+
if x >= 0 && x <= 50 {
228+
return x * 2
229+
}
230+
return none
231+
}
232+
233+
// Returns sum if both positive, none otherwise
234+
fn maybe_sum(a int, b int) ?int {
235+
if a > 0 && b > 0 {
236+
return a + b
237+
}
238+
return none
239+
}
240+
215241
// ===================== IF-EXPRESSION HELPERS =====================
216242

217243
fn int_abs(a int) int {
@@ -1678,5 +1704,71 @@ fn main() {
16781704
s5 := '${interp_v1}-${interp_v2}-${interp_v3}'
16791705
print_str(s5) // 1-2-3
16801706

1707+
// ==================== 35. IF-GUARD EXPRESSIONS ====================
1708+
print_str('--- 35. If-Guard Expressions ---')
1709+
1710+
// 35.1 Basic if-guard with success (positive value)
1711+
if g1_val := maybe_positive(42) {
1712+
print_int(g1_val) // 42
1713+
} else {
1714+
print_int(0)
1715+
}
1716+
1717+
// 35.2 If-guard with failure (non-positive value)
1718+
if g2_val := maybe_positive(-5) {
1719+
print_int(g2_val)
1720+
} else {
1721+
print_int(999) // 999 (else branch taken)
1722+
}
1723+
1724+
// 35.3 If-guard with computation in then branch
1725+
if g3_val := maybe_double(25) {
1726+
print_int(g3_val + 10) // 50 + 10 = 60
1727+
} else {
1728+
print_int(0)
1729+
}
1730+
1731+
// 35.4 If-guard with function call
1732+
if g4_result := maybe_sum(10, 20) {
1733+
print_int(g4_result) // 30
1734+
} else {
1735+
print_int(0)
1736+
}
1737+
1738+
// 35.5 Nested if with if-guard
1739+
g5_outer := 5
1740+
if g5_outer > 0 {
1741+
if g5_inner := maybe_positive(g5_outer * 10) {
1742+
print_int(g5_inner) // 50
1743+
} else {
1744+
print_int(0)
1745+
}
1746+
}
1747+
1748+
// 35.6 If-guard in sequence
1749+
mut g6_sum := 0
1750+
if g6_a := maybe_positive(10) {
1751+
g6_sum += g6_a
1752+
}
1753+
if g6_b := maybe_positive(20) {
1754+
g6_sum += g6_b
1755+
}
1756+
if g6_c := maybe_positive(-5) {
1757+
g6_sum += g6_c
1758+
}
1759+
print_int(g6_sum) // 10 + 20 + 0 = 30
1760+
1761+
// 35.7 If-guard with else-if chain
1762+
g7_test := 100
1763+
if g7_val := maybe_positive(-g7_test) {
1764+
print_int(g7_val)
1765+
} else {
1766+
if g7_val2 := maybe_positive(g7_test) {
1767+
print_int(g7_val2) // 100
1768+
} else {
1769+
print_int(0)
1770+
}
1771+
}
1772+
16811773
print_str('=== All tests completed ===')
16821774
}

‎vlib/v2/gen/cleanc/cleanc.v‎

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
9611009
fn (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
10471187
fn (g Gen) get_printf_format(inter ast.StringInter) string {
10481188
base_fmt := match inter.format {

0 commit comments

Comments
 (0)