1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

native: rune type literals/printing, pointer comparison and some missing branches in functions (#17839)

This commit is contained in:
Spydr 2023-04-01 00:09:02 +02:00 committed by GitHub
parent e1b8617c94
commit fedf0f7939
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 170 additions and 20 deletions

View File

@ -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')
}

View File

@ -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)

View File

@ -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
}

View File

@ -0,0 +1 @@
ok

View File

@ -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()
}

View File

@ -4,4 +4,8 @@
aaa
## #
### #
hello\tworld\n
hello\tworld\n
V
😀
🚀
★★★