native: initial support for typeof() expressions (#13730)
parent
a8f6574471
commit
a1d0db792e
|
@ -641,6 +641,31 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) {
|
|||
g.trap() // should never be reached, just in case
|
||||
}
|
||||
|
||||
fn (mut g Gen) relpc(dst Register, src Register) {
|
||||
// 488d1d 00000000 lea 0(%rip),%dst
|
||||
// 4801d8 add %dst, %src
|
||||
match dst {
|
||||
.rax {
|
||||
match src {
|
||||
.rsi {
|
||||
g.write([byte(0x48), 0x8d, 0x35, 0x00, 0x00, 0x00, 0x00]) // lea rsi, rip
|
||||
g.write([byte(0x48), 0x01, 0xf0]) // add rax, rsi
|
||||
}
|
||||
.rbx {
|
||||
g.write([byte(0x48), 0x8d, 0x1d, 0x00, 0x00, 0x00, 0x00])
|
||||
g.write([byte(0x48), 0x01, 0xd8])
|
||||
}
|
||||
else {
|
||||
panic('relpc requires .rax, {.rsi,.rbx}')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
panic('relpc requires .rax, {.rsi,.rbx}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) learel(reg Register, val int) {
|
||||
g.write8(0x48)
|
||||
g.write8(0x8d)
|
||||
|
@ -848,7 +873,9 @@ fn (mut g Gen) add_reg(a Register, b Register) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) mov_reg(a Register, b Register) {
|
||||
if a == .rbp && b == .rsp {
|
||||
if a == .rax && b == .rsi {
|
||||
g.write([byte(0x48), 0x89, 0xf0])
|
||||
} else if a == .rbp && b == .rsp {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
} else if a == .rdx && b == .rax {
|
||||
|
@ -1024,26 +1051,26 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
/*
|
||||
ast.int_type_idx {
|
||||
g.expr(node.left[i])
|
||||
match node.left[i] {
|
||||
ast.IndexExpr {
|
||||
ie := node.left[i] as ast.IndexExpr
|
||||
bracket := name.index('[') or {
|
||||
g.v_error('bracket expected', node.pos)
|
||||
exit(1)
|
||||
match node.left[i] {
|
||||
ast.IndexExpr {
|
||||
ie := node.left[i] as ast.IndexExpr
|
||||
bracket := name.index('[') or {
|
||||
g.v_error('bracket expected', node.pos)
|
||||
exit(1)
|
||||
}
|
||||
var_name := name[0 .. bracket]
|
||||
mut dest := g.get_var_offset(var_name)
|
||||
index := ie.index as ast.IntegerLiteral
|
||||
dest += index.val.int() * 8
|
||||
// TODO check if out of bounds access
|
||||
g.mov(.rax, right.val.int())
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
// eprintln('${var_name}[$index] = ${right.val.int()}')
|
||||
} else {
|
||||
dump(node)
|
||||
g.v_error('oops', node.pos)
|
||||
}
|
||||
}
|
||||
var_name := name[0 .. bracket]
|
||||
mut dest := g.get_var_offset(var_name)
|
||||
index := ie.index as ast.IntegerLiteral
|
||||
dest += index.val.int() * 8
|
||||
// TODO check if out of bounds access
|
||||
g.mov(.rax, right.val.int())
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
// eprintln('${var_name}[$index] = ${right.val.int()}')
|
||||
} else {
|
||||
dump(node)
|
||||
g.v_error('oops', node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
else {
|
||||
|
@ -1130,6 +1157,7 @@ g.v_error('oops', node.pos)
|
|||
pos += 8
|
||||
}
|
||||
ast.StringLiteral {
|
||||
// TODO: use learel
|
||||
g.mov64(.rsi, g.allocate_string('$e.val', 2, .abs64)) // for rsi its 2
|
||||
g.mov_reg_to_var(pos, .rsi)
|
||||
pos += 8
|
||||
|
@ -1169,7 +1197,7 @@ g.v_error('oops', node.pos)
|
|||
ast.StringLiteral {
|
||||
dest := g.allocate_var(name, 4, 0)
|
||||
ie := node.right[i] as ast.StringLiteral
|
||||
g.mov64(.rsi, g.allocate_string(ie.str(), 2, .abs64)) // for rsi its 2
|
||||
g.learel(.rsi, g.allocate_string(ie.val.str(), 3, .rel32))
|
||||
g.mov_reg_to_var(dest, .rsi)
|
||||
}
|
||||
ast.CallExpr {
|
||||
|
@ -1178,6 +1206,9 @@ g.v_error('oops', node.pos)
|
|||
g.mov_reg_to_var(dest, .rax)
|
||||
g.mov_var_to_reg(.rsi, dest)
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
g.v_error('unhandled selectors', node.pos)
|
||||
}
|
||||
ast.GoExpr {
|
||||
g.v_error('threads not implemented for the native backend', node.pos)
|
||||
}
|
||||
|
@ -1195,6 +1226,14 @@ g.v_error('oops', node.pos)
|
|||
}
|
||||
}
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
g.v_error('floating point arithmetic not yet implemented for the native backend',
|
||||
node.pos)
|
||||
}
|
||||
ast.TypeOf {
|
||||
g.gen_typeof_expr(node.right[i] as ast.TypeOf, true)
|
||||
g.mov_reg(.rsi, .rax)
|
||||
}
|
||||
else {
|
||||
// dump(node)
|
||||
g.v_error('unhandled assign_stmt expression: $right.type_name()', right.pos())
|
||||
|
@ -1286,9 +1325,11 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) {
|
|||
}
|
||||
ast.AsmDisp {
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
}
|
||||
*/
|
||||
ast.FloatLiteral {
|
||||
g.v_error('floating point arithmetic is not yet implemented for the native backend',
|
||||
asm_node.pos)
|
||||
}
|
||||
string {
|
||||
// XXX
|
||||
g.v_error('no strings allowed in this context', asm_node.pos)
|
||||
|
@ -1630,6 +1671,6 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
|
|||
// Generate the value assigned to the variable
|
||||
g.write32(initial_val)
|
||||
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
||||
g.println('mov [rbp-$n.hex2()], $initial_val (Allocate var `$name`)')
|
||||
g.println('mov [rbp-$n.hex2()], $initial_val ; Allocate var `$name`')
|
||||
return g.stack_var_pos
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ pub fn (mut g Gen) create_executable() {
|
|||
os.write_file_array(g.out_name, g.buf) or { panic(err) }
|
||||
os.chmod(g.out_name, 0o775) or { panic(err) } // make it executable
|
||||
if g.pref.is_verbose {
|
||||
println('\n$g.out_name: native binary has been successfully generated')
|
||||
eprintln('\n$g.out_name: native binary has been successfully generated')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,14 +277,28 @@ fn (mut g Gen) write_string_with_padding(s string, max int) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) get_var_offset(var_name string) int {
|
||||
offset := g.var_offset[var_name]
|
||||
fn (mut g Gen) try_var_offset(var_name string) int {
|
||||
offset := g.var_offset[var_name] or { return -1 }
|
||||
if offset == 0 {
|
||||
g.n_error('unknown variable `$var_name`')
|
||||
return -1
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
fn (mut g Gen) get_var_offset(var_name string) int {
|
||||
r := g.try_var_offset(var_name)
|
||||
if r == -1 {
|
||||
g.n_error('unknown variable `$var_name`')
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
|
||||
nl := if newline { '\n' } else { '' }
|
||||
r := g.typ(it.expr_type).name
|
||||
g.learel(.rax, g.allocate_string('$r$nl', 3, .rel32))
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) {
|
||||
newline := name in ['println', 'eprintln']
|
||||
fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 }
|
||||
|
@ -301,13 +315,17 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) {
|
|||
g.gen_print_reg(.rax, 3, fd)
|
||||
}
|
||||
ast.Ident {
|
||||
g.n_error('Printing idents is not yet supported in the native backend')
|
||||
/*
|
||||
vo := g.get_var_offset(expr.name)
|
||||
g.mov_var_to_reg(.rax, vo)
|
||||
//g.expr(expr)
|
||||
vo := g.try_var_offset(expr.name)
|
||||
if vo != -1 {
|
||||
g.n_error('Printing idents is not yet supported in the native backend')
|
||||
// g.mov_var_to_reg(.rsi, vo)
|
||||
// g.mov_reg(.rax, .rsi)
|
||||
// g.learel(.rax, vo * 8)
|
||||
// g.relpc(.rax, .rsi)
|
||||
// g.learel(.rax, g.allocate_string('$vo\n', 3, .rel32))
|
||||
// g.expr(expr)
|
||||
}
|
||||
g.gen_print_reg(.rax, 3, fd)
|
||||
*/
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.learel(.rax, g.allocate_string('$expr.val\n', 3, .rel32))
|
||||
|
@ -394,8 +412,10 @@ g.expr
|
|||
ast.SelectExpr {}
|
||||
ast.SqlExpr {}
|
||||
ast.TypeNode {}
|
||||
ast.TypeOf {}
|
||||
*/
|
||||
ast.TypeOf {
|
||||
g.gen_typeof_expr(expr, newline)
|
||||
}
|
||||
ast.LockExpr {
|
||||
// passthru
|
||||
eprintln('Warning: locks not implemented yet in the native backend')
|
||||
|
@ -728,7 +748,10 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
}
|
||||
ast.FloatLiteral {}
|
||||
ast.Ident {
|
||||
offset := g.get_var_offset(node.obj.name) // i := 0
|
||||
offset := g.try_var_offset(node.obj.name) // i := 0
|
||||
if offset == -1 {
|
||||
g.n_error('invalid ident $node.obj.name')
|
||||
}
|
||||
// offset := g.get_var_offset(node.name)
|
||||
// XXX this is intel specific
|
||||
g.mov_var_to_reg(.rax, offset)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
fn main() {
|
||||
a := 'string'
|
||||
t := typeof(a)
|
||||
println(t)
|
||||
t2 := typeof('another string')
|
||||
println(t2)
|
||||
n := 123
|
||||
t3 := typeof(n)
|
||||
println(t3)
|
||||
t4 := typeof(123)
|
||||
println(t4)
|
||||
// id := 'hello world'
|
||||
// println(id)
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
string
|
||||
string
|
||||
int
|
||||
int literal
|
Loading…
Reference in New Issue