Skip to content

Commit 67e241a

Browse files
committed
v2: move the entire option/result logic to the transformer
1 parent 68ae4f0 commit 67e241a

4 files changed

Lines changed: 543 additions & 134 deletions

File tree

‎cmd/v2/test.v‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,18 @@ fn main() {
20612061
print_int(0) // 0 (none case)
20622062
}
20632063

2064+
// 35.10 Direct or { value } pattern - successful call
2065+
or_direct1 := maybe_positive(42) or { 0 }
2066+
print_int(or_direct1) // 42
2067+
2068+
// 35.11 Direct or { value } pattern - fallback used
2069+
or_direct2 := maybe_positive(-10) or { 99 }
2070+
print_int(or_direct2) // 99
2071+
2072+
// 35.12 Chained or { value } with computation
2073+
or_chain := maybe_double(25) or { 0 }
2074+
print_int(or_chain + 5) // 50 + 5 = 55
2075+
20642076
// ==================== 36. RANGE EXPRESSIONS ====================
20652077
print_str('--- 36. Range Expressions ---')
20662078

‎cmd/v2/test_v2_self.sh‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
set -e
33

44
# Build v2 with v1
5+
rm v2 || true
56
v v2.v
67

8+
rm v3 || true
79
# Use v2 to compile itself to v3 (using cleanc backend)
810
./v2 -o v3 -backend cleanc v2.v || exit
911

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

Lines changed: 50 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,8 @@ pub fn (mut g Gen) gen() string {
11861186
// 3.6. Builtin helpers (array__free, etc.)
11871187
// IError__free - C interop in source doesn't generate correctly
11881188
g.sb.writeln('static inline void IError__free(IError* ie) { if (ie && ie->_object) free(ie->_object); }')
1189+
// IError_str - convert IError to string by calling msg() method
1190+
g.sb.writeln('static inline string IError_str(IError e) { return e.msg ? e.msg(e._object) : (string){"", 0}; }')
11891191
// array__free - inline implementation since method may not be generated due to $if blocks
11901192
g.sb.writeln('static inline void array__free(array* a) { if (a->data) free(a->data); a->data = 0; a->len = 0; a->cap = 0; }')
11911193
// Array_string__free - free each string then free the array
@@ -1948,6 +1950,10 @@ fn (mut g Gen) infer_type(node ast.Expr) string {
19481950
if t := g.const_types[node.name] {
19491951
return t
19501952
}
1953+
// Special case: 'err' in or-blocks is always IError
1954+
if node.name == 'err' {
1955+
return 'IError'
1956+
}
19511957
return 'int'
19521958
}
19531959
ast.ParenExpr {
@@ -5971,7 +5977,18 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
59715977
g.gen_expr(arg)
59725978
}
59735979
} else {
5974-
g.gen_expr(arg)
5980+
// Check if IError needs to be converted to string
5981+
arg_type := g.infer_type(arg)
5982+
// Convert IError to string for print functions or when param expects string
5983+
is_print_fn := name in ['println', 'eprintln', 'print', 'eprint']
5984+
if arg_type == 'IError' && (param_type == 'string' || is_print_fn) {
5985+
// Convert IError to string: IError_str(err)
5986+
g.sb.write_string('IError_str(')
5987+
g.gen_expr(arg)
5988+
g.sb.write_string(')')
5989+
} else {
5990+
g.gen_expr(arg)
5991+
}
59755992
}
59765993
}
59775994
g.cur_match_type = old_match_type_arg
@@ -6763,7 +6780,18 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
67636780
}
67646781
g.gen_expr(node.expr)
67656782
} else {
6766-
g.gen_expr(node.expr)
6783+
// Check if IError needs to be converted to string
6784+
arg_type := g.infer_type(node.expr)
6785+
// Convert IError to string for print functions or when param expects string
6786+
is_print_fn := name in ['println', 'eprintln', 'print', 'eprint']
6787+
if arg_type == 'IError' && (param_type == 'string' || is_print_fn) {
6788+
// Convert IError to string: IError_str(err)
6789+
g.sb.write_string('IError_str(')
6790+
g.gen_expr(node.expr)
6791+
g.sb.write_string(')')
6792+
} else {
6793+
g.gen_expr(node.expr)
6794+
}
67676795
}
67686796
g.sb.write_string(')')
67696797
}
@@ -7308,121 +7336,38 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
73087336
}
73097337
}
73107338
ast.OrExpr {
7311-
// Or expression: expr or { fallback }
7312-
// Following V's pattern for Result/Option types
7339+
// Most OrExpr should be expanded by transformer, but handle fallback
7340+
// for edge cases (e.g., builtin functions not tracked by transformer)
73137341
typ := g.infer_type(node.expr)
73147342

7315-
// Check if this is a Result type (_result_T)
73167343
if typ.starts_with('_result_') {
7317-
// Get base type from result type name
73187344
base_type := g.result_types[typ] or { 'int' }
7319-
7320-
if node.stmts.len >= 1 {
7321-
// Generate: ({ _result_T _or = expr; if (_or.is_error) { fallback } *(T*)_or.data; })
7322-
g.sb.write_string('({ ${typ} _or_res = ')
7323-
g.gen_expr(node.expr)
7324-
g.sb.write_string('; if (_or_res.is_error) { ')
7325-
7326-
// Handle fallback statements
7327-
if node.stmts.len == 1 {
7328-
stmt := node.stmts[0]
7329-
if stmt is ast.ExprStmt {
7330-
fallback_expr := stmt.expr
7331-
fallback_typ := g.infer_type(fallback_expr)
7332-
if fallback_typ == 'void' || fallback_typ == '' {
7333-
// panic/exit - just execute
7334-
g.gen_expr(fallback_expr)
7335-
g.sb.write_string('; ')
7336-
} else {
7337-
// Value fallback - assign to data
7338-
g.sb.write_string('*(${base_type}*)_or_res.data = ')
7339-
g.gen_expr(fallback_expr)
7340-
g.sb.write_string('; ')
7341-
}
7342-
}
7343-
} else {
7344-
// Multiple statements in or block
7345-
for stmt in node.stmts {
7346-
if stmt is ast.ExprStmt {
7347-
g.gen_expr(stmt.expr)
7348-
g.sb.write_string('; ')
7349-
}
7350-
}
7345+
g.sb.write_string('({ ${typ} _or_res = ')
7346+
g.gen_expr(node.expr)
7347+
g.sb.write_string('; if (_or_res.is_error) { ')
7348+
if node.stmts.len == 1 {
7349+
stmt := node.stmts[0]
7350+
if stmt is ast.ExprStmt {
7351+
g.gen_expr(stmt.expr)
7352+
g.sb.write_string('; ')
73517353
}
7352-
g.sb.write_string('} *(${base_type}*)_or_res.data; })')
7353-
} else {
7354-
// No fallback - just extract value
7355-
g.sb.write_string('(*(${base_type}*)(')
7356-
g.gen_expr(node.expr)
7357-
g.sb.write_string(').data)')
73587354
}
7355+
g.sb.write_string('} *(${base_type}*)_or_res.data; })')
73597356
} else if typ.starts_with('_option_') {
7360-
// Option type handling (similar to Result but checks state != 0)
73617357
base_type := g.option_types[typ] or { 'int' }
7362-
7363-
if node.stmts.len >= 1 {
7364-
g.sb.write_string('({ ${typ} _or_opt = ')
7365-
g.gen_expr(node.expr)
7366-
g.sb.write_string('; if (_or_opt.state != 0) { ')
7367-
7368-
if node.stmts.len == 1 {
7369-
stmt := node.stmts[0]
7370-
if stmt is ast.ExprStmt {
7371-
fallback_expr := stmt.expr
7372-
fallback_typ := g.infer_type(fallback_expr)
7373-
if fallback_typ == 'void' || fallback_typ == '' {
7374-
g.gen_expr(fallback_expr)
7375-
g.sb.write_string('; ')
7376-
} else {
7377-
g.sb.write_string('*(${base_type}*)_or_opt.data = ')
7378-
g.gen_expr(fallback_expr)
7379-
g.sb.write_string('; ')
7380-
}
7381-
}
7382-
} else {
7383-
for stmt in node.stmts {
7384-
if stmt is ast.ExprStmt {
7385-
g.gen_expr(stmt.expr)
7386-
g.sb.write_string('; ')
7387-
}
7388-
}
7389-
}
7390-
g.sb.write_string('} *(${base_type}*)_or_opt.data; })')
7391-
} else {
7392-
g.sb.write_string('(*(${base_type}*)(')
7393-
g.gen_expr(node.expr)
7394-
g.sb.write_string(').data)')
7395-
}
7396-
} else if typ == 'void' || typ == '' {
7397-
// Void type - just execute the expression
7358+
g.sb.write_string('({ ${typ} _or_opt = ')
73987359
g.gen_expr(node.expr)
7399-
} else if node.stmts.len == 1 {
7400-
stmt := node.stmts[0]
7401-
if stmt is ast.ExprStmt {
7402-
fallback_expr := stmt.expr
7403-
fallback_typ := g.infer_type(fallback_expr)
7404-
7405-
if typ == 'string' {
7406-
// For strings, check if empty (simplified "none" check)
7407-
g.sb.write_string('({ string _or_tmp = ')
7408-
g.gen_expr(node.expr)
7409-
g.sb.write_string('; if (_or_tmp.len == 0) { ')
7410-
if fallback_typ == 'void' || fallback_typ == '' {
7411-
g.gen_expr(fallback_expr)
7412-
g.sb.write_string('; ')
7413-
} else {
7414-
g.sb.write_string('_or_tmp = ')
7415-
g.gen_expr(fallback_expr)
7416-
g.sb.write_string('; ')
7417-
}
7418-
g.sb.write_string('} _or_tmp; })')
7419-
} else {
7420-
g.gen_expr(node.expr)
7360+
g.sb.write_string('; if (_or_opt.state != 0) { ')
7361+
if node.stmts.len == 1 {
7362+
stmt := node.stmts[0]
7363+
if stmt is ast.ExprStmt {
7364+
g.gen_expr(stmt.expr)
7365+
g.sb.write_string('; ')
74217366
}
7422-
} else {
7423-
g.gen_expr(node.expr)
74247367
}
7368+
g.sb.write_string('} *(${base_type}*)_or_opt.data; })')
74257369
} else {
7370+
// Unknown type - just generate the expression
74267371
g.gen_expr(node.expr)
74277372
}
74287373
}

0 commit comments

Comments
 (0)