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) _memory_panic(@FN, n)
} }
mut res := &u8(unsafe { nil }) mut res := &u8(unsafe { nil })
$if prealloc { $if native {
res = unsafe { C.malloc(n) }
} $else $if prealloc {
return unsafe { prealloc_malloc(n) } return unsafe { prealloc_malloc(n) }
} $else $if gcboehm ? { } $else $if gcboehm ? {
$if gcboehm_opt ? { $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 // rax times b
fn (mut c Amd64) mul_reg_rax(b Amd64Register) { fn (mut c Amd64) mul_reg_rax(b Amd64Register) {
match b { match b {
@ -2510,8 +2514,42 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E
ast.ArrayInit { ast.ArrayInit {
match node.op { match node.op {
.decl_assign { .decl_assign {
c.g.allocate_by_type(name, right.typ) c.g.allocate_by_type(ident.name, ast.array_type)
c.init_array(ident, right) 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 { else {
c.g.n_error('${@LOCATION} Unexpected operator `${node.op}`') 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 // /!\ 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) { fn (mut c Amd64) apply_op_int(left_value Amd64Register, right_value Amd64Register, op token.Kind) {
match op { match op {
@ -3109,7 +3183,6 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
c.push(c.main_reg()) c.push(c.main_reg())
c.g.gen_left_value(left) c.g.gen_left_value(left)
c.mov_reg(Amd64Register.rbx, Amd64Register.rax) // effective address of the left expr 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.pop(.rcx) // value of right expr
c.gen_type_promotion(node.right_types[0], var_type) 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) c.mov_store(.rbx, .rcx, size)
} }
.boolean_and_assign { .boolean_and_assign {
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.bitand_reg(.rax, .rcx) c.bitand_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size) c.mov_store(.rbx, .rax, size)
} }
.boolean_or_assign { .boolean_or_assign {
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.bitor_reg(.rax, .rcx) c.bitor_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size) c.mov_store(.rbx, .rax, size)
} }
else { else {
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.apply_op_int(.rax, .rcx, node.op) c.apply_op_int(.rax, .rcx, node.op)
c.mov_store(.rbx, .rax, size) 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) { fn (mut c Arm64) patch_relative_jmp(pos i32, addr i64) {
panic('Arm64.patch_relative_jmp() not implemented') 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

@ -29,45 +29,53 @@ already compiling functions:
// false: whitelist function // false: whitelist function
// true: blacklist function // true: blacklist function
const blacklist = { const blacklist = {
'main.main': false 'main.main': false
'c_error_number_str': false 'c_error_number_str': false
'exit': false 'exit': false
'gc_is_enabled': false 'gc_is_enabled': false
'int_max': false 'int_max': false
'int_min': false 'int_min': false
'flush_stdout': false 'flush_stdout': false
'flush_stderr': false 'flush_stderr': false
'print_character': false 'print_character': false
'u8.is_alnum': false 'u8.is_alnum': false
'u8.is_bin_digit': false 'u8.is_bin_digit': false
'u8.is_capital': false 'u8.is_capital': false
'u8.is_digit': false 'u8.is_digit': false
'u8.is_hex_digit': false 'u8.is_hex_digit': false
'u8.is_letter': false 'u8.is_letter': false
'u8.is_oct_digit': false 'u8.is_oct_digit': false
'u8.is_space': false 'u8.is_space': false
'string.is_capital': false 'string.is_capital': false
'string.is_ascii': false 'string.is_ascii': false
'string.is_identifier': false 'string.is_identifier': false
'string.is_blank': false 'string.is_blank': false
'string.indent_width': false 'string.indent_width': false
'string.index_u8': false 'string.index_u8': false
'string.last_index': true 'string.last_index': true
'string.last_index_u8': false 'string.last_index_u8': false
'string.contains_u8': false 'string.contains_u8': false
'malloc_noscan': false 'malloc_noscan': false
'malloc': false 'malloc': false
'is_nil': false 'is_nil': false
'memdup': false 'memdup': false
'vcalloc': false 'vcalloc': false
'vmemcpy': false 'vmemcpy': false
'eprint': false 'eprint': false
'eprintln': false 'eprintln': false
'_write_buf_to_fd': false '_write_buf_to_fd': false
'_writeln_to_fd': false '_writeln_to_fd': false
'_memory_panic': false '_memory_panic': false
'panic': false 'panic': false
'vcurrent_hash': 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 = { const windows_blacklist = {

View file

@ -150,21 +150,11 @@ fn (mut g Gen) expr(node ast.Expr) {
g.gen_sizeof_expr(node) g.gen_sizeof_expr(node)
} }
ast.IndexExpr { ast.IndexExpr {
g.code_gen.gen_index_expr(node)
if node.left_type.is_string() { 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) 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 { } 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 { else {
@ -192,8 +182,11 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
ast.Enum { ast.Enum {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident) 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 { 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) { fn (mut g Gen) const_var_ident(ident ast.Ident, var ConstVar) {
if g.is_register_type(var.typ) { if g.is_register_type(var.typ) {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident) 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}') 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 { ast.ArrayInit {
g.expr(node) // TODO: add a test that uses this g.expr(node) // TODO: add a test that uses this
} }
ast.IndexExpr { // TODO ast.IndexExpr {
g.n_error('${@LOCATION} Unsupported IndexExpr left value') g.code_gen.gen_index_expr(node)
} }
ast.PrefixExpr { ast.PrefixExpr {
if node.op != .mul { if node.op != .mul {

View file

@ -114,6 +114,7 @@ mut:
gen_asm_stmt(asm_node ast.AsmStmt) gen_asm_stmt(asm_node ast.AsmStmt)
gen_cast_expr(expr ast.CastExpr) gen_cast_expr(expr ast.CastExpr)
gen_exit(expr ast.Expr) gen_exit(expr ast.Expr)
gen_index_expr(ast.IndexExpr)
gen_match_expr(expr ast.MatchExpr) gen_match_expr(expr ast.MatchExpr)
gen_print_reg(r Register, n i32, fd i32) gen_print_reg(r Register, n i32, fd i32)
gen_print(s string, fd i32) gen_print(s string, fd i32)
@ -139,6 +140,7 @@ mut:
mov(r Register, val i32) mov(r Register, val i32)
mov64(r Register, val Number) mov64(r Register, val Number)
movabs(reg Register, val i64) movabs(reg Register, val i64)
mul_reg_main(b Register)
patch_relative_jmp(pos i32, addr i64) patch_relative_jmp(pos i32, addr i64)
pop2(r Register) pop2(r Register)
prefix_expr(node ast.PrefixExpr) prefix_expr(node ast.PrefixExpr)
@ -891,7 +893,7 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 {
return 1 return 1
} }
ts := g.table.sym(typ) ts := g.table.sym(typ)
if ts.size != -1 { if ts.size != -1 && ts.size != 0 {
return i32(ts.size) return i32(ts.size)
} }
mut size := i32(0) 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 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 {} else {}
} }
mut ts_ := g.table.sym(typ) mut ts_ := g.table.sym(typ)

View file

@ -1,3 +1,13 @@
fn main() { fn main() {
assert [1, 2, 3] != [] 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_lt_gt()
test_ref_deref() test_ref_deref()
test_nil() test_nil()
index_expr_test()
println("ok") 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() { fn test_eq_ne() {
unsafe { unsafe {
mut a := voidptr(0) mut a := voidptr(0)

View file

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

View file

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