1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00
v/vlib/v/gen/native/expr.v

348 lines
8.2 KiB
V

// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module native
import v.ast
fn (mut g Gen) expr(node ast.Expr) {
match node {
ast.ParExpr {
g.expr(node.expr)
}
ast.ArrayInit {
pos := g.allocate_array('_anonarray', 8, node.exprs.len)
g.code_gen.init_array(LocalVar{ offset: pos, typ: node.typ }, node)
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
}
ast.BoolLiteral {
g.code_gen.mov64(g.code_gen.main_reg(), if node.val {
1
} else {
0
})
}
ast.CallExpr {
if node.name == 'C.syscall' {
g.code_gen.gen_syscall(node)
} else if node.name == 'exit' {
g.code_gen.gen_exit(node.args[0].expr)
} else if node.name in ['println', 'print', 'eprintln', 'eprint'] {
expr := node.args[0].expr
typ := node.args[0].typ
g.gen_print_from_expr(expr, typ, node.name)
} else {
g.code_gen.call_fn(node)
}
}
ast.FloatLiteral {
val := g.eval.expr(node, ast.float_literal_type_idx).float_val()
g.code_gen.load_fp(val)
}
ast.Ident {
var := g.get_var_from_ident(node)
// XXX this is intel specific
match var {
LocalVar {
if g.is_register_type(var.typ) {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), node as ast.Ident)
} else if var.typ.is_pure_float() {
g.code_gen.load_fp_var(node as ast.Ident)
} else {
ts := g.table.sym(var.typ)
match ts.info {
ast.Struct {
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(node.name))
}
ast.Enum {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), node as ast.Ident,
typ: ast.int_type_idx
)
}
else {
g.n_error('Unsupported variable type')
}
}
}
}
else {
g.n_error('Unsupported variable kind')
}
}
}
ast.IfExpr {
g.if_expr(node)
}
ast.InfixExpr {
g.code_gen.infix_expr(node)
}
ast.IntegerLiteral {
g.code_gen.mov64(g.code_gen.main_reg(), i64(node.val.u64()))
}
ast.Nil {
g.code_gen.mov64(g.code_gen.main_reg(), 0)
}
ast.PostfixExpr {
g.postfix_expr(node)
}
ast.PrefixExpr {
g.code_gen.prefix_expr(node)
}
ast.StringLiteral {
str := g.eval_str_lit_escape_codes(node)
g.allocate_string(str, 3, .rel32)
}
ast.CharLiteral {
bytes := g.eval_escape_codes(node.val)
.bytes()
mut val := rune(0)
for i, v in bytes {
val |= v << (i * 8)
if i >= sizeof(rune) {
g.n_error('runes are only 4 bytes wide')
}
}
g.code_gen.movabs(g.code_gen.main_reg(), i64(val))
}
ast.StructInit {
pos := g.allocate_by_type('_anonstruct', node.typ)
g.code_gen.init_struct(LocalVar{ offset: pos, typ: node.typ }, node)
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
}
ast.GoExpr {
g.v_error('native backend doesnt support threads yet', node.pos)
}
ast.MatchExpr {
g.code_gen.gen_match_expr(node)
}
ast.SelectorExpr {
g.code_gen.gen_selector_expr(node)
}
ast.CastExpr {
g.code_gen.gen_cast_expr(node)
}
ast.EnumVal {
type_name := g.table.get_type_name(node.typ)
g.code_gen.mov(g.code_gen.main_reg(), g.enum_vals[type_name].fields[node.val])
}
ast.UnsafeExpr {
g.expr(node.expr)
}
ast.ConcatExpr {
g.code_gen.gen_concat_expr(node)
}
else {
g.n_error('expr: unhandled node type: ${node.type_name()}')
}
}
}
fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
g.expr(expr)
g.code_gen.cmp_zero(g.code_gen.main_reg())
return g.code_gen.cjmp(if neg { .jne } else { .je })
}
fn (mut g Gen) if_expr(node ast.IfExpr) {
if node.is_comptime {
if stmts := g.comptime_conditional(node) {
g.stmts(stmts)
}
return
}
if node.branches.len == 0 {
return
}
mut endif_label := 0
has_endif := node.branches.len > 1
if has_endif {
endif_label = g.labels.new_label()
}
for idx in 0 .. node.branches.len {
branch := node.branches[idx]
if idx == node.branches.len - 1 && node.has_else {
g.stmts(branch.stmts)
} else {
if branch.cond is ast.BoolLiteral {
if branch.cond.val {
g.stmts(branch.stmts)
}
continue
}
expr := branch.cond
label := g.labels.new_label()
cjmp_addr := g.condition(expr, false)
g.labels.patches << LabelPatch{
id: label
pos: cjmp_addr
}
g.println('; jump to label ${label}')
g.stmts(branch.stmts)
if has_endif {
jump_addr := g.code_gen.jmp(0)
g.labels.patches << LabelPatch{
id: endif_label
pos: jump_addr
}
g.println('; jump to label ${endif_label}')
}
// println('after if g.pos=$g.pos() jneaddr=$cjmp_addr')
g.labels.addrs[label] = g.pos()
g.println('; label ${label}')
}
}
if has_endif {
g.labels.addrs[endif_label] = g.pos()
g.println('; label ${endif_label}')
}
}
fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
if node.expr !is ast.Ident {
return
}
ident := node.expr as ast.Ident
match node.op {
.inc {
g.code_gen.inc_var(ident)
}
.dec {
g.code_gen.dec_var(ident)
}
else {}
}
}
fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
nl := if newline { '\n' } else { '' }
r := g.typ(it.typ).name
g.code_gen.learel(g.code_gen.main_reg(), g.allocate_string('${r}${nl}', 3, .rel32))
}
fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
newline := name in ['println', 'eprintln']
fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 }
match expr {
ast.StringLiteral {
str := g.eval_str_lit_escape_codes(expr)
if newline {
g.code_gen.gen_print(str + '\n', fd)
} else {
g.code_gen.gen_print(str, fd)
}
}
ast.Nil {
str := '0x0'
if newline {
g.code_gen.gen_print(str + '\n', fd)
} else {
g.code_gen.gen_print(str, fd)
}
}
ast.CharLiteral {
str := g.eval_escape_codes(expr.val)
if newline {
g.code_gen.gen_print(str + '\n', fd)
} else {
g.code_gen.gen_print(str, fd)
}
}
ast.Ident {
vo := g.try_var_offset(expr.name)
reg := g.code_gen.main_reg()
if vo != -1 {
g.gen_var_to_string(reg, expr, expr as ast.Ident)
g.code_gen.gen_print_reg(reg, -1, fd)
if newline {
g.code_gen.gen_print('\n', fd)
}
} else {
g.code_gen.gen_print_reg(reg, -1, fd)
}
}
ast.IntegerLiteral {
if newline {
g.code_gen.gen_print('${expr.val}\n', fd)
} else {
g.code_gen.gen_print('${expr.val}', fd)
}
}
ast.BoolLiteral {
// register 'true' and 'false' strings // g.expr(expr)
// XXX mov64 shuoldnt be used for addressing
nl := if newline { '\n' } else { '' }
if expr.val {
g.code_gen.gen_print('true' + nl, fd)
} else {
g.code_gen.gen_print('false' + nl, fd)
}
}
ast.SizeOf {
size := g.get_type_size(expr.typ)
if newline {
g.code_gen.gen_print('${size}\n', fd)
} else {
g.code_gen.gen_print('${size}', fd)
}
}
ast.OffsetOf {
styp := g.typ(expr.struct_type)
field_name := expr.field
if styp.kind == .struct_ {
off := g.get_field_offset(expr.struct_type, field_name)
if newline {
g.code_gen.gen_print('${off}\n', fd)
} else {
g.code_gen.gen_print('${off}', fd)
}
} else {
g.v_error('_offsetof expects a struct Type as first argument', expr.pos)
}
}
ast.None {
if newline {
g.code_gen.gen_print('<none>\n', fd)
} else {
g.code_gen.gen_print('<none>', fd)
}
}
ast.AtExpr {
if newline {
g.code_gen.gen_print(g.comptime_at(expr) + '\n', fd)
} else {
g.code_gen.gen_print(g.comptime_at(expr), fd)
}
}
ast.StringInterLiteral {
g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos)
}
ast.IfExpr {
if expr.is_comptime {
if stmts := g.comptime_conditional(expr) {
for i, stmt in stmts {
if i + 1 == stmts.len && stmt is ast.ExprStmt {
g.gen_print_from_expr(stmt.expr, stmt.typ, name)
} else {
g.stmt(stmt)
}
}
} else {
g.n_error('nothing to print')
}
} else {
g.n_error('non-comptime conditionals are not implemented yet.')
}
}
else {
g.expr(expr)
g.gen_to_string(g.code_gen.main_reg(), typ)
g.code_gen.gen_print_reg(g.code_gen.main_reg(), -1, fd)
if newline {
g.code_gen.gen_print('\n', fd)
}
}
}
}