Skip to content

Commit d6a5b80

Browse files
committed
v2: 17 out of 26 builtin tests now pass with cleanc
1 parent e8d7eeb commit d6a5b80

7 files changed

Lines changed: 132 additions & 16 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// dummy placeholder for functions from `map_d_gcboehm_opt.v`
2+
// that might be needed for compile time
3+
// `$if gcboehm_opt ? { ... } $else { ... }`
4+
5+
module builtin
6+
7+
fn new_map_noscan_key(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn,
8+
free_fn MapFreeFn) map {
9+
return new_map(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, free_fn)
10+
}
11+
12+
fn new_map_noscan_value(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn,
13+
free_fn MapFreeFn) map {
14+
return new_map(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, free_fn)
15+
}
16+
17+
fn new_map_noscan_key_value(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn,
18+
free_fn MapFreeFn) map {
19+
return new_map(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, free_fn)
20+
}
21+
22+
fn new_map_init_noscan_key(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn,
23+
n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map {
24+
return new_map_init(hash_fn, key_eq_fn, clone_fn, free_fn, n, key_bytes, value_bytes, keys, values)
25+
}
26+
27+
fn new_map_init_noscan_value(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn,
28+
n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map {
29+
return new_map_init(hash_fn, key_eq_fn, clone_fn, free_fn, n, key_bytes, value_bytes, keys, values)
30+
}
31+
32+
fn new_map_init_noscan_key_value(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn,
33+
n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map {
34+
return new_map_init(hash_fn, key_eq_fn, clone_fn, free_fn, n, key_bytes, value_bytes, keys, values)
35+
}

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

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ pub fn (mut g Gen) gen() string {
455455
g.sb.writeln('')
456456

457457
// Pass 4: Function forward declarations
458+
mut test_fn_names := []string{}
459+
mut has_main := false
458460
for file in g.files {
459461
g.set_file_module(file)
460462
for stmt in file.stmts {
@@ -473,6 +475,13 @@ pub fn (mut g Gen) gen() string {
473475
if fn_name == '' {
474476
continue
475477
}
478+
if fn_name == 'main' {
479+
has_main = true
480+
}
481+
if stmt.name.starts_with('test_') && !stmt.is_method
482+
&& stmt.typ.params.len == 0 {
483+
test_fn_names << fn_name
484+
}
476485
if g.env != unsafe { nil } {
477486
if fn_scope := g.env.get_fn_scope(g.cur_module, fn_name) {
478487
g.cur_fn_scope = fn_scope
@@ -494,6 +503,25 @@ pub fn (mut g Gen) gen() string {
494503
g.gen_file(file)
495504
}
496505

506+
// Generate test runner main if this is a test file (has test_ functions but no main)
507+
if !has_main && test_fn_names.len > 0 {
508+
g.sb.writeln('')
509+
g.sb.writeln('int main(int ___argc, char** ___argv) {')
510+
g.sb.writeln('\tg_main_argc = ___argc;')
511+
g.sb.writeln('\tg_main_argv = (void*)___argv;')
512+
for test_fn in test_fn_names {
513+
msg_run := 'Running test: ${test_fn}...'
514+
msg_ok := ' OK'
515+
g.sb.writeln('\tprintln((string){"${msg_run}", sizeof("${msg_run}") - 1});')
516+
g.sb.writeln('\t${test_fn}();')
517+
g.sb.writeln('\tprintln((string){"${msg_ok}", sizeof("${msg_ok}") - 1});')
518+
}
519+
msg_all := 'All ${test_fn_names.len} tests passed.'
520+
g.sb.writeln('\tprintln((string){"${msg_all}", sizeof("${msg_all}") - 1});')
521+
g.sb.writeln('\treturn 0;')
522+
g.sb.writeln('}')
523+
}
524+
497525
return g.sb.str()
498526
}
499527

@@ -1302,9 +1330,19 @@ fn (mut g Gen) gen_stmt(node ast.Stmt) {
13021330
ast.ExprStmt {
13031331
if node.expr is ast.UnsafeExpr {
13041332
unsafe_expr := node.expr as ast.UnsafeExpr
1333+
if unsafe_expr.stmts.len > 1 {
1334+
g.write_indent()
1335+
g.sb.writeln('{')
1336+
g.indent++
1337+
}
13051338
for stmt in unsafe_expr.stmts {
13061339
g.gen_stmt(stmt)
13071340
}
1341+
if unsafe_expr.stmts.len > 1 {
1342+
g.indent--
1343+
g.write_indent()
1344+
g.sb.writeln('}')
1345+
}
13081346
return
13091347
}
13101348
if node.expr is ast.IfExpr {
@@ -3452,6 +3490,12 @@ fn escape_c_string_literal_content(raw string) string {
34523490
if ch == `"` {
34533491
sb.write_u8(`\\`)
34543492
sb.write_u8(`"`)
3493+
} else if ch == `\n` {
3494+
sb.write_u8(`\\`)
3495+
sb.write_u8(`n`)
3496+
} else if ch == `\r` {
3497+
sb.write_u8(`\\`)
3498+
sb.write_u8(`r`)
34553499
} else {
34563500
sb.write_u8(ch)
34573501
}
@@ -3662,10 +3706,20 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
36623706
g.sb.write_string('false')
36633707
} else if node.kind == .char {
36643708
raw := strip_literal_quotes(node.value)
3665-
escaped := escape_char_literal_content(raw)
3666-
g.sb.write_u8(`'`)
3667-
g.sb.write_string(escaped)
3668-
g.sb.write_u8(`'`)
3709+
if raw.len > 1 && raw[0] != `\\` {
3710+
// Multi-byte UTF-8 character: emit as numeric codepoint
3711+
runes := raw.runes()
3712+
if runes.len > 0 {
3713+
g.sb.write_string(int(runes[0]).str())
3714+
} else {
3715+
g.sb.write_string("'${raw}'")
3716+
}
3717+
} else {
3718+
escaped := escape_char_literal_content(raw)
3719+
g.sb.write_u8(`'`)
3720+
g.sb.write_string(escaped)
3721+
g.sb.write_u8(`'`)
3722+
}
36693723
} else {
36703724
g.sb.write_string(sanitize_c_number_literal(node.value))
36713725
}
@@ -4427,6 +4481,12 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
44274481
}
44284482
}
44294483
ast.SelectorExpr {
4484+
// typeof(x).name -> just emit the typeof string directly (already a string)
4485+
if node.lhs is ast.KeywordOperator && node.lhs.op == .key_typeof
4486+
&& node.rhs.name == 'name' {
4487+
g.gen_keyword_operator(node.lhs)
4488+
return
4489+
}
44304490
// C.<ident> references C macros/constants directly (e.g. C.EOF -> EOF).
44314491
if node.lhs is ast.Ident && node.lhs.name == 'C' {
44324492
g.sb.write_string(node.rhs.name)

‎vlib/v2/pref/pref.v‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ fn detect_vroot() string {
6969

7070
pub fn new_preferences() Preferences {
7171
return Preferences{
72-
backend: if os.user_os() == 'macos' { .arm64 } else { .x64 }
72+
backend: .cleanc
7373
}
7474
}
7575

7676
// new_preferences_from_args parses full args list including option values
7777
pub fn new_preferences_from_args(args []string) Preferences {
78-
// Default backend based on OS: macOS defaults to arm64, others to x64
79-
default_backend := if os.user_os() == 'macos' { 'arm64' } else { 'x64' }
78+
// Default backend is cleanc
79+
default_backend := 'cleanc'
8080
mut backend_str_long := cmdline.option(args, '-backend', '')
8181
if backend_str_long.len == 0 {
8282
backend_str_long = ''
@@ -92,7 +92,7 @@ pub fn new_preferences_from_args(args []string) Preferences {
9292
} else {
9393
default_backend
9494
}
95-
mut backend := if os.user_os() == 'macos' { Backend.arm64 } else { Backend.x64 }
95+
mut backend := Backend.cleanc
9696
match backend_str {
9797
'cleanc' { backend = .cleanc }
9898
'v' { backend = .v }

‎vlib/v2/scanner/scanner.v‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ fn (mut s Scanner) number() {
557557
s.offset++
558558
for {
559559
c2 := s.src[s.offset]
560-
if c2 >= `0` && c2 <= `7` {
560+
if (c2 >= `0` && c2 <= `7`) || c2 == `_` {
561561
s.offset++
562562
continue
563563
}
@@ -575,8 +575,9 @@ fn (mut s Scanner) number() {
575575
s.offset++
576576
continue
577577
}
578-
// fraction
579-
else if !has_decimal && c == `.` && s.src[s.offset + 1] != `.` {
578+
// fraction (only if next char after '.' is a digit, not a letter like '.hex()')
579+
else if !has_decimal && c == `.` && s.src[s.offset + 1] != `.`
580+
&& s.src[s.offset + 1] >= `0` && s.src[s.offset + 1] <= `9` {
580581
has_decimal = true
581582
s.offset++
582583
continue

‎vlib/v2/ssa/builder.v‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3489,6 +3489,14 @@ fn (mut b Builder) expr_call(node ast.CallExpr) ValueID {
34893489
mangled_type = base_type
34903490
}
34913491
name = '${mangled_type}__${mangled_method}'
3492+
// If method not found, try lowercase type name (e.g., Array -> array)
3493+
if !map_has_key_type_id(b.func_ret_types, name) {
3494+
lower_name := '${mangled_type.to_lower()}__${mangled_method}'
3495+
if map_has_key_type_id(b.func_ret_types, lower_name) {
3496+
name = lower_name
3497+
mangled_type = mangled_type.to_lower()
3498+
}
3499+
}
34923500
is_method_call = true
34933501
// Check if this is a flag enum method
34943502
if map_has_key_bool(b.flag_enum_names, mangled_type)
@@ -3786,7 +3794,7 @@ fn (mut b Builder) expr_call_or_cast(node ast.CallOrCastExpr) ValueID {
37863794
if node.lhs is ast.Ident {
37873795
cast_name := node.lhs.name
37883796
if cast_name in ['int', 'i64', 'i32', 'i16', 'i8', 'u64', 'u32', 'u16', 'u8', 'f32', 'f64',
3789-
'voidptr', 'charptr', 'byteptr', 'usize', 'isize', 'rune', 'bool'] {
3797+
'voidptr', 'charptr', 'byteptr', 'usize', 'isize', 'rune', 'bool', 'char', 'byte'] {
37903798
// Type cast: just evaluate the expression (enums are already ints in SSA)
37913799
return b.expr(node.expr)
37923800
}

‎vlib/v2/transformer/transformer.v‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5310,6 +5310,18 @@ fn (t &Transformer) strip_pos(e ast.Expr) ast.Expr {
53105310
name: e.name
53115311
}
53125312
}
5313+
ast.PrefixExpr {
5314+
return ast.PrefixExpr{
5315+
op: e.op
5316+
expr: t.strip_pos(e.expr)
5317+
}
5318+
}
5319+
ast.CastExpr {
5320+
return ast.CastExpr{
5321+
typ: e.typ
5322+
expr: t.strip_pos(e.expr)
5323+
}
5324+
}
53135325
else {
53145326
return e
53155327
}
@@ -10680,7 +10692,7 @@ fn (t &Transformer) get_module_scope(module_name string) ?&types.Scope {
1068010692
fn (t &Transformer) is_cast_type_name(name string) bool {
1068110693
// Built-in primitive types
1068210694
if name in ['int', 'i8', 'i16', 'i32', 'i64', 'u8', 'u16', 'u32', 'u64', 'f32', 'f64', 'bool',
10683-
'byte', 'rune', 'usize', 'isize', 'string', 'byteptr', 'charptr', 'voidptr'] {
10695+
'byte', 'char', 'rune', 'usize', 'isize', 'string', 'byteptr', 'charptr', 'voidptr'] {
1068410696
return true
1068510697
}
1068610698
// Type names start with uppercase in V

‎vlib/v2/types/checker.v‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ fn (mut c Checker) expr_impl(expr ast.Expr) Type {
757757
// c.log('ast.BasicLiteral: ${expr.kind.str()}: ${expr.value}')
758758
match expr.kind {
759759
.char {
760-
return Type(char_)
760+
return Type(rune_)
761761
}
762762
.key_false, .key_true {
763763
return bool_
@@ -1114,10 +1114,10 @@ fn (mut c Checker) expr_impl(expr ast.Expr) Type {
11141114
return c.expr(expr.expr)
11151115
}
11161116
ast.RangeExpr {
1117-
c.expr(expr.start)
1117+
start_type := c.expr(expr.start)
11181118
c.expr(expr.end)
11191119
return Type(Array{
1120-
elem_type: int_
1120+
elem_type: start_type
11211121
})
11221122
}
11231123
ast.SelectExpr {

0 commit comments

Comments
 (0)