Skip to content

Commit

Permalink
native: cleanup assign, fix nested struct (#23778)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eliyaan authored Feb 21, 2025
1 parent b766900 commit 515d78d
Show file tree
Hide file tree
Showing 12 changed files with 524 additions and 274 deletions.
545 changes: 320 additions & 225 deletions vlib/v/gen/native/amd64.v

Large diffs are not rendered by default.

37 changes: 24 additions & 13 deletions vlib/v/gen/native/expr.v
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.local_var_ident(node, var)
}
else {
g.n_error('Unsupported variable kind')
g.n_error('${@LOCATION} Unsupported variable kind')
}
}
}
Expand Down Expand Up @@ -90,7 +90,7 @@ fn (mut g Gen) expr(node ast.Expr) {
for i, v in bytes {
val |= v << (i * 8)
if i >= sizeof(rune) {
g.n_error('runes are only 4 bytes wide')
g.n_error('${@LOCATION} runes are only 4 bytes wide')
}
}
g.code_gen.movabs(g.code_gen.main_reg(), i64(val))
Expand Down Expand Up @@ -129,7 +129,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.gen_sizeof_expr(node)
}
else {
g.n_error('expr: unhandled node type: ${node.type_name()}')
g.n_error('${@LOCATION} expr: unhandled node type: ${node.type_name()}')
}
}
}
Expand All @@ -151,7 +151,7 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
)
}
else {
g.n_error('Unsupported variable type')
g.n_error('${@LOCATION} Unsupported variable type')
}
}
}
Expand Down Expand Up @@ -273,7 +273,7 @@ fn (mut g Gen) gen_typeof_expr(node ast.TypeOf, newline bool) {

match ts.kind {
.sum_type {
g.n_error('`typeof()` is not implemented for sum types yet')
g.n_error('${@LOCATION} `typeof()` is not implemented for sum types yet')
}
.array_fixed {
fixed_info := ts.info as ast.ArrayFixed
Expand Down Expand Up @@ -427,10 +427,10 @@ fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
}
}
} else {
g.n_error('nothing to print')
g.n_error('${@LOCATION} nothing to print')
}
} else {
g.n_error('non-comptime conditionals are not implemented yet.')
g.n_error('${@LOCATION} non-comptime conditionals are not implemented yet.')
}
}
else {
Expand All @@ -445,11 +445,17 @@ fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
}

fn (mut g Gen) gen_selector_expr(expr ast.SelectorExpr) {
g.println('; .${expr.field_name} {')
main_reg := g.code_gen.main_reg()
g.expr(expr.expr)
offset := g.get_field_offset(expr.expr_type, expr.field_name)
g.code_gen.add(main_reg, offset)
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
if offset != 0 {
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)
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
}
g.println('; .${expr.field_name} {')
}

fn (mut g Gen) gen_left_value(node ast.Expr) {
Expand All @@ -465,18 +471,23 @@ fn (mut g Gen) gen_left_value(node ast.Expr) {
g.code_gen.add(Amd64Register.rax, offset)
}
}
ast.StructInit, ast.ArrayInit {
ast.StructInit {
g.expr(node)
}
ast.IndexExpr {} // TODO
ast.ArrayInit {
g.expr(node) // TODO: add a test that uses this
}
ast.IndexExpr { // TODO
g.n_error('${@LOCATION} Unsupported IndexExpr left value')
}
ast.PrefixExpr {
if node.op != .mul {
g.n_error('Unsupported left value')
g.n_error('${@LOCATION} Unsupported left value')
}
g.expr(node.right)
}
else {
g.n_error('Unsupported left value')
g.n_error('${@LOCATION} Unsupported left value')
}
}
}
40 changes: 22 additions & 18 deletions vlib/v/gen/native/gen.v
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ fn byt(n i32, s i32) u8 {
fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
mut obj := ident.obj
if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] {
obj = ident.scope.find(ident.name) or { g.n_error('unknown variable ${ident.name}') }
obj = ident.scope.find(ident.name) or {
g.n_error('${@LOCATION} unknown variable ${ident.name}')
}
}
match obj {
ast.Var {
Expand All @@ -277,7 +279,7 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
}
}
else {
g.n_error('unsupported variable type type:${obj} name:${ident.name}')
g.n_error('${@LOCATION} unsupported variable type type:${obj} name:${ident.name}')
}
}
}
Expand All @@ -291,7 +293,7 @@ fn (mut g Gen) get_type_from_var(var Var) ast.Type {
return var.typ
}
GlobalVar {
g.n_error('cannot get type from GlobalVar yet')
g.n_error('${@LOCATION} cannot get type from GlobalVar yet')
}
}
}
Expand Down Expand Up @@ -452,7 +454,7 @@ pub fn (mut g Gen) generate_header() {
}
}
else {
g.n_error('only `raw`, `linux`, `windows` and `macos` are supported for -os in -native')
g.n_error('${@LOCATION} only `raw`, `linux`, `windows` and `macos` are supported for -os in -native')
}
}
}
Expand Down Expand Up @@ -517,7 +519,7 @@ pub fn (mut g Gen) link(obj_name string) {
// TODO: implement linking for macos!
}
else {
g.n_error('native linking is not implemented for ${g.pref.os}')
g.n_error('${@LOCATION} native linking is not implemented for ${g.pref.os}')
}
}
}
Expand Down Expand Up @@ -681,15 +683,17 @@ fn (mut g Gen) try_var_offset(var_name string) i32 {
fn (mut g Gen) get_var_offset(var_name string) i32 {
r := g.try_var_offset(var_name)
if r == -1 {
g.n_error('unknown variable `${var_name}`')
g.n_error('${@LOCATION} unknown variable `${var_name}`')
}
return r
}

fn (mut g Gen) get_field_offset(in_type ast.Type, name string) i32 {
typ := g.unwrap(in_type)
ts := g.table.sym(typ)
field := ts.find_field(name) or { g.n_error('Could not find field `${name}` on init') }
field := ts.find_field(name) or {
g.n_error('${@LOCATION} Could not find field `${name}` on init')
}
return g.structs[typ.idx()].offsets[field.i]
}

Expand Down Expand Up @@ -724,7 +728,7 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 {
ast.float_literal_type_idx { 8 }
ast.char_type_idx { 1 }
ast.rune_type_idx { 4 }
else { g.n_error('unknown type size ${typ}') }
else { g.n_error('${@LOCATION} unknown type size ${typ}') }
}
}
if typ.is_bool() {
Expand Down Expand Up @@ -835,7 +839,7 @@ fn (mut g Gen) get_sizeof_ident(ident ast.Ident) i32 {
return g.get_type_size(typ)
}
size := g.var_alloc_size[ident.name] or {
g.n_error('unknown variable `${ident}`')
g.n_error('${@LOCATION} unknown variable `${ident}`')
return 0
}
return size
Expand Down Expand Up @@ -911,7 +915,7 @@ fn (mut g Gen) eval_escape_codes(str string) string {
`u` {
i++
utf8 := strconv.parse_int(str[i..i + 4], 16, 16) or {
g.n_error('invalid \\u escape code (${str[i..i + 4]})')
g.n_error('${@LOCATION} invalid \\u escape code (${str[i..i + 4]})')
0
}
i += 4
Expand All @@ -925,22 +929,22 @@ fn (mut g Gen) eval_escape_codes(str string) string {
`x` {
i++
c := strconv.parse_int(str[i..i + 2], 16, 8) or {
g.n_error('invalid \\x escape code (${str[i..i + 2]})')
g.n_error('${@LOCATION} invalid \\x escape code (${str[i..i + 2]})')
0
}
i += 2
buffer << u8(c)
}
`0`...`7` {
c := strconv.parse_int(str[i..i + 3], 8, 8) or {
g.n_error('invalid escape code \\${str[i..i + 3]}')
g.n_error('${@LOCATION} invalid escape code \\${str[i..i + 3]}')
0
}
i += 3
buffer << u8(c)
}
else {
g.n_error('invalid escape code \\${str[i]}')
g.n_error('${@LOCATION} invalid escape code \\${str[i]}')
}
}
}
Expand Down Expand Up @@ -973,7 +977,7 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) {
g.code_gen.mov_reg(g.code_gen.main_reg(), reg)
}
} else {
g.n_error('int-to-string conversion not implemented for type ${typ}')
g.n_error('${@LOCATION} int-to-string conversion not implemented for type ${typ}')
}
g.println('; to_string }')
}
Expand All @@ -986,7 +990,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va
g.code_gen.convert_rune_to_string(reg, buffer, var, config)
} else if typ.is_int() {
if typ.is_unsigned() {
g.n_error('Unsigned integer print is not supported')
g.n_error('${@LOCATION} Unsigned integer print is not supported')
} else {
buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough
end_of_buffer := buffer + 4 + 32 - 1 // 4 bytes for the size and 32 for the chars, -1 to not go out of array
Expand All @@ -1001,7 +1005,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va
} else if typ.is_string() {
g.code_gen.mov_var_to_reg(reg, var, config)
} else {
g.n_error('int-to-string conversion not implemented for type ${typ}')
g.n_error('${@LOCATION} int-to-string conversion not implemented for type ${typ}')
}
g.println('; var_to_string }')
}
Expand All @@ -1019,7 +1023,7 @@ fn (mut g Gen) patch_calls() {
for c in g.callpatches {
addr := g.fn_addr[c.name]
if addr == 0 {
g.n_error('fn addr of `${c.name}` = 0')
g.n_error('${@LOCATION} fn addr of `${c.name}` = 0')
return
}
last := i32(g.buf.len)
Expand All @@ -1038,7 +1042,7 @@ fn (mut g Gen) patch_labels() {
for label in g.labels.patches {
addr := g.labels.addrs[label.id]
if addr == 0 {
g.n_error('label addr = 0')
g.n_error('${@LOCATION} label addr = 0')
return
}

Expand Down
30 changes: 20 additions & 10 deletions vlib/v/gen/native/stmt.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
fn (mut g Gen) stmt(node ast.Stmt) {
match node {
ast.AssignStmt {
g.code_gen.assign_stmt(node)
g.assign_stmt(node)
}
ast.Block {
g.stmts(node.stmts)
}
ast.BranchStmt {
label_name := node.label
// break / continue statements in for loops
for i := g.labels.branches.len - 1; i >= 0; i-- {
branch := g.labels.branches[i]
if label_name == '' || label_name == branch.name {
Expand Down Expand Up @@ -110,11 +111,15 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.TypeDecl {}
ast.InterfaceDecl {}
else {
g.n_error('native.stmt(): bad node: ' + node.type_name())
g.n_error('${@LOCATION} bad node: ' + node.type_name())
}
}
}

fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
g.code_gen.assign_stmt(node)
}

fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
if node.has_init {
g.stmts([node.init])
Expand Down Expand Up @@ -144,12 +149,12 @@ fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
jump_addr = g.code_gen.cjmp(.jg)
}
else {
g.n_error('unsupported conditional in for-c loop')
g.n_error('${@LOCATION} unsupported conditional in for-c loop')
}
}
}
else {
g.n_error('unhandled infix.left')
g.n_error('${@LOCATION} unhandled infix.left')
}
}
}
Expand Down Expand Up @@ -245,6 +250,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
if node.is_range {
g.println('; for ${node.val_var} in range {')
// for a in node.cond .. node.high {

i := g.code_gen.allocate_var(node.val_var, 8, 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
Expand All @@ -253,7 +259,6 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
g.code_gen.mov_reg_to_var(LocalVar{i, ast.i64_type_idx, node.val_var}, main_reg) // i = node.cond // initial value

start := g.pos() // label-begin:
start_label := g.labels.new_label()

g.println('; check iterator against upper loop bound')
g.code_gen.mov_var_to_reg(main_reg, LocalVar{i, ast.i64_type_idx, node.val_var})
Expand All @@ -267,18 +272,22 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
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()
g.println('; label ${start_label} (start_label)')

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, node.val_var})
g.labels.branches.pop()
g.code_gen.jmp_back(start) // loops

g.labels.addrs[end_label] = g.pos()
g.println('; label ${end_label} (end_label)')
g.println('; for ${node.val_var} in range }')
Expand All @@ -292,11 +301,12 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
} else if it.kind == .map {
*/
} else {
g.n_error('for-in ${node.kind} statement is not yet implemented')
g.n_error('${@LOCATION} for-in ${node.kind} statement is not yet implemented')
}
}

fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) {
g.println('; gen_assert {')
mut cjmp_addr := i32(0)
ane := assert_node.expr
label := g.labels.new_label()
Expand All @@ -306,10 +316,10 @@ fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) {
pos: cjmp_addr
}
g.println('; jump to label ${label}')
g.expr(assert_node.expr)
g.code_gen.trap()
g.labels.addrs[label] = g.pos()
g.println('; label ${label}')
g.println('; gen_assert }')
}

fn (mut g Gen) gen_flag_hash_stmt(node ast.HashStmt) {
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/native/tests/arrays.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
assert [1, 2, 3] != []
}
Empty file.
Loading

0 comments on commit 515d78d

Please sign in to comment.