diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 614636aee7..3cccbff69b 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -212,6 +212,10 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) { c.g.println('cmp ${reg}, ${val}') } +fn (mut c Amd64) cmp_reg2(reg Register, reg2 Register) { + c.cmp_reg(reg as Amd64Register, reg2 as Amd64Register) +} + // `cmp rax, rbx` fn (mut c Amd64) cmp_reg(reg Amd64Register, reg2 Amd64Register) { match reg { @@ -1101,8 +1105,12 @@ fn (mut c Amd64) push(r Register) { c.g.write8(0x50 + i32(reg) - 8) } c.is_16bit_aligned = !c.is_16bit_aligned - c.g.println('push ${reg}') c.g.stack_depth++ + c.g.println('push ${reg}; stack_depth:${c.g.stack_depth}') +} + +fn (mut c Amd64) pop2(r Register) { + c.pop(r as Amd64Register) } pub fn (mut c Amd64) pop(reg Amd64Register) { @@ -1111,8 +1119,8 @@ pub fn (mut c Amd64) pop(reg Amd64Register) { } c.g.write8(0x58 + i32(reg) % 8) c.is_16bit_aligned = !c.is_16bit_aligned - c.g.println('pop ${reg}') c.g.stack_depth-- + c.g.println('pop ${reg} ; stack_depth:${c.g.stack_depth}') } pub fn (mut c Amd64) sub8(reg Amd64Register, val i32) { @@ -3620,7 +3628,7 @@ pub fn (mut c Amd64) allocate_var(name string, size i32, initial_val Number) i32 } // println('allocate_var(size=$size, initial_val=$initial_val)') - c.g.println('mov [rbp-${int(n).hex2()}], ${initial_val} ; Allocate var `${name}`') + c.g.println('mov [rbp-${int(n).hex2()}], ${initial_val} ; Allocate var `${name}` size: ${size}') return c.g.stack_var_pos } diff --git a/vlib/v/gen/native/arm64.v b/vlib/v/gen/native/arm64.v index 9022515054..7f77b54fcf 100644 --- a/vlib/v/gen/native/arm64.v +++ b/vlib/v/gen/native/arm64.v @@ -535,6 +535,14 @@ pub fn (mut c Arm64) add_reg2(r Register, r2 Register) { panic('Arm64.add_reg2() not implemented') } +fn (mut c Arm64) pop2(r Register) { + panic('Arm64.pop2() not implemented') +} + +fn (mut c Arm64) cmp_reg2(reg Register, reg2 Register) { + panic('Arm64.add_reg2() not implemented') +} + fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) { panic('Arm64.add_reg2() not implemented') } diff --git a/vlib/v/gen/native/blacklist.v b/vlib/v/gen/native/blacklist.v index 923ee77cf5..c618acd08c 100644 --- a/vlib/v/gen/native/blacklist.v +++ b/vlib/v/gen/native/blacklist.v @@ -46,7 +46,12 @@ const whitelist = { 'string.is_capital': false 'string.is_ascii': false 'string.is_identifier': false - // 'string.is_blank': false need for in + 'string.is_blank': false + 'string.indent_width': false + 'string.index_u8': false + 'string.last_index': true + 'string.last_index_u8': false + 'string.contains_u8': false } fn (g &Gen) is_blacklisted(name string, is_builtin bool) bool { diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index d484d90eae..08a3cd9a85 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -95,6 +95,7 @@ mut: cmp_to_stack_top(r Register) cmp_var_reg(var Var, reg Register, config VarConfig) cmp_var(var Var, val i32, config VarConfig) + cmp_reg2(reg Register, reg2 Register) cmp_zero(reg Register) convert_bool_to_string(r Register) convert_int_to_string(a Register, b Register) @@ -131,6 +132,7 @@ mut: mov64(r Register, val Number) movabs(reg Register, val i64) patch_relative_jmp(pos i32, addr i64) + pop2(r Register) prefix_expr(node ast.PrefixExpr) push(r Register) ret() diff --git a/vlib/v/gen/native/stmt.c.v b/vlib/v/gen/native/stmt.c.v index 3fe9c27cdb..0ef7da19c9 100644 --- a/vlib/v/gen/native/stmt.c.v +++ b/vlib/v/gen/native/stmt.c.v @@ -255,6 +255,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { } fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that + main_reg := g.code_gen.main_reg() if node.is_range { g.println('; for ${node.val_var} in range {') // for a in node.cond .. node.high { @@ -262,7 +263,6 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that i := g.code_gen.allocate_var(node.val_var, 8, i64(0)) // iterator variable g.println('; evaluate node.cond for lower bound:') g.expr(node.cond) // outputs the lower loop bound (initial value) to the main reg - main_reg := g.code_gen.main_reg() g.println('; move the result to i') g.code_gen.mov_reg_to_var(LocalVar{i, ast.i64_type_idx, node.val_var}, main_reg) // i = node.cond // initial value @@ -299,11 +299,79 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that g.labels.addrs[end_label] = g.pos() g.println('; label ${end_label} (end_label)') g.println('; for ${node.val_var} in range }') + } else if node.kind == .string { + g.println('; for ${node.val_var} in string {') + // for c in my_string { + + key_var := if node.key_var == '' { 'i' } else { node.key_var } + i := g.code_gen.allocate_var(key_var, 8, i64(0)) // iterator variable + c := g.code_gen.allocate_var(node.val_var, 1, i64(0)) // char variable + + g.expr(node.cond) // get the address of the string variable + g.code_gen.mov_deref(Amd64Register.rdx, main_reg, ast.charptr_type) + g.println('; push address of the string chars') + g.code_gen.push(Amd64Register.rdx) // address of the string + g.code_gen.add(main_reg, g.get_field_offset(ast.string_type, 'len')) + g.println('; push address of the len:') + g.code_gen.push(main_reg) // address of the len + + start := g.pos() // label-begin: + + g.println('; check iterator against upper loop bound') + g.code_gen.mov_var_to_reg(main_reg, LocalVar{i, ast.i64_type_idx, key_var}) + g.println('; pop address of the len:') + g.code_gen.pop2(Amd64Register.rdx) + g.println('; push address of the len:') + g.code_gen.push(Amd64Register.rdx) // len + g.code_gen.mov_deref(Amd64Register.rdx, Amd64Register.rdx, ast.int_type) + g.code_gen.cmp_reg2(main_reg, Amd64Register.rdx) + jump_addr := g.code_gen.cjmp(.jge) // leave loop i >= len + + g.println('; pop address of the len:') + g.code_gen.pop2(Amd64Register.rdx) // len + g.println('; pop address of the string chars') + g.code_gen.pop2(Amd64Register.rax) // address of the string + g.println('; push address of the string chars') + g.code_gen.push(Amd64Register.rax) + g.println('; push address of the len:') + g.code_gen.push(Amd64Register.rdx) // len + + g.code_gen.mov_var_to_reg(Amd64Register.rdx, LocalVar{i, ast.i64_type_idx, key_var}) + g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rdx) + g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u8_type_idx) + g.code_gen.mov_reg_to_var(LocalVar{c, ast.u8_type_idx, node.val_var}, Amd64Register.rax) // store the char + + end_label := g.labels.new_label() + g.labels.patches << LabelPatch{ + id: end_label + pos: jump_addr + } + g.println('; jump to label ${end_label} (end_label)') + + start_label := g.labels.new_label() // used for continue + g.labels.branches << BranchLabel{ + name: node.label + start: start_label + end: end_label + } + g.stmts(node.stmts) // writes the actual body of the loop + + g.labels.addrs[start_label] = g.pos() // used for continue (continue: jump before the inc) + g.println('; label ${start_label} (continue_label)') + + g.code_gen.inc_var(LocalVar{i, ast.i64_type_idx, key_var}) + g.labels.branches.pop() + g.code_gen.jmp_back(start) // loops + + g.labels.addrs[end_label] = g.pos() + g.code_gen.pop2(Amd64Register.rdx) // len + g.code_gen.pop2(Amd64Register.rax) // address of the string + g.println('; label ${end_label} (end_label)') + g.println('; for ${node.val_var} in string }') /* } else if node.kind == .array { } else if node.kind == .array_fixed { } else if node.kind == .map { - } else if node.kind == .string { } else if node.kind == .struct { } else if it.kind in [.array, .string] || it.cond_type.has_flag(.variadic) { } else if it.kind == .map { diff --git a/vlib/v/gen/native/tests/builtin.vv b/vlib/v/gen/native/tests/builtin.vv index 4358631896..4ebf63409e 100644 --- a/vlib/v/gen/native/tests/builtin.vv +++ b/vlib/v/gen/native/tests/builtin.vv @@ -22,7 +22,6 @@ assert !a.is_ascii() assert '_9'.is_identifier() == true assert 'a 9'.is_identifier() == false assert 't'.is_identifier() == true -/* assert ''.is_blank() assert ' '.is_blank() assert ' \t'.is_blank() @@ -48,18 +47,18 @@ assert !a.is_ascii() assert 'abc'.index_u8(`A`) == -1 assert 'abc'.index_u8(`B`) == -1 assert 'abc'.index_u8(`C`) == -1 +/* assert 'abcabca'.last_index('ca')? == 5 assert 'abcabca'.last_index('ab')? == 3 assert 'abcabca'.last_index('b')? == 4 assert 'Zabcabca'.last_index('Z')? == 0 x := 'Zabcabca'.last_index('Y') assert x == none - // TODO: `assert 'Zabcabca'.index_last('Y') == none` is a cgen error, 2023/12/04 +*/ assert 'abcabca'.last_index_u8(`a`) == 6 assert 'abcabca'.last_index_u8(`c`) == 5 assert 'abcabca'.last_index_u8(`b`) == 4 assert 'Zabcabca'.last_index_u8(`Z`) == 0 - // assert 'abc'.last_index_u8(`d`) == -1 assert 'abc'.last_index_u8(`A`) == -1 assert 'abc'.last_index_u8(`B`) == -1 @@ -69,6 +68,7 @@ assert !a.is_ascii() assert 'abc abca'.contains_u8(`c`) assert 'abc abca'.contains_u8(` `) assert !'abc abca'.contains_u8(`A`) +/* assert 'Abcd'.camel_to_snake() == 'abcd' assert 'aBcd'.camel_to_snake() == 'a_bcd' assert 'AAbb'.camel_to_snake() == 'aa_bb' diff --git a/vlib/v/gen/native/tests/linux.vv b/vlib/v/gen/native/tests/linux.vv new file mode 100644 index 0000000000..fc8ce95945 --- /dev/null +++ b/vlib/v/gen/native/tests/linux.vv @@ -0,0 +1,21 @@ + +fn test_for_c_in_string() { + $if windows { + println('0') + println('97') + println('1') + println('98') + println('2') + println('99') + } $else { + s := 'abc' + for i, c in s { + println(i) + println(int(c)) + } + } +} + +fn main() { + test_for_c_in_string() +} diff --git a/vlib/v/gen/native/tests/linux.vv.out b/vlib/v/gen/native/tests/linux.vv.out new file mode 100644 index 0000000000..e23e1e2d2b --- /dev/null +++ b/vlib/v/gen/native/tests/linux.vv.out @@ -0,0 +1,6 @@ +0 +97 +1 +98 +2 +99 diff --git a/vlib/v/gen/native/tests/native_test.v b/vlib/v/gen/native/tests/native_test.v index 6c2a4aa102..ea5732a935 100644 --- a/vlib/v/gen/native/tests/native_test.v +++ b/vlib/v/gen/native/tests/native_test.v @@ -49,7 +49,7 @@ fn test_native() { continue } } - if test == 'fibonacci_native.vv' { + if test == 'fibonacci_native.vv' || test.contains('linux') { if user_os == 'windows' { println('>>> SKIPPING ${test} on windows for now') continue