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

native: fix small issues with compile-time conditionals (#16149)

This commit is contained in:
Spydr
2022-10-22 18:56:19 +02:00
committed by GitHub
parent b8b2b4ad0a
commit 83338e044a
5 changed files with 438 additions and 383 deletions

View File

@@ -1848,6 +1848,402 @@ fn (mut g Gen) delay_fn_call(name string) {
// do nothing for now
}
fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, name string, ident ast.Ident) {
match right {
ast.IntegerLiteral {
// g.allocate_var(name, 4, right.val.int())
match node.op {
.plus_assign {
g.mov_var_to_reg(.rax, ident)
g.add(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
.minus_assign {
g.mov_var_to_reg(.rax, ident)
g.sub(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
.mult_assign {
g.mov_var_to_reg(.rax, ident)
g.mov64(.rdx, right.val.int())
g.mul_reg(.rax, .rdx)
g.mov_reg_to_var(ident, .rax)
}
.div_assign {
g.mov_var_to_reg(.rax, ident)
g.mov64(.rdx, right.val.int())
g.div_reg(.rax, .rdx)
g.mov_reg_to_var(ident, .rax)
}
.decl_assign {
g.allocate_var(name, 8, right.val.int())
}
.assign {
// dump(g.typ(node.left_types[i]))
match node.left[i] {
ast.Ident {
// lname := '${node.left[i]}'
// g.expr(node.right[i])
g.mov(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
else {
tn := node.left[i].type_name()
dump(node.left_types)
g.n_error('unhandled assign type: $tn')
}
}
}
else {
eprintln('ERROR 2')
dump(node)
}
}
}
ast.InfixExpr {
// eprintln('infix') dump(node) dump(right)
g.infix_expr(right)
offset := g.allocate_var(name, g.get_sizeof_ident(ident), 0)
// `mov DWORD PTR [rbp-0x8],eax`
if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()')
}
g.mov_reg_to_var(ident, .rax)
}
ast.Ident {
// eprintln('identr') dump(node) dump(right)
match node.op {
.plus_assign {
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.add_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.minus_assign {
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.sub_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.div_assign {
// this should be called when `a /= b` but it's not :?
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.div_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.decl_assign {
typ := node.left_types[i]
if typ.is_number() || typ.is_real_pointer() || typ.is_bool() {
g.allocate_var(name, g.get_type_size(typ), 0)
} else {
ts := g.table.sym(typ)
match ts.info {
ast.Struct {
g.allocate_struct(name, typ)
}
else {}
}
}
var_ := g.get_var_from_ident(ident)
// TODO global var
right_var := g.get_var_from_ident(right) as LocalVar
match var_ {
LocalVar {
var := var_ as LocalVar
if var.typ.is_number() || var.typ.is_real_pointer() || var.typ.is_bool() {
g.mov_var_to_reg(.rax, right as ast.Ident)
g.mov_reg_to_var(ident, .rax)
} else {
ts := g.table.sym(var.typ)
match ts.info {
ast.Struct {
size := g.get_type_size(var.typ)
if size >= 8 {
for offset in 0 .. size / 8 {
g.mov_var_to_reg(.rax, right_var,
offset: offset * 8
typ: ast.i64_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: offset * 8
typ: ast.i64_type_idx
)
}
if size % 8 != 0 {
g.mov_var_to_reg(.rax, right_var,
offset: size - 8
typ: ast.i64_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - 8
typ: ast.i64_type_idx
)
}
} else {
mut left_size := if size >= 4 {
g.mov_var_to_reg(.rax, right_var,
typ: ast.int_type_idx
)
g.mov_reg_to_var(var, .rax,
typ: ast.int_type_idx
)
size - 4
} else {
size
}
if left_size >= 2 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i16_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i16_type_idx
)
left_size -= 2
}
if left_size == 1 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i8_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i8_type_idx
)
}
}
}
else {
g.n_error('Unsupported variable type')
}
}
}
}
else {
g.n_error('Unsupported variable kind')
}
}
}
.assign {
var_ := g.get_var_from_ident(ident)
// TODO global var
right_var := g.get_var_from_ident(right) as LocalVar
match var_ {
LocalVar {
var := var_ as LocalVar
if var.typ.is_number() || var.typ.is_real_pointer() || var.typ.is_bool() {
g.mov_var_to_reg(.rax, right as ast.Ident)
g.mov_reg_to_var(ident, .rax)
} else {
ts := g.table.sym(var.typ)
match ts.info {
ast.Struct {
size := g.get_type_size(var.typ)
if size >= 8 {
for offset in 0 .. size / 8 {
g.mov_var_to_reg(.rax, right_var,
offset: offset * 8
typ: ast.i64_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: offset * 8
typ: ast.i64_type_idx
)
}
if size % 8 != 0 {
g.mov_var_to_reg(.rax, right_var,
offset: size - 8
typ: ast.i64_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - 8
typ: ast.i64_type_idx
)
}
} else {
mut left_size := if size >= 4 {
g.mov_var_to_reg(.rax, right_var,
typ: ast.int_type_idx
)
g.mov_reg_to_var(var, .rax,
typ: ast.int_type_idx
)
size - 4
} else {
size
}
if left_size >= 2 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i16_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i16_type_idx
)
left_size -= 2
}
if left_size == 1 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i8_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i8_type_idx
)
}
}
}
else {
g.n_error('Unsupported variable type')
}
}
}
}
else {
g.n_error('Unsupported variable kind')
}
}
}
else {
eprintln('TODO: unhandled assign ident case')
dump(node)
}
}
// a += b
}
ast.StructInit {
match node.op {
.decl_assign {
g.allocate_struct(name, right.typ)
g.init_struct(ident, right)
}
else {
g.n_error('Unexpected operator `$node.op`')
}
}
}
ast.ArrayInit {
// check if array is empty
mut pos := g.allocate_array(name, 8, right.exprs.len)
// allocate array of right.exprs.len vars
for e in right.exprs {
match e {
ast.IntegerLiteral {
g.mov(.rax, e.val.int())
g.mov_reg_to_var(LocalVar{pos, ast.i64_type_idx, ''}, .rax)
pos += 8
}
ast.StringLiteral {
// TODO: use learel
str := g.eval_escape_codes(e)
g.mov64(.rsi, g.allocate_string(str, 2, .abs64)) // for rsi its 2
g.mov_reg_to_var(LocalVar{pos, ast.u64_type_idx, ''}, .rsi)
pos += 8
}
else {
dump(e)
g.n_error('unhandled array init type')
}
}
}
}
ast.IndexExpr {
// a := arr[0]
offset := g.allocate_var(name, g.get_sizeof_ident(ident), 0)
if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()')
}
ie := right as ast.IndexExpr
var := ie.left as ast.Ident
dest := g.get_var_offset(var.name)
if ie.index is ast.IntegerLiteral {
index := ie.index
ie_offset := index.val.int() * 8
g.mov_var_to_reg(.rax, var, typ: ast.i64_type_idx, offset: ie_offset)
} else if ie.index is ast.Ident {
ie_ident := ie.index
g.lea_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rdi, ie_ident)
g.add_reg(.rax, .rdi)
g.mov_deref(.rax, .rax, ast.i64_type_idx)
} else {
g.n_error('only integers and idents can be used as indexes')
}
// TODO check if out of bounds access
g.mov_reg_to_var(ident, .eax)
}
ast.StringLiteral {
dest := g.allocate_var(name, 8, 0)
ie := right as ast.StringLiteral
str := g.eval_escape_codes(ie)
g.learel(.rsi, g.allocate_string(str, 3, .rel32))
g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi)
}
ast.CallExpr {
g.allocate_var(name, g.get_sizeof_ident(ident), 0)
g.call_fn(right)
g.mov_reg_to_var(ident, .rax)
g.mov_var_to_reg(.rsi, ident)
}
ast.GoExpr {
g.v_error('threads not implemented for the native backend', 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(right as ast.TypeOf, true)
g.mov_reg(.rsi, .rax)
}
ast.AtExpr {
dest := g.allocate_var(name, 8, 0)
g.learel(.rsi, g.allocate_string(g.comptime_at(right), 3, .rel32))
g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi)
}
else {
if right is ast.IfExpr && (right as ast.IfExpr).is_comptime {
if stmts := g.comptime_conditional(right) {
for j, stmt in stmts {
if j + 1 == stmts.len {
if stmt is ast.ExprStmt {
g.assign_right_expr(node, i, stmt.expr, name, ident)
} else {
g.n_error('last stmt must be expr')
}
} else {
g.stmt(stmt)
}
}
} else {
g.n_error('missing value for assignment')
}
return
}
// dump(node)
size := g.get_type_size(node.left_types[i])
if size !in [1, 2, 4, 8] || node.op !in [.assign, .decl_assign] {
g.v_error('unhandled assign_stmt expression: $right.type_name()', right.pos())
}
if node.op == .decl_assign {
g.allocate_var(name, size, 0)
}
g.expr(right)
var := g.get_var_from_ident(ident)
match var {
LocalVar { g.mov_reg_to_var(var as LocalVar, .rax) }
GlobalVar { g.mov_reg_to_var(var as GlobalVar, .rax) }
Register { g.mov_reg(var as Register, .rax) }
}
}
}
}
fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
// `a := 1` | `a,b := 1,2`
for i, left in node.left {
@@ -1931,380 +2327,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
}
continue
}
name := left.str()
ident := left as ast.Ident
match right {
ast.IntegerLiteral {
// g.allocate_var(name, 4, right.val.int())
match node.op {
.plus_assign {
g.mov_var_to_reg(.rax, ident)
g.add(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
.minus_assign {
g.mov_var_to_reg(.rax, ident)
g.sub(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
.mult_assign {
g.mov_var_to_reg(.rax, ident)
g.mov64(.rdx, right.val.int())
g.mul_reg(.rax, .rdx)
g.mov_reg_to_var(ident, .rax)
}
.div_assign {
g.mov_var_to_reg(.rax, ident)
g.mov64(.rdx, right.val.int())
g.div_reg(.rax, .rdx)
g.mov_reg_to_var(ident, .rax)
}
.decl_assign {
g.allocate_var(name, 8, right.val.int())
}
.assign {
// dump(g.typ(node.left_types[i]))
match node.left[i] {
ast.Ident {
// lname := '${node.left[i]}'
// g.expr(node.right[i])
g.mov(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
else {
tn := node.left[i].type_name()
dump(node.left_types)
g.n_error('unhandled assign type: $tn')
}
}
}
else {
eprintln('ERROR 2')
dump(node)
}
}
}
ast.InfixExpr {
// eprintln('infix') dump(node) dump(right)
g.infix_expr(right)
offset := g.allocate_var(name, g.get_sizeof_ident(ident), 0)
// `mov DWORD PTR [rbp-0x8],eax`
if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()')
}
g.mov_reg_to_var(ident, .rax)
}
ast.Ident {
// eprintln('identr') dump(node) dump(right)
match node.op {
.plus_assign {
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.add_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.minus_assign {
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.sub_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.div_assign {
// this should be called when `a /= b` but it's not :?
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.div_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.decl_assign {
typ := node.left_types[i]
if typ.is_number() || typ.is_real_pointer() || typ.is_bool() {
g.allocate_var(name, g.get_type_size(typ), 0)
} else {
ts := g.table.sym(typ)
match ts.info {
ast.Struct {
g.allocate_struct(name, typ)
}
else {}
}
}
var_ := g.get_var_from_ident(ident)
// TODO global var
right_var := g.get_var_from_ident(right) as LocalVar
match var_ {
LocalVar {
var := var_ as LocalVar
if var.typ.is_number() || var.typ.is_real_pointer()
|| var.typ.is_bool() {
g.mov_var_to_reg(.rax, right as ast.Ident)
g.mov_reg_to_var(ident, .rax)
} else {
ts := g.table.sym(var.typ)
match ts.info {
ast.Struct {
size := g.get_type_size(var.typ)
if size >= 8 {
for offset in 0 .. size / 8 {
g.mov_var_to_reg(.rax, right_var,
offset: offset * 8, typ: ast.i64_type_idx)
g.mov_reg_to_var(var, .rax,
offset: offset * 8
typ: ast.i64_type_idx
)
}
if size % 8 != 0 {
g.mov_var_to_reg(.rax, right_var,
offset: size - 8, typ: ast.i64_type_idx)
g.mov_reg_to_var(var, .rax,
offset: size - 8
typ: ast.i64_type_idx
)
}
} else {
mut left_size := if size >= 4 {
g.mov_var_to_reg(.rax, right_var,
typ: ast.int_type_idx)
g.mov_reg_to_var(var, .rax,
typ: ast.int_type_idx
)
size - 4
} else {
size
}
if left_size >= 2 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i16_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i16_type_idx
)
left_size -= 2
}
if left_size == 1 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i8_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i8_type_idx
)
}
}
}
else {
g.n_error('Unsupported variable type')
}
}
}
}
else {
g.n_error('Unsupported variable kind')
}
}
}
.assign {
var_ := g.get_var_from_ident(ident)
// TODO global var
right_var := g.get_var_from_ident(right) as LocalVar
match var_ {
LocalVar {
var := var_ as LocalVar
if var.typ.is_number() || var.typ.is_real_pointer()
|| var.typ.is_bool() {
g.mov_var_to_reg(.rax, right as ast.Ident)
g.mov_reg_to_var(ident, .rax)
} else {
ts := g.table.sym(var.typ)
match ts.info {
ast.Struct {
size := g.get_type_size(var.typ)
if size >= 8 {
for offset in 0 .. size / 8 {
g.mov_var_to_reg(.rax, right_var,
offset: offset * 8, typ: ast.i64_type_idx)
g.mov_reg_to_var(var, .rax,
offset: offset * 8
typ: ast.i64_type_idx
)
}
if size % 8 != 0 {
g.mov_var_to_reg(.rax, right_var,
offset: size - 8, typ: ast.i64_type_idx)
g.mov_reg_to_var(var, .rax,
offset: size - 8
typ: ast.i64_type_idx
)
}
} else {
mut left_size := if size >= 4 {
g.mov_var_to_reg(.rax, right_var,
typ: ast.int_type_idx)
g.mov_reg_to_var(var, .rax,
typ: ast.int_type_idx
)
size - 4
} else {
size
}
if left_size >= 2 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i16_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i16_type_idx
)
left_size -= 2
}
if left_size == 1 {
g.mov_var_to_reg(.rax, right_var,
offset: size - left_size
typ: ast.i8_type_idx
)
g.mov_reg_to_var(var, .rax,
offset: size - left_size
typ: ast.i8_type_idx
)
}
}
}
else {
g.n_error('Unsupported variable type')
}
}
}
}
else {
g.n_error('Unsupported variable kind')
}
}
}
else {
eprintln('TODO: unhandled assign ident case')
dump(node)
}
}
// a += b
}
ast.StructInit {
match node.op {
.decl_assign {
g.allocate_struct(name, right.typ)
g.init_struct(ident, right)
}
else {
g.n_error('Unexpected operator `$node.op`')
}
}
}
ast.ArrayInit {
// check if array is empty
mut pos := g.allocate_array(name, 8, right.exprs.len)
// allocate array of right.exprs.len vars
for e in right.exprs {
match e {
ast.IntegerLiteral {
g.mov(.rax, e.val.int())
g.mov_reg_to_var(LocalVar{pos, ast.i64_type_idx, ''}, .rax)
pos += 8
}
ast.StringLiteral {
// TODO: use learel
str := g.eval_escape_codes(e)
g.mov64(.rsi, g.allocate_string(str, 2, .abs64)) // for rsi its 2
g.mov_reg_to_var(LocalVar{pos, ast.u64_type_idx, ''}, .rsi)
pos += 8
}
else {
dump(e)
g.n_error('unhandled array init type')
}
}
}
}
ast.IndexExpr {
// a := arr[0]
offset := g.allocate_var(name, g.get_sizeof_ident(ident), 0)
if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()')
}
ie := node.right[i] as ast.IndexExpr
var := ie.left as ast.Ident
dest := g.get_var_offset(var.name)
if ie.index is ast.IntegerLiteral {
index := ie.index
ie_offset := index.val.int() * 8
g.mov_var_to_reg(.rax, var, typ: ast.i64_type_idx, offset: ie_offset)
} else if ie.index is ast.Ident {
ie_ident := ie.index
g.lea_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rdi, ie_ident)
g.add_reg(.rax, .rdi)
g.mov_deref(.rax, .rax, ast.i64_type_idx)
} else {
g.n_error('only integers and idents can be used as indexes')
}
// TODO check if out of bounds access
g.mov_reg_to_var(ident, .eax)
}
ast.StringLiteral {
dest := g.allocate_var(name, 8, 0)
ie := node.right[i] as ast.StringLiteral
str := g.eval_escape_codes(ie)
g.learel(.rsi, g.allocate_string(str, 3, .rel32))
g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi)
}
ast.CallExpr {
g.allocate_var(name, g.get_sizeof_ident(ident), 0)
g.call_fn(right)
g.mov_reg_to_var(ident, .rax)
g.mov_var_to_reg(.rsi, ident)
}
ast.GoExpr {
g.v_error('threads not implemented for the native backend', 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)
}
ast.AtExpr {
dest := g.allocate_var(name, 8, 0)
g.learel(.rsi, g.allocate_string(g.comptime_at(right), 3, .rel32))
g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi)
}
else {
// dump(node)
size := g.get_type_size(node.left_types[i])
if size !in [1, 2, 4, 8] || node.op !in [.assign, .decl_assign] {
g.v_error('unhandled assign_stmt expression: $right.type_name()',
right.pos())
}
if node.op == .decl_assign {
g.allocate_var(name, size, 0)
}
g.expr(right)
var := g.get_var_from_ident(ident)
match var {
LocalVar { g.mov_reg_to_var(var as LocalVar, .rax) }
GlobalVar { g.mov_reg_to_var(var as GlobalVar, .rax) }
Register { g.mov_reg(var as Register, .rax) }
}
}
}
// }
g.assign_right_expr(node, i, right, left.str(), left as ast.Ident)
}
}
@@ -2756,7 +2779,9 @@ fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
fn (mut g Gen) if_expr(node ast.IfExpr) {
if node.is_comptime {
g.comptime_conditional(node)
if stmts := g.comptime_conditional(node) {
g.stmts(stmts)
}
return
}
if node.branches.len == 0 {

View File

@@ -9,20 +9,19 @@ fn (mut g Gen) comptime_at(node ast.AtExpr) string {
return node.val
}
fn (mut g Gen) comptime_conditional(node ast.IfExpr) {
fn (mut g Gen) comptime_conditional(node ast.IfExpr) ?[]ast.Stmt {
if node.branches.len == 0 {
return
return none
}
for i, branch in node.branches {
// handle $else branch, which does not have a condition
if node.has_else && i + 1 == node.branches.len {
g.stmts(branch.stmts)
} else if g.comptime_is_truthy(branch.cond) {
g.stmts(branch.stmts)
break
if (node.has_else && i + 1 == node.branches.len) || g.comptime_is_truthy(branch.cond) {
return branch.stmts
}
}
return none
}
fn (mut g Gen) comptime_is_truthy(cond ast.Expr) bool {

View File

@@ -871,6 +871,23 @@ g.expr
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, name)
} else {
g.stmt(stmt)
}
}
} else {
g.n_error('nothing to print')
}
} else {
g.n_error('non-comptime if exprs not yet implemented')
}
}
else {
dump(typeof(expr).name)
dump(expr)
@@ -1326,7 +1343,10 @@ fn (mut g Gen) expr(node ast.Expr) {
}
ast.IfExpr {
if node.is_comptime {
g.comptime_conditional(node)
if stmts := g.comptime_conditional(node) {
g.stmts(stmts)
} else {
}
} else {
g.if_expr(node)
}

View File

@@ -7,6 +7,13 @@ fn comptime_if() {
println('linux or windows or macos')
}
os := $if linux || windows || macos {
'linux or windows or macos'
} $else {
'other'
}
println(os)
$if linux && windows {
assert false
}
@@ -17,6 +24,8 @@ fn comptime_if() {
assert false
}
println($if true { 'printing directly' } $else { '' })
$if test {
println('test')
} $else $if debug {

View File

@@ -1,3 +1,5 @@
linux or windows or macos
linux or windows or macos
custom defines work
printing directly
other