diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 27302b8c79..91709bd692 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1521,11 +1521,16 @@ fn (mut g Gen) mul_reg(a Register, b Register) { g.write8(0xf7) g.write8(0xeb) } + .rdx { + g.write8(0x48) + g.write8(0xf7) + g.write8(0xe2) + } else { - panic('unhandled div ${a}') + panic('unhandled mul ${b}') } } - g.println('mul ${a}') + g.println('mul ${b}') } fn (mut g Gen) imul_reg(r Register) { @@ -1558,11 +1563,16 @@ fn (mut g Gen) div_reg(a Register, b Register) { g.write8(0xf7) g.write8(0xfb) // idiv ebx } + .rdx { + g.write8(0x48) + g.write8(0xf7) + g.write8(0xf2) + } else { - panic('unhandled div ${a}') + panic('unhandled div ${b}') } } - g.println('div ${a}') + g.println('div ${b}') } fn (mut g Gen) mod_reg(a Register, b Register) { @@ -2207,7 +2217,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam } ast.StringLiteral { // TODO: use learel - str := g.eval_escape_codes(e) + str := g.eval_str_lit_escape_codes(e) g.mov64(.rsi, g.allocate_string(str, 2, .abs64)) // for rsi its 2 g.mov_reg_to_var(LocalVar{pos, ast.u64_type_idx, ''}, .rsi) pos += 8 @@ -2247,7 +2257,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam ast.StringLiteral { dest := g.allocate_var(name, 8, 0) ie := right as ast.StringLiteral - str := g.eval_escape_codes(ie) + str := g.eval_str_lit_escape_codes(ie) g.learel(.rsi, g.allocate_string(str, 3, .rel32)) g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi) } @@ -2831,7 +2841,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { } } if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx - && g.table.sym(node.left_type).info !is ast.Enum { + && g.table.sym(node.left_type).info !is ast.Enum && !node.left_type.is_ptr() + && !node.left_type.is_voidptr() { g.n_error('unsupported type for `${node.op}`: ${node.left_type}') } // left: rax, right: rdx @@ -3203,6 +3214,18 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { .gt { jump_addr = g.cjmp(.jle) } + .le { + jump_addr = g.cjmp(.jg) + } + .ge { + jump_addr = g.cjmp(.jl) + } + .ne { + jump_addr = g.cjmp(.je) + } + .eq { + jump_addr = g.cjmp(.jne) + } else { g.n_error('unhandled infix cond token') } diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 588398cf74..b450bb105e 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -686,12 +686,15 @@ fn (mut g Gen) gen_match_expr(expr ast.MatchExpr) { } } -fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string { +fn (mut g Gen) eval_str_lit_escape_codes(str_lit ast.StringLiteral) string { if str_lit.is_raw { return str_lit.val + } else { + return g.eval_escape_codes(str_lit.val) } +} - str := str_lit.val +fn (mut g Gen) eval_escape_codes(str string) string { mut buffer := []u8{} mut i := 0 @@ -705,7 +708,7 @@ fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string { // skip \ i++ match str[i] { - `\\`, `'`, `"` { + `\\`, `'`, `"`, `\`` { buffer << str[i] i++ } @@ -792,9 +795,23 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) { } } -fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) { +fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config VarConfig) { typ := g.get_type_from_var(var) - if typ.is_int() { + if typ == ast.rune_type_idx { + buffer := g.allocate_var('rune-buffer', 8, 0) + g.lea_var_to_reg(reg, buffer) + match reg { + .rax { + g.mov_var_to_reg(.rdi, var, config) + g.write8(0x48) + g.write8(0x89) + g.write8(0x38) + } + else { + g.n_error('rune to string not implemented for ${reg}') + } + } + } else if typ.is_int() { buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough g.mov_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 0), var, config) g.lea_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 1), buffer) @@ -804,7 +821,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) { g.mov_var_to_reg(g.get_builtin_arg_reg(.bool_to_string, 0), var, config) g.call_builtin(.bool_to_string) } else if typ.is_string() { - g.mov_var_to_reg(.rax, var, config) + g.mov_var_to_reg(reg, var, config) } else { g.n_error('int-to-string conversion not implemented for type ${typ}') } @@ -815,7 +832,15 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 } match expr { ast.StringLiteral { - str := g.eval_escape_codes(expr) + str := g.eval_str_lit_escape_codes(expr) + if newline { + g.gen_print(str + '\n', fd) + } else { + g.gen_print(str, fd) + } + } + ast.CharLiteral { + str := g.eval_escape_codes(expr.val) if newline { g.gen_print(str + '\n', fd) } else { @@ -826,7 +851,7 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) vo := g.try_var_offset(expr.name) if vo != -1 { - g.gen_var_to_string(.rax, expr as ast.Ident) + g.gen_var_to_string(.rax, expr, expr as ast.Ident) g.gen_print_reg(.rax, -1, fd) if newline { g.gen_print('\n', fd) @@ -1173,7 +1198,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { if node.exprs.len == 1 { match node.exprs[0] { ast.StringLiteral { - s = g.eval_escape_codes(node.exprs[0] as ast.StringLiteral) + s = g.eval_str_lit_escape_codes(node.exprs[0] as ast.StringLiteral) g.expr(node.exprs[0]) g.mov64(.rax, g.allocate_string(s, 2, .abs64)) } @@ -1383,7 +1408,7 @@ fn (mut g Gen) gen_syscall(node ast.CallExpr) { if expr.field_name == 'str' { match expr.expr { ast.StringLiteral { - s := g.eval_escape_codes(expr.expr) + s := g.eval_str_lit_escape_codes(expr.expr) g.allocate_string(s, 2, .abs64) g.mov64(ra[i], 1) done = true @@ -1400,7 +1425,7 @@ fn (mut g Gen) gen_syscall(node ast.CallExpr) { g.warning('C.syscall expects c"string" or "string".str, C backend will crash', node.pos) } - s := g.eval_escape_codes(expr) + s := g.eval_str_lit_escape_codes(expr) g.allocate_string(s, 2, .abs64) g.mov64(ra[i], 1) } @@ -1512,9 +1537,21 @@ fn (mut g Gen) expr(node ast.Expr) { g.prefix_expr(node) } ast.StringLiteral { - str := g.eval_escape_codes(node) + str := g.eval_str_lit_escape_codes(node) g.allocate_string(str, 3, .rel32) } + ast.CharLiteral { + bytes := g.eval_escape_codes(node.val) + .bytes() + mut val := rune(0) + for i, v in bytes { + val |= v << (i * 8) + if i >= sizeof(rune) { + g.n_error('runes are only 4 bytes wide') + } + } + g.movabs(.rax, i64(val)) + } ast.StructInit { pos := g.allocate_by_type('_anonstruct', node.typ) g.init_struct(LocalVar{ offset: pos, typ: node.typ }, node) diff --git a/vlib/v/gen/native/tests/pointers.vv b/vlib/v/gen/native/tests/pointers.vv new file mode 100644 index 0000000000..bafe190836 --- /dev/null +++ b/vlib/v/gen/native/tests/pointers.vv @@ -0,0 +1,68 @@ +fn main() { + test_eq_ne() + test_lt_gt() + test_ref_deref() + println("ok") +} + +fn test_eq_ne() { + unsafe { + mut a := voidptr(0) + mut b := voidptr(0) + assert a == a + assert !(a != a) + assert a == b + assert !(a != b) + + a = voidptr(0xdeadbeef) + assert a != b + assert !(a == b) + + b = voidptr(0xdeadbeef) + assert a == b + assert !(a != b) + } +} + +fn test_lt_gt() { + unsafe { + mut a := voidptr(0) + mut b := voidptr(1) + + assert !(a < a) + assert !(a > a) + assert a >= a + assert a <= a + + assert a < b + assert !(a > b) + assert a <= b + assert !(a >= b) + + a = voidptr(0x42) + assert a > b + assert a >= b + assert !(a < b) + assert !(a <= b) + + b = voidptr(0x42) + assert a >= b + assert a <= b + assert !(a > b) + assert !(a < b) + } +} + +fn test_ref_deref() { + mut a := 42 + b := &a + c := &b + + assert *b == 42 + + a = 50 + assert *b == 50 + + assert *c == b + assert **c == *b +} diff --git a/vlib/v/gen/native/tests/pointers.vv.out b/vlib/v/gen/native/tests/pointers.vv.out new file mode 100644 index 0000000000..9766475a41 --- /dev/null +++ b/vlib/v/gen/native/tests/pointers.vv.out @@ -0,0 +1 @@ +ok diff --git a/vlib/v/gen/native/tests/string.vv b/vlib/v/gen/native/tests/string.vv index ebe72f9cb5..7cbcd35369 100644 --- a/vlib/v/gen/native/tests/string.vv +++ b/vlib/v/gen/native/tests/string.vv @@ -21,8 +21,25 @@ fn test_raw_string() { println(raw) } +fn test_runes() { + mut a := `V` + println(a) + + a = `😀` + println(a) + + rocket := `🚀` + println(rocket) + + // should all print `★` + print(`\u2605`) + print(`\xe2\x98\x85`) + println(`\xe2\x98\x85`) +} + fn main() { test_unicode_characters() test_escape_codes() test_raw_string() + test_runes() } \ No newline at end of file diff --git a/vlib/v/gen/native/tests/string.vv.out b/vlib/v/gen/native/tests/string.vv.out index 188e46ae74..c6d8227ab8 100644 --- a/vlib/v/gen/native/tests/string.vv.out +++ b/vlib/v/gen/native/tests/string.vv.out @@ -4,4 +4,8 @@ aaa ## # ### # -hello\tworld\n \ No newline at end of file +hello\tworld\n +V +😀 +🚀 +★★★ \ No newline at end of file