1
0
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:
Spydr 2022-10-02 21:31:59 +02:00 committed by GitHub
parent b83d0281e4
commit 7993f0bf39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 281 additions and 4 deletions

View File

@ -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.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])
@ -2733,7 +2738,8 @@ 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.n_error('ignored comptime')
g.comptime_conditional(node)
return
}
if node.branches.len == 0 {
return

View 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
}
}
}
}

View File

@ -811,13 +811,19 @@ g.expr
g.v_error('struct.field selector not yet implemented for this backend', expr.pos)
}
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.ArrayDecompose {}
ast.ArrayInit {}
ast.AsCast {}
ast.Assoc {}
ast.AtExpr {}
ast.CTempVar {}
ast.CastExpr {}
ast.ChanInit {}
@ -1326,7 +1332,7 @@ fn (mut g Gen) expr(node ast.Expr) {
}
ast.IfExpr {
if node.is_comptime {
eprintln('Warning: ignored compile time conditional not yet supported for the native backend.')
g.comptime_conditional(node)
} else {
g.if_expr(node)
}

View 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()
}

View File

@ -0,0 +1,3 @@
3
atexpr.vv:4
abc

View 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')
}
}

View File

@ -0,0 +1,3 @@
linux or windows or macos
custom defines work
other

View File

@ -40,7 +40,7 @@ fn test_native() {
work_test_path := '$wrkdir/$test_file_name'
exe_test_path := '$wrkdir/${test_file_name}.exe'
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 {
println(cmd)
}