This commit is contained in:
Eliyaan (Nopana) 2025-09-13 10:24:21 +00:00 committed by GitHub
commit 374c6ab467
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 213 additions and 60 deletions

View file

@ -486,7 +486,9 @@ pub fn malloc_noscan(n isize) &u8 {
_memory_panic(@FN, n)
}
mut res := &u8(unsafe { nil })
$if prealloc {
$if native {
res = unsafe { C.malloc(n) }
} $else $if prealloc {
return unsafe { prealloc_malloc(n) }
} $else $if gcboehm ? {
$if gcboehm_opt ? {

View file

@ -1798,6 +1798,10 @@ fn (mut c Amd64) mov(r Register, val i32) {
}
}
fn (mut c Amd64) mul_reg_main(b Register) {
c.mul_reg_rax(b as Amd64Register)
}
// rax times b
fn (mut c Amd64) mul_reg_rax(b Amd64Register) {
match b {
@ -2510,8 +2514,42 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E
ast.ArrayInit {
match node.op {
.decl_assign {
c.g.allocate_by_type(name, right.typ)
c.init_array(ident, right)
c.g.allocate_by_type(ident.name, ast.array_type)
len := ast.CallArg{
expr: if right.has_len {
right.len_expr
} else {
ast.IntegerLiteral{'0', right.pos}
}
typ: ast.int_type
pos: right.pos
}
cap := ast.CallArg{
expr: if right.has_cap {
right.cap_expr
} else {
ast.IntegerLiteral{'0', right.pos}
}
typ: ast.int_type
pos: right.pos
}
size := ast.CallArg{
expr: ast.IntegerLiteral{c.g.get_type_size(right.elem_type).str(), right.pos}
typ: ast.int_type
pos: right.pos
}
c.call_fn(ast.CallExpr{
pos: right.pos
name: '__new_array'
args: [len, cap, size]
expected_arg_types: [ast.int_type, ast.int_type, ast.int_type]
language: .v
return_type: ast.array_type
nr_ret_values: 1
is_return_used: true
})
c.lea_var_to_reg(Amd64Register.rdx, c.g.get_var_offset(ident.name))
c.move_struct(.rax, .rdx, c.g.get_type_size(ast.array_type))
}
else {
c.g.n_error('${@LOCATION} Unexpected operator `${node.op}`')
@ -2673,6 +2711,42 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E
}*/
}
fn (mut c Amd64) gen_index_expr(node ast.IndexExpr) {
if node.left_type.is_string() {
c.g.expr(node.index)
c.push(Amd64Register.rax)
c.g.expr(node.left) // load address of string struct
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u64_type_idx) // load value of the str pointer
c.pop2(Amd64Register.rdx) // index
c.add_reg2(Amd64Register.rax, Amd64Register.rdx) // add the offset to the address
} else if node.left_type.is_any_kind_of_pointer() {
// load the pointer
c.g.expr(node.left)
c.mov_reg(Amd64Register.rcx, Amd64Register.rax)
// add the index times the size (bytes) of the type
c.g.expr(node.index)
c.mov(Amd64Register.rbx, i32(c.g.get_type_size(node.typ)))
c.mul_reg_main(Amd64Register.rbx)
c.add_reg2(Amd64Register.rax, Amd64Register.rcx)
} else if node.is_array {
c.g.expr(node.left)
offset := c.g.get_field_offset(ast.array_type, 'data')
if offset != 0 {
c.add(Amd64Register.rax, offset)
}
c.mov_reg(Amd64Register.rcx, Amd64Register.rax)
// add the index times the size (bytes) of the type
c.g.expr(node.index)
c.mov(Amd64Register.rbx, i32(c.g.get_type_size(node.typ)))
c.mul_reg_main(Amd64Register.rbx)
c.add_reg2(Amd64Register.rax, Amd64Register.rcx)
} else {
c.g.n_error('${@LOCATION} index expr: unhandled node type {node}')
}
}
// /!\ for div, mul, mod the left value should always be .rax
fn (mut c Amd64) apply_op_int(left_value Amd64Register, right_value Amd64Register, op token.Kind) {
match op {
@ -3109,7 +3183,6 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
c.push(c.main_reg())
c.g.gen_left_value(left)
c.mov_reg(Amd64Register.rbx, Amd64Register.rax) // effective address of the left expr
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.pop(.rcx) // value of right expr
c.gen_type_promotion(node.right_types[0], var_type)
@ -3124,14 +3197,17 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
c.mov_store(.rbx, .rcx, size)
}
.boolean_and_assign {
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.bitand_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.boolean_or_assign {
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.bitor_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
else {
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.apply_op_int(.rax, .rcx, node.op)
c.mov_store(.rbx, .rax, size)
}

View file

@ -554,3 +554,11 @@ fn (mut c Arm64) mov_deref(reg Register, regptr Register, typ ast.Type) {
fn (mut c Arm64) patch_relative_jmp(pos i32, addr i64) {
panic('Arm64.patch_relative_jmp() not implemented')
}
fn (mut c Arm64) mul_reg_main(b Register) {
panic('Arm64.mul_reg_main() not implemented')
}
fn (mut c Arm64) gen_index_expr(node ast.IndexExpr) {
panic('Arm64.gen_index_expr{) not implemented')
}

View file

@ -68,6 +68,14 @@ const blacklist = {
'_memory_panic': false
'panic': false
'vcurrent_hash': false
'__new_array': false
'panic_on_negative_len': false
'panic_on_negative_cap': false
'panic_n': false
'impl_i64_to_string': false
'vmemmove': false
'tos': false
'strings.new_builder': true
}
const windows_blacklist = {

View file

@ -150,21 +150,11 @@ fn (mut g Gen) expr(node ast.Expr) {
g.gen_sizeof_expr(node)
}
ast.IndexExpr {
g.code_gen.gen_index_expr(node)
if node.left_type.is_string() {
g.expr(node.index)
g.code_gen.push(Amd64Register.rax)
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() {
dump(node)
g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string')
} else {
g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string')
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, node.typ)
}
}
else {
@ -192,8 +182,11 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
ast.Enum {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident)
}
ast.Array {
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(ident.name))
}
else {
g.n_error('${@LOCATION} Unsupported variable type')
g.n_error('${@LOCATION} Unsupported variable type ${ts.info}')
}
}
}
@ -210,8 +203,18 @@ fn (mut g Gen) global_var_ident(ident ast.Ident, var GlobalVar) {
fn (mut g Gen) const_var_ident(ident ast.Ident, var ConstVar) {
if g.is_register_type(var.typ) {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident)
} else {
} else if g.is_fp_type(var.typ) {
g.n_error('${@LOCATION} Unsupported variable type ${ident} ${var}')
} else {
ts := g.table.sym(g.unwrap(var.typ))
match ts.info {
ast.Struct {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident)
}
else {
g.n_error('${@LOCATION} Unsupported variable type ${ident} ${var} ${ts.info}')
}
}
}
}
@ -556,8 +559,8 @@ fn (mut g Gen) gen_left_value(node ast.Expr) {
ast.ArrayInit {
g.expr(node) // TODO: add a test that uses this
}
ast.IndexExpr { // TODO
g.n_error('${@LOCATION} Unsupported IndexExpr left value')
ast.IndexExpr {
g.code_gen.gen_index_expr(node)
}
ast.PrefixExpr {
if node.op != .mul {

View file

@ -114,6 +114,7 @@ mut:
gen_asm_stmt(asm_node ast.AsmStmt)
gen_cast_expr(expr ast.CastExpr)
gen_exit(expr ast.Expr)
gen_index_expr(ast.IndexExpr)
gen_match_expr(expr ast.MatchExpr)
gen_print_reg(r Register, n i32, fd i32)
gen_print(s string, fd i32)
@ -139,6 +140,7 @@ mut:
mov(r Register, val i32)
mov64(r Register, val Number)
movabs(reg Register, val i64)
mul_reg_main(b Register)
patch_relative_jmp(pos i32, addr i64)
pop2(r Register)
prefix_expr(node ast.PrefixExpr)
@ -891,7 +893,7 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 {
return 1
}
ts := g.table.sym(typ)
if ts.size != -1 {
if ts.size != -1 && ts.size != 0 {
return i32(ts.size)
}
mut size := i32(0)
@ -929,6 +931,22 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 {
}
g.structs[typ.idx()] = strc
}
ast.Array {
// TODO: replace u32 by the enum ArrayFlags size
for f_typ in [ast.voidptr_type, ast.int_type, ast.int_type, ast.int_type, ast.u32_type,
ast.int_type] {
f_size := g.get_type_size(f_typ)
f_align := g.get_type_align(f_typ)
padding := (f_align - size % f_align) % f_align
strc.offsets << size + padding
size += f_size + padding
if f_align > align {
align = f_align
}
}
size = (size + align - 1) / align * align
g.structs[typ.idx()] = strc
}
else {}
}
mut ts_ := g.table.sym(typ)

View file

@ -1,3 +1,13 @@
fn main() {
assert [1, 2, 3] != []
mut my_array := []int{len:3}
my_array[0] = 4
my_array[1] = 5
my_array[2] = 6
println(my_array[0])
println(my_array[1])
println(my_array[2])
assert my_array[0] == 4
assert my_array[1] == 5
assert my_array[2] == 6
}

View file

@ -0,0 +1,3 @@
4
5
6

View file

@ -3,9 +3,25 @@ fn main() {
test_lt_gt()
test_ref_deref()
test_nil()
index_expr_test()
println("ok")
}
fn index_expr_test() {
mut buf := C.malloc(2)
unsafe {
buf[0] = 1
buf[1] = 2
assert buf[0] == 1
assert buf[1] == 2
buf = malloc_noscan(2)
buf[0] = 3
buf[1] = 4
assert buf[0] == 3
assert buf[1] == 4
}
}
fn test_eq_ne() {
unsafe {
mut a := voidptr(0)

View file

@ -85,6 +85,13 @@ fn test_runes() {
println(`\xe2\x98\x85`)
}
const a = 'my string'
fn const_test() {
b := a
println(b)
}
fn main() {
test_unicode_characters()
test_string_len()
@ -93,4 +100,5 @@ fn main() {
test_escape_codes()
test_raw_string()
test_runes()
const_test()
}

View file

@ -23,3 +23,4 @@ V
😀
🚀
★★★★
my string