mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
native: support nested structs, improve support for right expr of IndexExpr (#24627)
This commit is contained in:
parent
64872fe858
commit
da8d8fa27c
6 changed files with 104 additions and 14 deletions
|
@ -631,7 +631,7 @@ fn (mut c Amd64) mov_deref(r Register, rptr Register, typ ast.Type) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.g.write8(i32(reg) % 8 * 8 + i32(regptr) % 8)
|
c.g.write8(i32(reg) % 8 * 8 + i32(regptr) % 8)
|
||||||
c.g.println('mov ${reg}, [${regptr}]')
|
c.g.println('mov ${reg}, [${regptr}]; size ${size}')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) mov_store(regptr Amd64Register, reg Amd64Register, size Size) {
|
fn (mut c Amd64) mov_store(regptr Amd64Register, reg Amd64Register, size Size) {
|
||||||
|
@ -1887,7 +1887,7 @@ pub fn (mut c Amd64) call_fn(node ast.CallExpr) {
|
||||||
c.bitand_reg(.rdx, .rbx)
|
c.bitand_reg(.rdx, .rbx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {}
|
else {} // handled below
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_floats[i] {
|
if is_floats[i] {
|
||||||
|
@ -2214,12 +2214,13 @@ fn (mut c Amd64) mov_float_xmm0_var(reg Amd64Register, var_type ast.Type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) create_string_struct(typ ast.Type, name string, str string) {
|
fn (mut c Amd64) create_string_struct(typ ast.Type, name string, str string) i32 {
|
||||||
dest := c.allocate_var(name, c.g.get_type_size(typ), i64(0))
|
dest := c.allocate_var(name, c.g.get_type_size(typ), i64(0))
|
||||||
c.learel(Amd64Register.rsi, c.g.allocate_string(str, 3, .rel32))
|
c.learel(Amd64Register.rsi, c.g.allocate_string(str, 3, .rel32))
|
||||||
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
|
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
|
||||||
offset := c.g.get_field_offset(typ, 'len')
|
offset := c.g.get_field_offset(typ, 'len')
|
||||||
c.mov_int_to_var(LocalVar{dest, ast.i32_type_idx, name}, i32(str.len), offset: offset)
|
c.mov_int_to_var(LocalVar{dest, ast.i32_type_idx, name}, i32(str.len), offset: offset)
|
||||||
|
return dest
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.Expr, name string, ident ast.Ident) {
|
fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.Expr, name string, ident ast.Ident) {
|
||||||
|
@ -3698,14 +3699,20 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
for f in init.init_fields {
|
for f in init.init_fields {
|
||||||
|
c.g.println('; ${var.name}.${f.name}')
|
||||||
field := ts.find_field(f.name) or {
|
field := ts.find_field(f.name) or {
|
||||||
c.g.n_error('${@LOCATION} Could not find field `${f.name}` on init (${ts.info})')
|
c.g.n_error('${@LOCATION} Could not find field `${f.name}` on init (${ts.info})')
|
||||||
}
|
}
|
||||||
offset := c.g.structs[typ.idx()].offsets[field.i]
|
f_offset := c.g.structs[typ.idx()].offsets[field.i]
|
||||||
|
f_ts := c.g.table.sym(field.typ)
|
||||||
|
|
||||||
c.g.expr(f.expr)
|
c.g.expr(f.expr)
|
||||||
// TODO: expr not on rax
|
if f_ts.info is ast.Struct {
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: field.typ)
|
c.copy_struct_to_struct(field, f_offset, 0, var)
|
||||||
|
} else {
|
||||||
|
// TODO: expr not on rax -> may be done
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rax, offset: f_offset, typ: field.typ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GlobalVar {
|
GlobalVar {
|
||||||
|
@ -3714,6 +3721,36 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// f_offset is the offset of the field in the root struct
|
||||||
|
// data_offset is the offset to add to rax to find the data
|
||||||
|
// needs rax to hold the address of the root field data
|
||||||
|
fn (mut c Amd64) copy_struct_to_struct(field ast.StructField, f_offset i32, data_offset i32, var LocalVar) {
|
||||||
|
f_typ_idx := field.typ.idx()
|
||||||
|
f_ts := c.g.table.sym(field.typ)
|
||||||
|
|
||||||
|
for f2 in (f_ts.info as ast.Struct).fields {
|
||||||
|
c.g.println('; ${var.name}. ... .${f2.name}')
|
||||||
|
field2 := f_ts.find_field(f2.name) or {
|
||||||
|
c.g.n_error('${@LOCATION} Could not find field `${f2.name}` on init (${f_ts.info})')
|
||||||
|
}
|
||||||
|
f2_offset := c.g.structs[f_typ_idx].offsets[field2.i]
|
||||||
|
f2_ts := c.g.table.sym(field2.typ)
|
||||||
|
|
||||||
|
if f2_ts.info is ast.Struct {
|
||||||
|
c.copy_struct_to_struct(field2, f_offset + f2_offset, data_offset + f2_offset,
|
||||||
|
var)
|
||||||
|
} else {
|
||||||
|
c.mov_reg(Amd64Register.rdx, Amd64Register.rax)
|
||||||
|
c.add(Amd64Register.rdx, data_offset + f2_offset)
|
||||||
|
c.mov_deref(Amd64Register.rdx, Amd64Register.rdx, field2.typ)
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rdx,
|
||||||
|
offset: f_offset + f2_offset
|
||||||
|
typ: field2.typ
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
|
fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
|
||||||
match var {
|
match var {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
|
|
|
@ -543,7 +543,7 @@ fn (mut c Arm64) cmp_reg2(reg Register, reg2 Register) {
|
||||||
panic('Arm64.add_reg2() not implemented')
|
panic('Arm64.add_reg2() not implemented')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) {
|
fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) i32 {
|
||||||
panic('Arm64.add_reg2() not implemented')
|
panic('Arm64.add_reg2() not implemented')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,8 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
str := g.eval_str_lit_escape_codes(node)
|
str := g.eval_str_lit_escape_codes(node)
|
||||||
g.code_gen.create_string_struct(ast.string_type_idx, 'string_lit', str)
|
pos := g.code_gen.create_string_struct(ast.string_type_idx, 'str_lit', str)
|
||||||
|
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
|
||||||
}
|
}
|
||||||
ast.CharLiteral {
|
ast.CharLiteral {
|
||||||
bytes := g.eval_escape_codes(node.val)
|
bytes := g.eval_escape_codes(node.val)
|
||||||
|
@ -131,9 +132,14 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
if node.left_type.is_string() {
|
if node.left_type.is_string() {
|
||||||
g.expr(node.index)
|
g.expr(node.index)
|
||||||
g.code_gen.mov_var_to_reg(Amd64Register.rdx, node.left as ast.Ident) // load address of string
|
g.code_gen.push(Amd64Register.rax)
|
||||||
g.code_gen.add_reg2(Amd64Register.rdx, Amd64Register.rax) // add the offset to the address
|
|
||||||
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rdx, ast.u8_type_idx)
|
g.expr(node.left) // load address of string struct
|
||||||
|
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u64_type_idx) // load value of the str pointer
|
||||||
|
|
||||||
|
g.code_gen.pop2(Amd64Register.rdx) // index
|
||||||
|
g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rdx) // add the offset to the address
|
||||||
|
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u8_type_idx)
|
||||||
} else if node.left_type.is_pointer() {
|
} else if node.left_type.is_pointer() {
|
||||||
dump(node)
|
dump(node)
|
||||||
g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string')
|
g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string')
|
||||||
|
@ -464,9 +470,12 @@ fn (mut g Gen) gen_selector_expr(expr ast.SelectorExpr) {
|
||||||
g.code_gen.add(main_reg, offset)
|
g.code_gen.add(main_reg, offset)
|
||||||
}
|
}
|
||||||
if expr.next_token != .dot { // the deref needs to be on the last selector (that has no . after it)
|
if expr.next_token != .dot { // the deref needs to be on the last selector (that has no . after it)
|
||||||
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
|
ts := g.table.sym(expr.typ)
|
||||||
|
if ts.info !is ast.Struct {
|
||||||
|
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.println('; .${expr.field_name} {')
|
g.println('; .${expr.field_name} }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_left_value(node ast.Expr) {
|
fn (mut g Gen) gen_left_value(node ast.Expr) {
|
||||||
|
|
|
@ -100,7 +100,7 @@ mut:
|
||||||
convert_bool_to_string(r Register)
|
convert_bool_to_string(r Register)
|
||||||
convert_int_to_string(a Register, b Register)
|
convert_int_to_string(a Register, b Register)
|
||||||
convert_rune_to_string(r Register, buffer i32, var Var, config VarConfig)
|
convert_rune_to_string(r Register, buffer i32, var Var, config VarConfig)
|
||||||
create_string_struct(typ ast.Type, name string, str string)
|
create_string_struct(typ ast.Type, name string, str string) i32
|
||||||
dec_var(var Var, config VarConfig)
|
dec_var(var Var, config VarConfig)
|
||||||
fn_decl(node ast.FnDecl)
|
fn_decl(node ast.FnDecl)
|
||||||
gen_asm_stmt(asm_node ast.AsmStmt)
|
gen_asm_stmt(asm_node ast.AsmStmt)
|
||||||
|
|
|
@ -16,6 +16,10 @@ fn test_string_len() {
|
||||||
println(d.len)
|
println(d.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Idx {
|
||||||
|
a string
|
||||||
|
}
|
||||||
|
|
||||||
fn test_string_index() {
|
fn test_string_index() {
|
||||||
a := '1234'
|
a := '1234'
|
||||||
assert a[0] == `1`
|
assert a[0] == `1`
|
||||||
|
@ -26,6 +30,10 @@ fn test_string_index() {
|
||||||
assert a[1] != `0`
|
assert a[1] != `0`
|
||||||
assert a[2] != `0`
|
assert a[2] != `0`
|
||||||
assert a[3] != `0`
|
assert a[3] != `0`
|
||||||
|
|
||||||
|
x := Idx{'abc'}
|
||||||
|
assert x.a[1] == `b`
|
||||||
|
assert x.a[2] != `b`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_for_i_in_len() {
|
fn test_for_i_in_len() {
|
||||||
|
|
|
@ -196,9 +196,45 @@ fn assign_fields() {
|
||||||
assert f.a == 2
|
assert f.a == 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Nest {
|
||||||
|
a string
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Nest2 {
|
||||||
|
a Nest
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Nest3 {
|
||||||
|
a Nest2
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Int {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NestMixed {
|
||||||
|
s string
|
||||||
|
b Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested_test() {
|
||||||
|
x := Nest{'abc'}
|
||||||
|
assert x.a[1] == `b`
|
||||||
|
|
||||||
|
x2 := Nest2{Nest{'def'}}
|
||||||
|
assert x2.a.a[2] == `f`
|
||||||
|
|
||||||
|
x3 := Nest3{Nest2{Nest{'ghi'}}}
|
||||||
|
assert x3.a.a.a[1] == `h`
|
||||||
|
|
||||||
|
x4 := NestMixed{'abc', Int{3}}
|
||||||
|
assert x4.b.a == 3
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
struct_test()
|
struct_test()
|
||||||
return_test()
|
return_test()
|
||||||
alias_test()
|
alias_test()
|
||||||
assign_fields()
|
assign_fields()
|
||||||
|
nested_test()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue