mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: support for compile-time conditionals (#15949)
This commit is contained in:
parent
b83d0281e4
commit
7993f0bf39
@ -2262,6 +2262,11 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
g.gen_typeof_expr(node.right[i] as ast.TypeOf, true)
|
g.gen_typeof_expr(node.right[i] as ast.TypeOf, true)
|
||||||
g.mov_reg(.rsi, .rax)
|
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 {
|
else {
|
||||||
// dump(node)
|
// dump(node)
|
||||||
size := g.get_type_size(node.left_types[i])
|
size := g.get_type_size(node.left_types[i])
|
||||||
@ -2733,7 +2738,8 @@ fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
|
|||||||
|
|
||||||
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
g.n_error('ignored comptime')
|
g.comptime_conditional(node)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if node.branches.len == 0 {
|
if node.branches.len == 0 {
|
||||||
return
|
return
|
||||||
|
217
vlib/v/gen/native/comptime.v
Normal file
217
vlib/v/gen/native/comptime.v
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
// Copyright (c) 2019-2022 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) comptime_at(node ast.AtExpr) string {
|
||||||
|
return node.val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) comptime_conditional(node ast.IfExpr) {
|
||||||
|
if node.branches.len == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) comptime_is_truthy(cond ast.Expr) bool {
|
||||||
|
match cond {
|
||||||
|
ast.BoolLiteral {
|
||||||
|
return cond.val
|
||||||
|
}
|
||||||
|
ast.ParExpr {
|
||||||
|
return g.comptime_is_truthy(cond.expr)
|
||||||
|
}
|
||||||
|
ast.PrefixExpr {
|
||||||
|
match cond.op {
|
||||||
|
.not {
|
||||||
|
return !g.comptime_is_truthy(cond.right)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Compile time infix expr `$cond` is not handled by the native backed.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.PostfixExpr {
|
||||||
|
return g.comptime_ident((cond.expr as ast.Ident).name, true)
|
||||||
|
}
|
||||||
|
ast.InfixExpr {
|
||||||
|
match cond.op {
|
||||||
|
.logical_or {
|
||||||
|
return g.comptime_is_truthy(cond.left) || g.comptime_is_truthy(cond.right)
|
||||||
|
}
|
||||||
|
.and {
|
||||||
|
return g.comptime_is_truthy(cond.left) && g.comptime_is_truthy(cond.right)
|
||||||
|
}
|
||||||
|
.eq {
|
||||||
|
return g.comptime_is_truthy(cond.left) == g.comptime_is_truthy(cond.right)
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
return g.comptime_is_truthy(cond.left) != g.comptime_is_truthy(cond.right)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Compile time infix expr `$cond` is not handled by the native backend.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Ident {
|
||||||
|
return g.comptime_ident(cond.name, false)
|
||||||
|
}
|
||||||
|
ast.ComptimeCall {
|
||||||
|
g.n_error('Comptime calls are not implemented')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// should be unreachable
|
||||||
|
g.n_error('Compile time conditional `$cond` is not handled by the native backend.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) comptime_ident(name string, is_comptime_optional bool) bool {
|
||||||
|
return match name {
|
||||||
|
//
|
||||||
|
// Operating systems
|
||||||
|
//
|
||||||
|
'windows' {
|
||||||
|
g.pref.os == .windows
|
||||||
|
}
|
||||||
|
'ios' {
|
||||||
|
g.pref.os == .ios
|
||||||
|
}
|
||||||
|
'macos', 'mac', 'darwin' {
|
||||||
|
g.pref.os == .macos
|
||||||
|
}
|
||||||
|
'linux' {
|
||||||
|
g.pref.os == .linux
|
||||||
|
}
|
||||||
|
'serenity' {
|
||||||
|
g.pref.os == .serenity
|
||||||
|
}
|
||||||
|
'vinix' {
|
||||||
|
g.pref.os == .vinix
|
||||||
|
}
|
||||||
|
'freebsd' {
|
||||||
|
g.pref.os == .freebsd
|
||||||
|
}
|
||||||
|
'openbsd' {
|
||||||
|
g.pref.os == .openbsd
|
||||||
|
}
|
||||||
|
'netbsd' {
|
||||||
|
g.pref.os == .netbsd
|
||||||
|
}
|
||||||
|
'bsd' {
|
||||||
|
g.pref.os in [.freebsd, .openbsd, .netbsd]
|
||||||
|
}
|
||||||
|
'dragonfly' {
|
||||||
|
g.pref.os == .dragonfly
|
||||||
|
}
|
||||||
|
'android' {
|
||||||
|
g.pref.os == .android
|
||||||
|
}
|
||||||
|
'termux' {
|
||||||
|
g.pref.os == .termux
|
||||||
|
}
|
||||||
|
'solaris' {
|
||||||
|
g.pref.os == .solaris
|
||||||
|
}
|
||||||
|
'haiku' {
|
||||||
|
g.pref.os == .haiku
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// C compilers, these will probably always be false
|
||||||
|
//
|
||||||
|
'gcc' {
|
||||||
|
g.pref.ccompiler_type == .gcc
|
||||||
|
}
|
||||||
|
'tinyc' {
|
||||||
|
g.pref.ccompiler_type == .tinyc
|
||||||
|
}
|
||||||
|
'clang' {
|
||||||
|
g.pref.ccompiler_type == .clang
|
||||||
|
}
|
||||||
|
'mingw' {
|
||||||
|
g.pref.ccompiler_type == .mingw
|
||||||
|
}
|
||||||
|
'msvc' {
|
||||||
|
g.pref.ccompiler_type == .msvc
|
||||||
|
}
|
||||||
|
'cplusplus' {
|
||||||
|
g.pref.ccompiler_type == .cplusplus
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Platforms
|
||||||
|
//
|
||||||
|
'amd64', 'x64' {
|
||||||
|
g.pref.arch == .amd64
|
||||||
|
}
|
||||||
|
'arm64' {
|
||||||
|
g.pref.arch == .arm64
|
||||||
|
}
|
||||||
|
'x86' {
|
||||||
|
false // native only supports 64-bit systems
|
||||||
|
}
|
||||||
|
'little_endian' {
|
||||||
|
true // all systems targeted by native should be little-endian
|
||||||
|
}
|
||||||
|
'big_endian' {
|
||||||
|
false // all systems targeted by native should be little-endian
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Other
|
||||||
|
//
|
||||||
|
'debug' {
|
||||||
|
g.pref.is_debug
|
||||||
|
}
|
||||||
|
'prod' {
|
||||||
|
g.pref.is_prod
|
||||||
|
}
|
||||||
|
'test' {
|
||||||
|
g.pref.is_test
|
||||||
|
}
|
||||||
|
'js' {
|
||||||
|
g.pref.arch == .js_node
|
||||||
|
}
|
||||||
|
'glibc' {
|
||||||
|
g.pref.is_glibc
|
||||||
|
}
|
||||||
|
'prealloc' {
|
||||||
|
g.pref.prealloc
|
||||||
|
}
|
||||||
|
'no_bounds_checking' {
|
||||||
|
false // TODO
|
||||||
|
}
|
||||||
|
'freestanding' {
|
||||||
|
g.pref.arch == .js_freestanding
|
||||||
|
}
|
||||||
|
'no_segfault_handler' {
|
||||||
|
false // TODO
|
||||||
|
}
|
||||||
|
'no_backtrace' {
|
||||||
|
false // TODO
|
||||||
|
}
|
||||||
|
'no_main' {
|
||||||
|
g.pref.is_script
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if is_comptime_optional
|
||||||
|
|| (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
g.n_error('Unhandled os ifdef name "$name".')
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -811,13 +811,19 @@ g.expr
|
|||||||
g.v_error('struct.field selector not yet implemented for this backend', expr.pos)
|
g.v_error('struct.field selector not yet implemented for this backend', expr.pos)
|
||||||
}
|
}
|
||||||
ast.NodeError {}
|
ast.NodeError {}
|
||||||
|
ast.AtExpr {
|
||||||
|
if newline {
|
||||||
|
g.gen_print(g.comptime_at(expr) + '\n', fd)
|
||||||
|
} else {
|
||||||
|
g.gen_print(g.comptime_at(expr), fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
ast.AnonFn {}
|
ast.AnonFn {}
|
||||||
ast.ArrayDecompose {}
|
ast.ArrayDecompose {}
|
||||||
ast.ArrayInit {}
|
ast.ArrayInit {}
|
||||||
ast.AsCast {}
|
ast.AsCast {}
|
||||||
ast.Assoc {}
|
ast.Assoc {}
|
||||||
ast.AtExpr {}
|
|
||||||
ast.CTempVar {}
|
ast.CTempVar {}
|
||||||
ast.CastExpr {}
|
ast.CastExpr {}
|
||||||
ast.ChanInit {}
|
ast.ChanInit {}
|
||||||
@ -1326,7 +1332,7 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||||||
}
|
}
|
||||||
ast.IfExpr {
|
ast.IfExpr {
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
eprintln('Warning: ignored compile time conditional not yet supported for the native backend.')
|
g.comptime_conditional(node)
|
||||||
} else {
|
} else {
|
||||||
g.if_expr(node)
|
g.if_expr(node)
|
||||||
}
|
}
|
||||||
|
13
vlib/v/gen/native/tests/atexpr.vv
Normal file
13
vlib/v/gen/native/tests/atexpr.vv
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
fn abc() {
|
||||||
|
// a comment
|
||||||
|
a := @LINE
|
||||||
|
b := @FILE_LINE
|
||||||
|
c := @FN
|
||||||
|
println(a)
|
||||||
|
println(b)
|
||||||
|
println(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
abc()
|
||||||
|
}
|
3
vlib/v/gen/native/tests/atexpr.vv.out
Normal file
3
vlib/v/gen/native/tests/atexpr.vv.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
3
|
||||||
|
atexpr.vv:4
|
||||||
|
abc
|
29
vlib/v/gen/native/tests/comptime.vv
Normal file
29
vlib/v/gen/native/tests/comptime.vv
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
fn main() {
|
||||||
|
comptime_if()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comptime_if() {
|
||||||
|
$if linux || windows || macos {
|
||||||
|
println('linux or windows or macos')
|
||||||
|
}
|
||||||
|
|
||||||
|
$if linux && windows {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
|
||||||
|
$if custom_define ? {
|
||||||
|
println('custom defines work')
|
||||||
|
} $else {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
|
||||||
|
$if test {
|
||||||
|
println('test')
|
||||||
|
} $else $if debug {
|
||||||
|
println('debug')
|
||||||
|
} $else $if prod {
|
||||||
|
println('production')
|
||||||
|
} $else {
|
||||||
|
println('other')
|
||||||
|
}
|
||||||
|
}
|
3
vlib/v/gen/native/tests/comptime.vv.out
Normal file
3
vlib/v/gen/native/tests/comptime.vv.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
linux or windows or macos
|
||||||
|
custom defines work
|
||||||
|
other
|
@ -40,7 +40,7 @@ fn test_native() {
|
|||||||
work_test_path := '$wrkdir/$test_file_name'
|
work_test_path := '$wrkdir/$test_file_name'
|
||||||
exe_test_path := '$wrkdir/${test_file_name}.exe'
|
exe_test_path := '$wrkdir/${test_file_name}.exe'
|
||||||
tmperrfile := '$dir/${test}.tmperr'
|
tmperrfile := '$dir/${test}.tmperr'
|
||||||
cmd := '${os.quoted_path(vexe)} -o ${os.quoted_path(exe_test_path)} -b native ${os.quoted_path(full_test_path)} 2> ${os.quoted_path(tmperrfile)}'
|
cmd := '${os.quoted_path(vexe)} -o ${os.quoted_path(exe_test_path)} -b native ${os.quoted_path(full_test_path)} -d custom_define 2> ${os.quoted_path(tmperrfile)}'
|
||||||
if is_verbose {
|
if is_verbose {
|
||||||
println(cmd)
|
println(cmd)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user