mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
parser,fmt,markused: add top level comptime $if
support (enable $if platform { import module struct Abc {} }
) (#25216)
Some checks are pending
Graphics CI / gg-regressions (push) Waiting to run
vlib modules CI / build-module-docs (push) Waiting to run
native backend CI / native-backend-ubuntu (push) Waiting to run
native backend CI / native-backend-windows (push) Waiting to run
Shy and PV CI / v-compiles-puzzle-vibes (push) Waiting to run
Sanitized CI / sanitize-undefined-clang (push) Waiting to run
Sanitized CI / sanitize-undefined-gcc (push) Waiting to run
Sanitized CI / tests-sanitize-address-clang (push) Waiting to run
Sanitized CI / sanitize-address-msvc (push) Waiting to run
Sanitized CI / sanitize-address-gcc (push) Waiting to run
Sanitized CI / sanitize-memory-clang (push) Waiting to run
sdl CI / v-compiles-sdl-examples (push) Waiting to run
Time CI / time-linux (push) Waiting to run
Time CI / time-macos (push) Waiting to run
Time CI / time-windows (push) Waiting to run
toml CI / toml-module-pass-external-test-suites (push) Waiting to run
Tools CI / tools-linux (clang) (push) Waiting to run
Tools CI / tools-linux (gcc) (push) Waiting to run
Tools CI / tools-linux (tcc) (push) Waiting to run
Tools CI / tools-macos (clang) (push) Waiting to run
Tools CI / tools-windows (gcc) (push) Waiting to run
Tools CI / tools-windows (msvc) (push) Waiting to run
Tools CI / tools-windows (tcc) (push) Waiting to run
Tools CI / tools-docker-ubuntu-musl (push) Waiting to run
vab CI / v-compiles-os-android (push) Waiting to run
vab CI / vab-compiles-v-examples (push) Waiting to run
wasm backend CI / wasm-backend (ubuntu-22.04) (push) Waiting to run
wasm backend CI / wasm-backend (windows-2022) (push) Waiting to run
Some checks are pending
Graphics CI / gg-regressions (push) Waiting to run
vlib modules CI / build-module-docs (push) Waiting to run
native backend CI / native-backend-ubuntu (push) Waiting to run
native backend CI / native-backend-windows (push) Waiting to run
Shy and PV CI / v-compiles-puzzle-vibes (push) Waiting to run
Sanitized CI / sanitize-undefined-clang (push) Waiting to run
Sanitized CI / sanitize-undefined-gcc (push) Waiting to run
Sanitized CI / tests-sanitize-address-clang (push) Waiting to run
Sanitized CI / sanitize-address-msvc (push) Waiting to run
Sanitized CI / sanitize-address-gcc (push) Waiting to run
Sanitized CI / sanitize-memory-clang (push) Waiting to run
sdl CI / v-compiles-sdl-examples (push) Waiting to run
Time CI / time-linux (push) Waiting to run
Time CI / time-macos (push) Waiting to run
Time CI / time-windows (push) Waiting to run
toml CI / toml-module-pass-external-test-suites (push) Waiting to run
Tools CI / tools-linux (clang) (push) Waiting to run
Tools CI / tools-linux (gcc) (push) Waiting to run
Tools CI / tools-linux (tcc) (push) Waiting to run
Tools CI / tools-macos (clang) (push) Waiting to run
Tools CI / tools-windows (gcc) (push) Waiting to run
Tools CI / tools-windows (msvc) (push) Waiting to run
Tools CI / tools-windows (tcc) (push) Waiting to run
Tools CI / tools-docker-ubuntu-musl (push) Waiting to run
vab CI / v-compiles-os-android (push) Waiting to run
vab CI / vab-compiles-v-examples (push) Waiting to run
wasm backend CI / wasm-backend (ubuntu-22.04) (push) Waiting to run
wasm backend CI / wasm-backend (windows-2022) (push) Waiting to run
This commit is contained in:
parent
344f7ccdcb
commit
19d31f221f
14 changed files with 955 additions and 434 deletions
|
@ -1,5 +1,7 @@
|
||||||
module ast
|
module ast
|
||||||
|
|
||||||
|
import v.pref
|
||||||
|
|
||||||
pub const valid_comptime_if_os = ['windows', 'ios', 'macos', 'mach', 'darwin', 'hpux', 'gnu', 'qnx',
|
pub const valid_comptime_if_os = ['windows', 'ios', 'macos', 'mach', 'darwin', 'hpux', 'gnu', 'qnx',
|
||||||
'linux', 'freebsd', 'openbsd', 'netbsd', 'bsd', 'dragonfly', 'android', 'termux', 'solaris',
|
'linux', 'freebsd', 'openbsd', 'netbsd', 'bsd', 'dragonfly', 'android', 'termux', 'solaris',
|
||||||
'haiku', 'serenity', 'vinix', 'plan9', 'wasm32_emscripten']
|
'haiku', 'serenity', 'vinix', 'plan9', 'wasm32_emscripten']
|
||||||
|
@ -22,3 +24,225 @@ fn all_valid_comptime_idents() []string {
|
||||||
res << valid_comptime_if_other
|
res << valid_comptime_if_other
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eval_comptime_not_user_defined_ident(ident string, the_pref &pref.Preferences) !bool {
|
||||||
|
mut is_true := false
|
||||||
|
if ident in valid_comptime_if_os {
|
||||||
|
if ident_enum_val := pref.os_from_string(ident) {
|
||||||
|
if ident_enum_val == the_pref.os {
|
||||||
|
is_true = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ident in valid_comptime_if_compilers {
|
||||||
|
is_true = pref.cc_from_string(ident) == the_pref.ccompiler_type
|
||||||
|
} else if ident in valid_comptime_if_platforms {
|
||||||
|
match ident {
|
||||||
|
'amd64' {
|
||||||
|
is_true = the_pref.arch == .amd64
|
||||||
|
}
|
||||||
|
'i386' {
|
||||||
|
is_true = the_pref.arch == .i386
|
||||||
|
}
|
||||||
|
'aarch64' {
|
||||||
|
is_true = the_pref.arch == .arm64
|
||||||
|
}
|
||||||
|
'arm64' {
|
||||||
|
is_true = the_pref.arch == .arm64
|
||||||
|
}
|
||||||
|
'arm32' {
|
||||||
|
is_true = the_pref.arch == .arm32
|
||||||
|
}
|
||||||
|
'rv64' {
|
||||||
|
is_true = the_pref.arch == .rv64
|
||||||
|
}
|
||||||
|
'rv32' {
|
||||||
|
is_true = the_pref.arch == .rv32
|
||||||
|
}
|
||||||
|
's390x' {
|
||||||
|
is_true = the_pref.arch == .s390x
|
||||||
|
}
|
||||||
|
'ppc64le' {
|
||||||
|
is_true = the_pref.arch == .ppc64le
|
||||||
|
}
|
||||||
|
'loongarch64' {
|
||||||
|
is_true = the_pref.arch == .loongarch64
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return error('invalid \$if condition: unknown platforms `${ident}`')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ident in valid_comptime_if_cpu_features {
|
||||||
|
match ident {
|
||||||
|
'x64' {
|
||||||
|
is_true = the_pref.m64
|
||||||
|
}
|
||||||
|
'x32' {
|
||||||
|
is_true = !the_pref.m64
|
||||||
|
}
|
||||||
|
'little_endian' {
|
||||||
|
is_true = $if little_endian { true } $else { false }
|
||||||
|
}
|
||||||
|
'big_endian' {
|
||||||
|
is_true = $if big_endian { true } $else { false }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return error('invalid \$if condition: unknown cpu_features `${ident}`')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ident in valid_comptime_if_other {
|
||||||
|
match ident {
|
||||||
|
'apk' {
|
||||||
|
is_true = the_pref.is_apk
|
||||||
|
}
|
||||||
|
'js' {
|
||||||
|
is_true = the_pref.backend.is_js()
|
||||||
|
}
|
||||||
|
'debug' {
|
||||||
|
is_true = the_pref.is_debug
|
||||||
|
}
|
||||||
|
'prod' {
|
||||||
|
is_true = the_pref.is_prod
|
||||||
|
}
|
||||||
|
'test' {
|
||||||
|
is_true = the_pref.is_test
|
||||||
|
}
|
||||||
|
'glibc' {
|
||||||
|
is_true = the_pref.is_glibc
|
||||||
|
}
|
||||||
|
'prealloc' {
|
||||||
|
is_true = the_pref.prealloc
|
||||||
|
}
|
||||||
|
'no_bounds_checking' {
|
||||||
|
is_true = the_pref.no_bounds_checking
|
||||||
|
}
|
||||||
|
'freestanding' {
|
||||||
|
is_true = the_pref.is_bare && !the_pref.output_cross_c
|
||||||
|
}
|
||||||
|
'threads' {
|
||||||
|
return error('threads should handle outside of `check_valid_ident()`')
|
||||||
|
}
|
||||||
|
'js_node' {
|
||||||
|
is_true = the_pref.backend == .js_node
|
||||||
|
}
|
||||||
|
'js_browser' {
|
||||||
|
is_true = the_pref.backend == .js_browser
|
||||||
|
}
|
||||||
|
'js_freestanding' {
|
||||||
|
is_true = the_pref.backend == .js_freestanding
|
||||||
|
}
|
||||||
|
'interpreter' {
|
||||||
|
is_true = the_pref.backend == .interpret
|
||||||
|
}
|
||||||
|
'es5' {
|
||||||
|
is_true = the_pref.output_es5
|
||||||
|
}
|
||||||
|
'profile' {
|
||||||
|
is_true = the_pref.is_prof
|
||||||
|
}
|
||||||
|
'wasm32' {
|
||||||
|
is_true = the_pref.arch == .wasm32
|
||||||
|
}
|
||||||
|
'wasm32_wasi' {
|
||||||
|
is_true = the_pref.os == .wasm32_wasi
|
||||||
|
}
|
||||||
|
'fast_math' {
|
||||||
|
is_true = the_pref.fast_math
|
||||||
|
}
|
||||||
|
'native' {
|
||||||
|
is_true = the_pref.backend == .native
|
||||||
|
}
|
||||||
|
'autofree' {
|
||||||
|
is_true = the_pref.autofree
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return error('invalid \$if condition: unknown other indent `${ident}`')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ident in the_pref.compile_defines {
|
||||||
|
is_true = true
|
||||||
|
} else {
|
||||||
|
return error('invalid \$if condition: unknown indent `${ident}`')
|
||||||
|
}
|
||||||
|
return is_true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const system_ident_map = {
|
||||||
|
// OS
|
||||||
|
'windows': '_WIN32'
|
||||||
|
'ios': '__TARGET_IOS__'
|
||||||
|
'macos': '__APPLE__'
|
||||||
|
'mach': '__MACH__'
|
||||||
|
'darwin': '__DARWIN__'
|
||||||
|
'hpux': '__HPUX__'
|
||||||
|
'gnu': '__GNU__'
|
||||||
|
'qnx': '__QNX__'
|
||||||
|
'linux': '__linux__'
|
||||||
|
'serenity': '__serenity__'
|
||||||
|
'plan9': '__plan9__'
|
||||||
|
'vinix': '__vinix__'
|
||||||
|
'freebsd': '__FreeBSD__'
|
||||||
|
'openbsd': '__OpenBSD__'
|
||||||
|
'netbsd': '__NetBSD__'
|
||||||
|
'bsd': '__BSD__'
|
||||||
|
'dragonfly': '__DragonFly__'
|
||||||
|
'android': '__ANDROID__'
|
||||||
|
'termux': '__TERMUX__'
|
||||||
|
'solaris': '__sun'
|
||||||
|
'haiku': '__HAIKU__'
|
||||||
|
// Backend
|
||||||
|
'js': '_VJS'
|
||||||
|
'wasm32_emscripten': '__EMSCRIPTEN__'
|
||||||
|
'native': '_VNATIVE'
|
||||||
|
// Compiler
|
||||||
|
'gcc': '__V_GCC__'
|
||||||
|
'tinyc': '__TINYC__'
|
||||||
|
'clang': '__clang__'
|
||||||
|
'mingw': '__MINGW32__'
|
||||||
|
'msvc': '_MSC_VER'
|
||||||
|
'cplusplus': '__cplusplus'
|
||||||
|
// Others
|
||||||
|
'threads': '__VTHREADS__'
|
||||||
|
'gcboehm': '_VGCBOEHM'
|
||||||
|
'debug': '_VDEBUG'
|
||||||
|
'prod': '_VPROD'
|
||||||
|
'profile': '_VPROFILE'
|
||||||
|
'test': '_VTEST'
|
||||||
|
'glibc': '__GLIBC__'
|
||||||
|
'prealloc': '_VPREALLOC'
|
||||||
|
'no_bounds_checking': 'CUSTOM_DEFINE_no_bounds_checking'
|
||||||
|
'freestanding': '_VFREESTANDING'
|
||||||
|
'autofree': '_VAUTOFREE'
|
||||||
|
// CPU
|
||||||
|
'amd64': '__V_amd64'
|
||||||
|
'aarch64': '__V_arm64'
|
||||||
|
'arm64': '__V_arm64' // aarch64 alias
|
||||||
|
'arm32': '__V_arm32'
|
||||||
|
'i386': '__V_x86'
|
||||||
|
'rv64': '__V_rv64'
|
||||||
|
'riscv64': '__V_rv64' // rv64 alias
|
||||||
|
'rv32': '__V_rv32'
|
||||||
|
'riscv32': '__V_rv32' // rv32 alias
|
||||||
|
's390x': '__V_s390x'
|
||||||
|
'ppc64le': '__V_ppc64le'
|
||||||
|
'loongarch64': '__V_loongarch64'
|
||||||
|
'x64': 'TARGET_IS_64BIT'
|
||||||
|
'x32': 'TARGET_IS_32BIT'
|
||||||
|
'little_endian': 'TARGET_ORDER_IS_LITTLE'
|
||||||
|
'big_endian': 'TARGET_ORDER_IS_BIG'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn comptime_if_to_ifdef(name string, the_pref &pref.Preferences) !string {
|
||||||
|
if name == 'fast_math' {
|
||||||
|
return if the_pref.ccompiler_type == .msvc {
|
||||||
|
// turned on by: `-cflags /fp:fast`
|
||||||
|
'_M_FP_FAST'
|
||||||
|
} else {
|
||||||
|
// turned on by: `-cflags -ffast-math`
|
||||||
|
'__FAST_MATH__'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ifdef := system_ident_map[name] {
|
||||||
|
return ifdef
|
||||||
|
}
|
||||||
|
return error('bad os ifdef name `${name}`')
|
||||||
|
}
|
||||||
|
|
|
@ -784,191 +784,6 @@ fn (mut c Checker) evaluate_once_comptime_if_attribute(mut node ast.Attr) bool {
|
||||||
return node.ct_skip
|
return node.ct_skip
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) comptime_if_to_ifdef(name string) !string {
|
|
||||||
match name {
|
|
||||||
// platforms/os-es:
|
|
||||||
'windows' {
|
|
||||||
return '_WIN32'
|
|
||||||
}
|
|
||||||
'ios' {
|
|
||||||
return '__TARGET_IOS__'
|
|
||||||
}
|
|
||||||
'macos' {
|
|
||||||
return '__APPLE__'
|
|
||||||
}
|
|
||||||
'mach' {
|
|
||||||
return '__MACH__'
|
|
||||||
}
|
|
||||||
'darwin' {
|
|
||||||
return '__DARWIN__'
|
|
||||||
}
|
|
||||||
'hpux' {
|
|
||||||
return '__HPUX__'
|
|
||||||
}
|
|
||||||
'gnu' {
|
|
||||||
return '__GNU__'
|
|
||||||
}
|
|
||||||
'qnx' {
|
|
||||||
return '__QNX__'
|
|
||||||
}
|
|
||||||
'linux' {
|
|
||||||
return '__linux__'
|
|
||||||
}
|
|
||||||
'serenity' {
|
|
||||||
return '__serenity__'
|
|
||||||
}
|
|
||||||
'plan9' {
|
|
||||||
return '__plan9__'
|
|
||||||
}
|
|
||||||
'vinix' {
|
|
||||||
return '__vinix__'
|
|
||||||
}
|
|
||||||
'freebsd' {
|
|
||||||
return '__FreeBSD__'
|
|
||||||
}
|
|
||||||
'openbsd' {
|
|
||||||
return '__OpenBSD__'
|
|
||||||
}
|
|
||||||
'netbsd' {
|
|
||||||
return '__NetBSD__'
|
|
||||||
}
|
|
||||||
'bsd' {
|
|
||||||
return '__BSD__'
|
|
||||||
}
|
|
||||||
'dragonfly' {
|
|
||||||
return '__DragonFly__'
|
|
||||||
}
|
|
||||||
'android' {
|
|
||||||
return '__ANDROID__'
|
|
||||||
}
|
|
||||||
'termux' {
|
|
||||||
// Note: termux is running on Android natively so __ANDROID__ will also be defined
|
|
||||||
return '__TERMUX__'
|
|
||||||
}
|
|
||||||
'solaris' {
|
|
||||||
return '__sun'
|
|
||||||
}
|
|
||||||
'haiku' {
|
|
||||||
return '__HAIKU__'
|
|
||||||
}
|
|
||||||
//
|
|
||||||
'js' {
|
|
||||||
return '_VJS'
|
|
||||||
}
|
|
||||||
'wasm32_emscripten' {
|
|
||||||
return '__EMSCRIPTEN__'
|
|
||||||
}
|
|
||||||
'native' {
|
|
||||||
return '_VNATIVE' // when using the native backend, cgen is inactive
|
|
||||||
}
|
|
||||||
// compilers:
|
|
||||||
'gcc' {
|
|
||||||
return '__V_GCC__'
|
|
||||||
}
|
|
||||||
'tinyc' {
|
|
||||||
return '__TINYC__'
|
|
||||||
}
|
|
||||||
'clang' {
|
|
||||||
return '__clang__'
|
|
||||||
}
|
|
||||||
'mingw' {
|
|
||||||
return '__MINGW32__'
|
|
||||||
}
|
|
||||||
'msvc' {
|
|
||||||
return '_MSC_VER'
|
|
||||||
}
|
|
||||||
'cplusplus' {
|
|
||||||
return '__cplusplus'
|
|
||||||
}
|
|
||||||
// other:
|
|
||||||
'threads' {
|
|
||||||
return '__VTHREADS__'
|
|
||||||
}
|
|
||||||
'gcboehm' {
|
|
||||||
return '_VGCBOEHM'
|
|
||||||
}
|
|
||||||
'debug' {
|
|
||||||
return '_VDEBUG'
|
|
||||||
}
|
|
||||||
'prod' {
|
|
||||||
return '_VPROD'
|
|
||||||
}
|
|
||||||
'profile' {
|
|
||||||
return '_VPROFILE'
|
|
||||||
}
|
|
||||||
'test' {
|
|
||||||
return '_VTEST'
|
|
||||||
}
|
|
||||||
'glibc' {
|
|
||||||
return '__GLIBC__'
|
|
||||||
}
|
|
||||||
'prealloc' {
|
|
||||||
return '_VPREALLOC'
|
|
||||||
}
|
|
||||||
'no_bounds_checking' {
|
|
||||||
return 'CUSTOM_DEFINE_no_bounds_checking'
|
|
||||||
}
|
|
||||||
'freestanding' {
|
|
||||||
return '_VFREESTANDING'
|
|
||||||
}
|
|
||||||
'autofree' {
|
|
||||||
return '_VAUTOFREE'
|
|
||||||
}
|
|
||||||
// architectures:
|
|
||||||
'amd64' {
|
|
||||||
return '__V_amd64'
|
|
||||||
}
|
|
||||||
'aarch64', 'arm64' {
|
|
||||||
return '__V_arm64'
|
|
||||||
}
|
|
||||||
'arm32' {
|
|
||||||
return '__V_arm32'
|
|
||||||
}
|
|
||||||
'i386' {
|
|
||||||
return '__V_x86'
|
|
||||||
}
|
|
||||||
'rv64', 'riscv64' {
|
|
||||||
return '__V_rv64'
|
|
||||||
}
|
|
||||||
'rv32', 'riscv32' {
|
|
||||||
return '__V_rv32'
|
|
||||||
}
|
|
||||||
's390x' {
|
|
||||||
return '__V_s390x'
|
|
||||||
}
|
|
||||||
'ppc64le' {
|
|
||||||
return '__V_ppc64le'
|
|
||||||
}
|
|
||||||
'loongarch64' {
|
|
||||||
return '__V_loongarch64'
|
|
||||||
}
|
|
||||||
// bitness:
|
|
||||||
'x64' {
|
|
||||||
return 'TARGET_IS_64BIT'
|
|
||||||
}
|
|
||||||
'x32' {
|
|
||||||
return 'TARGET_IS_32BIT'
|
|
||||||
}
|
|
||||||
// endianness:
|
|
||||||
'little_endian' {
|
|
||||||
return 'TARGET_ORDER_IS_LITTLE'
|
|
||||||
}
|
|
||||||
'big_endian' {
|
|
||||||
return 'TARGET_ORDER_IS_BIG'
|
|
||||||
}
|
|
||||||
'fast_math' {
|
|
||||||
if c.pref.ccompiler_type == .msvc {
|
|
||||||
// turned on by: `-cflags /fp:fast`
|
|
||||||
return '_M_FP_FAST'
|
|
||||||
}
|
|
||||||
// turned on by: `-cflags -ffast-math`
|
|
||||||
return '__FAST_MATH__'
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
return error('bad os ifdef name "${name}"')
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if `ident` is a function generic, such as `T`
|
// check if `ident` is a function generic, such as `T`
|
||||||
fn (mut c Checker) is_generic_ident(ident string) bool {
|
fn (mut c Checker) is_generic_ident(ident string) bool {
|
||||||
if !isnil(c.table.cur_fn) && ident in c.table.cur_fn.generic_names
|
if !isnil(c.table.cur_fn) && ident in c.table.cur_fn.generic_names
|
||||||
|
@ -1141,10 +956,6 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, mut sb strings.Builder) (
|
||||||
should_record_ident = true
|
should_record_ident = true
|
||||||
is_user_ident = true
|
is_user_ident = true
|
||||||
ident_name = cname
|
ident_name = cname
|
||||||
// ifdef := c.comptime_if_to_ifdef(cname, true) or {
|
|
||||||
// c.error(err.msg(), cond.pos)
|
|
||||||
// return false, false
|
|
||||||
//}
|
|
||||||
sb.write_string('defined(CUSTOM_DEFINE_${cname})')
|
sb.write_string('defined(CUSTOM_DEFINE_${cname})')
|
||||||
is_true = cname in c.pref.compile_defines
|
is_true = cname in c.pref.compile_defines
|
||||||
return is_true, false
|
return is_true, false
|
||||||
|
@ -1483,143 +1294,12 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, mut sb strings.Builder) (
|
||||||
should_record_ident = true
|
should_record_ident = true
|
||||||
is_user_ident = false
|
is_user_ident = false
|
||||||
ident_name = cname
|
ident_name = cname
|
||||||
if cname in ast.valid_comptime_if_os {
|
if cname in ast.valid_comptime_not_user_defined {
|
||||||
if cname_enum_val := pref.os_from_string(cname) {
|
if cname == 'threads' {
|
||||||
if cname_enum_val == c.pref.os {
|
|
||||||
is_true = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if cname in ast.valid_comptime_if_compilers {
|
|
||||||
is_true = pref.cc_from_string(cname) == c.pref.ccompiler_type
|
|
||||||
} else if cname in ast.valid_comptime_if_platforms {
|
|
||||||
if cname == 'aarch64' {
|
|
||||||
c.note('use `arm64` instead of `aarch64`', cond.pos)
|
|
||||||
}
|
|
||||||
match cname {
|
|
||||||
'amd64' {
|
|
||||||
is_true = c.pref.arch == .amd64
|
|
||||||
}
|
|
||||||
'i386' {
|
|
||||||
is_true = c.pref.arch == .i386
|
|
||||||
}
|
|
||||||
'aarch64' {
|
|
||||||
is_true = c.pref.arch == .arm64
|
|
||||||
}
|
|
||||||
'arm64' {
|
|
||||||
is_true = c.pref.arch == .arm64
|
|
||||||
}
|
|
||||||
'arm32' {
|
|
||||||
is_true = c.pref.arch == .arm32
|
|
||||||
}
|
|
||||||
'rv64' {
|
|
||||||
is_true = c.pref.arch == .rv64
|
|
||||||
}
|
|
||||||
'rv32' {
|
|
||||||
is_true = c.pref.arch == .rv32
|
|
||||||
}
|
|
||||||
's390x' {
|
|
||||||
is_true = c.pref.arch == .s390x
|
|
||||||
}
|
|
||||||
'ppc64le' {
|
|
||||||
is_true = c.pref.arch == .ppc64le
|
|
||||||
}
|
|
||||||
'loongarch64' {
|
|
||||||
is_true = c.pref.arch == .loongarch64
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.error('invalid \$if condition: unknown platforms `${cname}`',
|
|
||||||
cond.pos)
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if cname in ast.valid_comptime_if_cpu_features {
|
|
||||||
match cname {
|
|
||||||
'x64' {
|
|
||||||
is_true = c.pref.m64
|
|
||||||
}
|
|
||||||
'x32' {
|
|
||||||
is_true = !c.pref.m64
|
|
||||||
}
|
|
||||||
'little_endian' {
|
|
||||||
is_true = $if little_endian { true } $else { false }
|
|
||||||
}
|
|
||||||
'big_endian' {
|
|
||||||
is_true = $if big_endian { true } $else { false }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.error('invalid \$if condition: unknown cpu_features `${cname}`',
|
|
||||||
cond.pos)
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if cname in ast.valid_comptime_if_other {
|
|
||||||
match cname {
|
|
||||||
'apk' {
|
|
||||||
is_true = c.pref.is_apk
|
|
||||||
}
|
|
||||||
'js' {
|
|
||||||
is_true = c.pref.backend.is_js()
|
|
||||||
}
|
|
||||||
'debug' {
|
|
||||||
is_true = c.pref.is_debug
|
|
||||||
}
|
|
||||||
'prod' {
|
|
||||||
is_true = c.pref.is_prod
|
|
||||||
}
|
|
||||||
'test' {
|
|
||||||
is_true = c.pref.is_test
|
|
||||||
}
|
|
||||||
'glibc' {
|
|
||||||
is_true = c.pref.is_glibc
|
|
||||||
}
|
|
||||||
'prealloc' {
|
|
||||||
is_true = c.pref.prealloc
|
|
||||||
}
|
|
||||||
'no_bounds_checking' {
|
|
||||||
is_true = c.pref.no_bounds_checking
|
|
||||||
}
|
|
||||||
'freestanding' {
|
|
||||||
is_true = c.pref.is_bare && !c.pref.output_cross_c
|
|
||||||
}
|
|
||||||
'threads' {
|
|
||||||
is_true = c.table.gostmts > 0
|
is_true = c.table.gostmts > 0
|
||||||
}
|
} else {
|
||||||
'js_node' {
|
is_true = ast.eval_comptime_not_user_defined_ident(cname, c.pref) or {
|
||||||
is_true = c.pref.backend == .js_node
|
c.error(err.msg(), cond.pos)
|
||||||
}
|
|
||||||
'js_browser' {
|
|
||||||
is_true = c.pref.backend == .js_browser
|
|
||||||
}
|
|
||||||
'js_freestanding' {
|
|
||||||
is_true = c.pref.backend == .js_freestanding
|
|
||||||
}
|
|
||||||
'interpreter' {
|
|
||||||
is_true = c.pref.backend == .interpret
|
|
||||||
}
|
|
||||||
'es5' {
|
|
||||||
is_true = c.pref.output_es5
|
|
||||||
}
|
|
||||||
'profile' {
|
|
||||||
is_true = c.pref.is_prof
|
|
||||||
}
|
|
||||||
'wasm32' {
|
|
||||||
is_true = c.pref.arch == .wasm32
|
|
||||||
}
|
|
||||||
'wasm32_wasi' {
|
|
||||||
is_true = c.pref.os == .wasm32_wasi
|
|
||||||
}
|
|
||||||
'fast_math' {
|
|
||||||
is_true = c.pref.fast_math
|
|
||||||
}
|
|
||||||
'native' {
|
|
||||||
is_true = c.pref.backend == .native
|
|
||||||
}
|
|
||||||
'autofree' {
|
|
||||||
is_true = c.pref.autofree
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.error('invalid \$if condition: unknown other indent `${cname}`',
|
|
||||||
cond.pos)
|
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1655,7 +1335,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, mut sb strings.Builder) (
|
||||||
c.error('invalid \$if condition: unknown indent `${cname}`', cond.pos)
|
c.error('invalid \$if condition: unknown indent `${cname}`', cond.pos)
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
if ifdef := c.comptime_if_to_ifdef(cname) {
|
if ifdef := ast.comptime_if_to_ifdef(cname, c.pref) {
|
||||||
sb.write_string('defined(${ifdef})')
|
sb.write_string('defined(${ifdef})')
|
||||||
} else {
|
} else {
|
||||||
sb.write_string('${is_true}')
|
sb.write_string('${is_true}')
|
||||||
|
|
|
@ -51,6 +51,8 @@ pub mut:
|
||||||
wsinfix_depth int
|
wsinfix_depth int
|
||||||
format_state FormatState
|
format_state FormatState
|
||||||
source_text string // can be set by `echo "println('hi')" | v fmt`, i.e. when processing source not from a file, but from stdin. In this case, it will contain the entire input text. You can use f.file.path otherwise, and read from that file.
|
source_text string // can be set by `echo "println('hi')" | v fmt`, i.e. when processing source not from a file, but from stdin. In this case, it will contain the entire input text. You can use f.file.path otherwise, and read from that file.
|
||||||
|
global_processed_imports []string
|
||||||
|
branch_processed_imports []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@[params]
|
@[params]
|
||||||
|
@ -317,12 +319,17 @@ pub fn (mut f Fmt) import_stmt(imp ast.Import) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
imp_stmt := f.imp_stmt_str(imp)
|
imp_stmt := f.imp_stmt_str(imp)
|
||||||
if imp_stmt in f.processed_imports {
|
if imp_stmt in f.global_processed_imports
|
||||||
|
|| (f.inside_comptime_if && imp_stmt in f.branch_processed_imports) {
|
||||||
// Skip duplicates.
|
// Skip duplicates.
|
||||||
f.import_comments(imp.next_comments)
|
f.import_comments(imp.next_comments)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.processed_imports << imp_stmt
|
if f.inside_comptime_if {
|
||||||
|
f.branch_processed_imports << imp_stmt
|
||||||
|
} else {
|
||||||
|
f.global_processed_imports << imp_stmt
|
||||||
|
}
|
||||||
if !f.format_state.is_vfmt_on {
|
if !f.format_state.is_vfmt_on {
|
||||||
original_imp_line := f.get_source_lines()#[imp.pos.line_nr..imp.pos.last_line + 1].join('\n')
|
original_imp_line := f.get_source_lines()#[imp.pos.line_nr..imp.pos.last_line + 1].join('\n')
|
||||||
// Same line comments(`imp.comments`) are included in the `original_imp_line`.
|
// Same line comments(`imp.comments`) are included in the `original_imp_line`.
|
||||||
|
@ -1070,7 +1077,7 @@ pub fn (mut f Fmt) enum_decl(node ast.EnumDecl) {
|
||||||
f.writeln('')
|
f.writeln('')
|
||||||
f.comments(field.next_comments, has_nl: true, level: .indent)
|
f.comments(field.next_comments, has_nl: true, level: .indent)
|
||||||
}
|
}
|
||||||
f.writeln('}\n')
|
f.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||||
|
@ -2354,6 +2361,7 @@ pub fn (mut f Fmt) if_expr(node ast.IfExpr) {
|
||||||
start_len := f.line_len
|
start_len := f.line_len
|
||||||
for {
|
for {
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
|
f.branch_processed_imports.clear()
|
||||||
mut sum_len := 0
|
mut sum_len := 0
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
// `else`, close previous branch
|
// `else`, close previous branch
|
||||||
|
|
16
vlib/v/fmt/tests/comptime_if_top_enum_empty_line_keep.vv
Normal file
16
vlib/v/fmt/tests/comptime_if_top_enum_empty_line_keep.vv
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
$if new_c_1 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_a
|
||||||
|
enum1_b
|
||||||
|
}
|
||||||
|
} $else $if new_c_2 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_c
|
||||||
|
enum1_d
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_e
|
||||||
|
enum1_f
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ pub enum PubEnum {
|
||||||
foo
|
foo
|
||||||
bar
|
bar
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PrivateEnum {
|
enum PrivateEnum {
|
||||||
foo
|
foo
|
||||||
bar
|
bar
|
||||||
|
|
|
@ -331,18 +331,8 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.TypeDecl, map[string]ast.StructDecl) {
|
fn all_global_decl_in_stmts(stmts []ast.Stmt, mut all_fns map[string]ast.FnDecl, mut all_consts map[string]ast.ConstField, mut all_globals map[string]ast.GlobalField, mut all_decltypes map[string]ast.TypeDecl, mut all_structs map[string]ast.StructDecl) {
|
||||||
util.timing_start(@METHOD)
|
for node in stmts {
|
||||||
defer {
|
|
||||||
util.timing_measure(@METHOD)
|
|
||||||
}
|
|
||||||
mut all_fns := map[string]ast.FnDecl{}
|
|
||||||
mut all_consts := map[string]ast.ConstField{}
|
|
||||||
mut all_globals := map[string]ast.GlobalField{}
|
|
||||||
mut all_decltypes := map[string]ast.TypeDecl{}
|
|
||||||
mut all_structs := map[string]ast.StructDecl{}
|
|
||||||
for i in 0 .. ast_files.len {
|
|
||||||
for node in ast_files[i].stmts {
|
|
||||||
match node {
|
match node {
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
fkey := node.fkey()
|
fkey := node.fkey()
|
||||||
|
@ -370,9 +360,49 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast
|
||||||
all_decltypes[node.name] = node
|
all_decltypes[node.name] = node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast.ExprStmt {
|
||||||
|
match node.expr {
|
||||||
|
ast.IfExpr {
|
||||||
|
if node.expr.is_comptime {
|
||||||
|
// top level comptime $if
|
||||||
|
for branch in node.expr.branches {
|
||||||
|
all_global_decl_in_stmts(branch.stmts, mut all_fns, mut
|
||||||
|
all_consts, mut all_globals, mut all_decltypes, mut
|
||||||
|
all_structs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.MatchExpr {
|
||||||
|
if node.expr.is_comptime {
|
||||||
|
// top level comptime $match
|
||||||
|
for branch in node.expr.branches {
|
||||||
|
all_global_decl_in_stmts(branch.stmts, mut all_fns, mut
|
||||||
|
all_consts, mut all_globals, mut all_decltypes, mut
|
||||||
|
all_structs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.TypeDecl, map[string]ast.StructDecl) {
|
||||||
|
util.timing_start(@METHOD)
|
||||||
|
defer {
|
||||||
|
util.timing_measure(@METHOD)
|
||||||
|
}
|
||||||
|
mut all_fns := map[string]ast.FnDecl{}
|
||||||
|
mut all_consts := map[string]ast.ConstField{}
|
||||||
|
mut all_globals := map[string]ast.GlobalField{}
|
||||||
|
mut all_decltypes := map[string]ast.TypeDecl{}
|
||||||
|
mut all_structs := map[string]ast.StructDecl{}
|
||||||
|
for i in 0 .. ast_files.len {
|
||||||
|
all_global_decl_in_stmts(ast_files[i].stmts, mut all_fns, mut all_consts, mut
|
||||||
|
all_globals, mut all_decltypes, mut all_structs)
|
||||||
}
|
}
|
||||||
return all_fns, all_consts, all_globals, all_decltypes, all_structs
|
return all_fns, all_consts, all_globals, all_decltypes, all_structs
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,10 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
||||||
// p.warn('enum val $val')
|
// p.warn('enum val $val')
|
||||||
if p.tok.kind == .assign {
|
if p.tok.kind == .assign {
|
||||||
p.next()
|
p.next()
|
||||||
|
old_assign_rhs := p.inside_assign_rhs
|
||||||
|
p.inside_assign_rhs = true
|
||||||
expr = p.expr(0)
|
expr = p.expr(0)
|
||||||
|
p.inside_assign_rhs = old_assign_rhs
|
||||||
has_expr = true
|
has_expr = true
|
||||||
uses_exprs = true
|
uses_exprs = true
|
||||||
}
|
}
|
||||||
|
@ -225,7 +228,8 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
})
|
})
|
||||||
|
|
||||||
if idx in [ast.string_type_idx, ast.rune_type_idx, ast.array_type_idx, ast.map_type_idx] {
|
if idx in [ast.string_type_idx, ast.rune_type_idx, ast.array_type_idx, ast.map_type_idx]
|
||||||
|
&& !p.pref.is_fmt {
|
||||||
p.error_with_pos('cannot register enum `${name}`, another type with this name exists',
|
p.error_with_pos('cannot register enum `${name}`, another type with this name exists',
|
||||||
end_pos)
|
end_pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,6 +359,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
check_name = if language == .js { p.check_js_name() } else { p.check_name() }
|
check_name = if language == .js { p.check_js_name() } else { p.check_name() }
|
||||||
name = check_name
|
name = check_name
|
||||||
}
|
}
|
||||||
|
|
||||||
if language == .v && !p.pref.translated && !p.is_translated && !p.builtin_mod
|
if language == .v && !p.pref.translated && !p.is_translated && !p.builtin_mod
|
||||||
&& util.contains_capital(check_name) {
|
&& util.contains_capital(check_name) {
|
||||||
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
||||||
|
@ -655,6 +656,7 @@ run them via `v file.v` instead',
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
// Body
|
// Body
|
||||||
|
keep_fn_name := p.cur_fn_name
|
||||||
p.cur_fn_name = name
|
p.cur_fn_name = name
|
||||||
mut stmts := []ast.Stmt{}
|
mut stmts := []ast.Stmt{}
|
||||||
body_start_pos := p.tok.pos()
|
body_start_pos := p.tok.pos()
|
||||||
|
@ -671,6 +673,7 @@ run them via `v file.v` instead',
|
||||||
p.inside_unsafe_fn = false
|
p.inside_unsafe_fn = false
|
||||||
p.inside_fn = false
|
p.inside_fn = false
|
||||||
}
|
}
|
||||||
|
p.cur_fn_name = keep_fn_name
|
||||||
if !no_body && are_params_type_only {
|
if !no_body && are_params_type_only {
|
||||||
p.error_with_pos('functions with type only params can not have bodies', body_start_pos)
|
p.error_with_pos('functions with type only params can not have bodies', body_start_pos)
|
||||||
return ast.FnDecl{
|
return ast.FnDecl{
|
||||||
|
|
|
@ -5,6 +5,7 @@ module parser
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.token
|
import v.token
|
||||||
|
import v.pkgconfig
|
||||||
|
|
||||||
fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
was_inside_if_expr := p.inside_if_expr
|
was_inside_if_expr := p.inside_if_expr
|
||||||
|
@ -25,6 +26,8 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
mut has_else := false
|
mut has_else := false
|
||||||
mut comments := []ast.Comment{}
|
mut comments := []ast.Comment{}
|
||||||
mut prev_guard := false
|
mut prev_guard := false
|
||||||
|
mut comptime_skip_curr_stmts := false
|
||||||
|
mut comptime_has_true_branch := false
|
||||||
for p.tok.kind in [.key_if, .key_else] {
|
for p.tok.kind in [.key_if, .key_else] {
|
||||||
p.inside_if = true
|
p.inside_if = true
|
||||||
if is_comptime {
|
if is_comptime {
|
||||||
|
@ -58,6 +61,16 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
is_special: true
|
is_special: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if is_comptime && comptime_has_true_branch && !p.pref.is_fmt
|
||||||
|
&& !p.pref.output_cross_c {
|
||||||
|
p.skip_scope()
|
||||||
|
branches << ast.IfBranch{
|
||||||
|
pos: start_pos.extend(end_pos)
|
||||||
|
body_pos: body_pos.extend(p.tok.pos())
|
||||||
|
comments: comments
|
||||||
|
scope: p.scope
|
||||||
|
}
|
||||||
|
} else {
|
||||||
branches << ast.IfBranch{
|
branches << ast.IfBranch{
|
||||||
stmts: p.parse_block_no_scope(false)
|
stmts: p.parse_block_no_scope(false)
|
||||||
pos: start_pos.extend(end_pos)
|
pos: start_pos.extend(end_pos)
|
||||||
|
@ -65,6 +78,7 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
comments: comments
|
comments: comments
|
||||||
scope: p.scope
|
scope: p.scope
|
||||||
}
|
}
|
||||||
|
}
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
comments = []
|
comments = []
|
||||||
break
|
break
|
||||||
|
@ -114,7 +128,10 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
comments << p.eat_comments()
|
comments << p.eat_comments()
|
||||||
p.check(.decl_assign)
|
p.check(.decl_assign)
|
||||||
comments << p.eat_comments()
|
comments << p.eat_comments()
|
||||||
|
old_assign_rhs := p.inside_assign_rhs
|
||||||
|
p.inside_assign_rhs = true
|
||||||
expr := p.expr(0)
|
expr := p.expr(0)
|
||||||
|
p.inside_assign_rhs = old_assign_rhs
|
||||||
if expr !in [ast.CallExpr, ast.IndexExpr, ast.PrefixExpr, ast.SelectorExpr, ast.Ident] {
|
if expr !in [ast.CallExpr, ast.IndexExpr, ast.PrefixExpr, ast.SelectorExpr, ast.Ident] {
|
||||||
p.error_with_pos('if guard condition expression is illegal, it should return an Option',
|
p.error_with_pos('if guard condition expression is illegal, it should return an Option',
|
||||||
expr.pos())
|
expr.pos())
|
||||||
|
@ -141,6 +158,12 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
p.comptime_if_cond = true
|
p.comptime_if_cond = true
|
||||||
p.inside_if_cond = true
|
p.inside_if_cond = true
|
||||||
cond = p.expr(0)
|
cond = p.expr(0)
|
||||||
|
if is_comptime && p.is_in_top_level_comptime(p.inside_assign_rhs) {
|
||||||
|
comptime_skip_curr_stmts = !p.comptime_if_cond(mut cond)
|
||||||
|
if !comptime_skip_curr_stmts {
|
||||||
|
comptime_has_true_branch = true
|
||||||
|
}
|
||||||
|
}
|
||||||
if mut cond is ast.InfixExpr && !is_comptime {
|
if mut cond is ast.InfixExpr && !is_comptime {
|
||||||
if cond.op in [.key_is, .not_is] {
|
if cond.op in [.key_is, .not_is] {
|
||||||
if mut cond.left is ast.Ident {
|
if mut cond.left is ast.Ident {
|
||||||
|
@ -170,6 +193,16 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
return ast.IfExpr{}
|
return ast.IfExpr{}
|
||||||
}
|
}
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
|
if is_comptime && comptime_skip_curr_stmts && !p.pref.is_fmt && !p.pref.output_cross_c {
|
||||||
|
p.skip_scope()
|
||||||
|
branches << ast.IfBranch{
|
||||||
|
cond: cond
|
||||||
|
pos: start_pos.extend(end_pos)
|
||||||
|
body_pos: body_pos.extend(p.prev_tok.pos())
|
||||||
|
comments: comments
|
||||||
|
scope: p.scope
|
||||||
|
}
|
||||||
|
} else {
|
||||||
stmts := p.parse_block_no_scope(false)
|
stmts := p.parse_block_no_scope(false)
|
||||||
branches << ast.IfBranch{
|
branches << ast.IfBranch{
|
||||||
cond: cond
|
cond: cond
|
||||||
|
@ -179,6 +212,7 @@ fn (mut p Parser) if_expr(is_comptime bool, is_expr bool) ast.IfExpr {
|
||||||
comments: comments
|
comments: comments
|
||||||
scope: p.scope
|
scope: p.scope
|
||||||
}
|
}
|
||||||
|
}
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
if is_guard {
|
if is_guard {
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
|
@ -570,3 +604,167 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
|
||||||
has_exception: has_else || has_timeout
|
has_exception: has_else || has_timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) comptime_if_cond(mut cond ast.Expr) bool {
|
||||||
|
mut is_true := false
|
||||||
|
match mut cond {
|
||||||
|
ast.BoolLiteral {
|
||||||
|
return cond.val
|
||||||
|
}
|
||||||
|
ast.ParExpr {
|
||||||
|
return p.comptime_if_cond(mut cond.expr)
|
||||||
|
}
|
||||||
|
ast.PrefixExpr {
|
||||||
|
if cond.op != .not {
|
||||||
|
p.error('invalid \$if prefix operator, only allow `!`.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !p.comptime_if_cond(mut cond.right)
|
||||||
|
}
|
||||||
|
ast.PostfixExpr {
|
||||||
|
if cond.op != .question {
|
||||||
|
p.error('invalid \$if postfix operator, only allow `?`.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if cond.expr !is ast.Ident {
|
||||||
|
p.error('invalid \$if postfix condition, only allow `Indent`.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
cname := (cond.expr as ast.Ident).name
|
||||||
|
return cname in p.pref.compile_defines
|
||||||
|
}
|
||||||
|
ast.InfixExpr {
|
||||||
|
match cond.op {
|
||||||
|
.and, .logical_or {
|
||||||
|
l := p.comptime_if_cond(mut cond.left)
|
||||||
|
r := p.comptime_if_cond(mut cond.right)
|
||||||
|
// if at least one of the cond has `keep_stmts`, we should keep stmts
|
||||||
|
return if cond.op == .and { l && r } else { l || r }
|
||||||
|
}
|
||||||
|
.eq, .ne, .gt, .lt, .ge, .le {
|
||||||
|
match mut cond.left {
|
||||||
|
ast.Ident {
|
||||||
|
// $if version == 2
|
||||||
|
match mut cond.right {
|
||||||
|
ast.StringLiteral {
|
||||||
|
match cond.op {
|
||||||
|
.eq {
|
||||||
|
is_true = cond.left.str() == cond.right.str()
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
is_true = cond.left.str() != cond.right.str()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('string type only support `==` and `!=` operator')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.IntegerLiteral {
|
||||||
|
match cond.op {
|
||||||
|
.eq {
|
||||||
|
is_true = cond.left.str().i64() == cond.right.val.i64()
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
is_true = cond.left.str().i64() != cond.right.val.i64()
|
||||||
|
}
|
||||||
|
.gt {
|
||||||
|
is_true = cond.left.str().i64() > cond.right.val.i64()
|
||||||
|
}
|
||||||
|
.lt {
|
||||||
|
is_true = cond.left.str().i64() < cond.right.val.i64()
|
||||||
|
}
|
||||||
|
.ge {
|
||||||
|
is_true = cond.left.str().i64() >= cond.right.val.i64()
|
||||||
|
}
|
||||||
|
.le {
|
||||||
|
is_true = cond.left.str().i64() <= cond.right.val.i64()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('int type only support `==` `!=` `>` `<` `>=` and `<=` operator')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.BoolLiteral {
|
||||||
|
match cond.op {
|
||||||
|
.eq {
|
||||||
|
is_true = cond.left.str().bool() == cond.right.val
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
is_true = cond.left.str().bool() != cond.right.val
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('bool type only support `==` and `!=` operator')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('compare only support string int and bool type')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return is_true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('invalid \$if condition')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.error('invalid \$if condition')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('invalid \$if operator: ${cond.op}')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Ident {
|
||||||
|
cname := cond.name
|
||||||
|
if cname in ast.valid_comptime_not_user_defined {
|
||||||
|
if cname == 'threads' {
|
||||||
|
is_true = p.table.gostmts > 0
|
||||||
|
} else {
|
||||||
|
is_true = ast.eval_comptime_not_user_defined_ident(cname, p.pref) or {
|
||||||
|
p.error(err.msg())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.error('invalid \$if condition: unknown indent `${cname}`')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return is_true
|
||||||
|
}
|
||||||
|
ast.ComptimeCall {
|
||||||
|
if cond.kind == .pkgconfig {
|
||||||
|
if mut m := pkgconfig.main([cond.args_var]) {
|
||||||
|
if _ := m.run() {
|
||||||
|
is_true = true
|
||||||
|
} else {
|
||||||
|
// pkgconfig not found, do not issue error, just set false
|
||||||
|
is_true = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.error(err.msg())
|
||||||
|
is_true = false
|
||||||
|
}
|
||||||
|
return is_true
|
||||||
|
}
|
||||||
|
if cond.kind == .d {
|
||||||
|
is_true = cond.compile_value.bool()
|
||||||
|
return is_true
|
||||||
|
}
|
||||||
|
p.error('invalid \$if condition: unknown ComptimeCall')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.error('invalid \$if condition ${cond}')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_true
|
||||||
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ mut:
|
||||||
generic_type_level int // to avoid infinite recursion segfaults due to compiler bugs in ensure_type_exists
|
generic_type_level int // to avoid infinite recursion segfaults due to compiler bugs in ensure_type_exists
|
||||||
main_already_defined bool // TODO move to checker
|
main_already_defined bool // TODO move to checker
|
||||||
is_vls bool
|
is_vls bool
|
||||||
|
inside_import_section bool
|
||||||
pub mut:
|
pub mut:
|
||||||
scanner &scanner.Scanner = unsafe { nil }
|
scanner &scanner.Scanner = unsafe { nil }
|
||||||
table &ast.Table = unsafe { nil }
|
table &ast.Table = unsafe { nil }
|
||||||
|
@ -290,6 +291,7 @@ pub fn (mut p Parser) parse() &ast.File {
|
||||||
} else {
|
} else {
|
||||||
stmts << module_decl
|
stmts << module_decl
|
||||||
}
|
}
|
||||||
|
p.inside_import_section = true
|
||||||
// imports
|
// imports
|
||||||
for {
|
for {
|
||||||
if p.tok.kind == .key_import {
|
if p.tok.kind == .key_import {
|
||||||
|
@ -451,6 +453,12 @@ fn (mut p Parser) parse_block() []ast.Stmt {
|
||||||
return stmts
|
return stmts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut p Parser) is_in_top_level_comptime(inside_assign_rhs bool) bool {
|
||||||
|
// TODO: find out a better way detect we are in top level.
|
||||||
|
return p.cur_fn_name.len == 0 && p.inside_ct_if_expr && !inside_assign_rhs && !p.script_mode
|
||||||
|
&& p.tok.kind != .name
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut p Parser) parse_block_no_scope(is_top_level bool) []ast.Stmt {
|
fn (mut p Parser) parse_block_no_scope(is_top_level bool) []ast.Stmt {
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
mut stmts := []ast.Stmt{cap: 20}
|
mut stmts := []ast.Stmt{cap: 20}
|
||||||
|
@ -459,7 +467,12 @@ fn (mut p Parser) parse_block_no_scope(is_top_level bool) []ast.Stmt {
|
||||||
if p.tok.kind != .rcbr {
|
if p.tok.kind != .rcbr {
|
||||||
mut count := 0
|
mut count := 0
|
||||||
for p.tok.kind !in [.eof, .rcbr] {
|
for p.tok.kind !in [.eof, .rcbr] {
|
||||||
|
if p.is_in_top_level_comptime(old_assign_rhs) {
|
||||||
|
// top level `$if cond { println() }` should goto `p.stmt()`
|
||||||
|
stmts << p.top_stmt()
|
||||||
|
} else {
|
||||||
stmts << p.stmt(is_top_level)
|
stmts << p.stmt(is_top_level)
|
||||||
|
}
|
||||||
count++
|
count++
|
||||||
if count % 100000 == 0 {
|
if count % 100000 == 0 {
|
||||||
if p.is_vls {
|
if p.is_vls {
|
||||||
|
@ -617,6 +630,10 @@ fn (p &Parser) trace_parser(label string) {
|
||||||
fn (mut p Parser) top_stmt() ast.Stmt {
|
fn (mut p Parser) top_stmt() ast.Stmt {
|
||||||
p.trace_parser('top_stmt')
|
p.trace_parser('top_stmt')
|
||||||
for {
|
for {
|
||||||
|
if p.tok.kind !in [.key_import, .comment, .dollar] {
|
||||||
|
// import section should only prepend by `import`, `comment` or `$if`.
|
||||||
|
p.inside_import_section = false
|
||||||
|
}
|
||||||
match p.tok.kind {
|
match p.tok.kind {
|
||||||
.key_pub {
|
.key_pub {
|
||||||
match p.peek_tok.kind {
|
match p.peek_tok.kind {
|
||||||
|
@ -660,8 +677,10 @@ fn (mut p Parser) top_stmt() ast.Stmt {
|
||||||
return p.interface_decl()
|
return p.interface_decl()
|
||||||
}
|
}
|
||||||
.key_import {
|
.key_import {
|
||||||
|
if !p.inside_import_section {
|
||||||
p.error_with_pos('`import x` can only be declared at the beginning of the file',
|
p.error_with_pos('`import x` can only be declared at the beginning of the file',
|
||||||
p.tok.pos())
|
p.tok.pos())
|
||||||
|
}
|
||||||
return p.import_stmt()
|
return p.import_stmt()
|
||||||
}
|
}
|
||||||
.key_global {
|
.key_global {
|
||||||
|
@ -677,13 +696,15 @@ fn (mut p Parser) top_stmt() ast.Stmt {
|
||||||
return p.struct_decl(false)
|
return p.struct_decl(false)
|
||||||
}
|
}
|
||||||
.dollar {
|
.dollar {
|
||||||
if p.peek_tok.kind == .eof {
|
match p.peek_tok.kind {
|
||||||
|
.eof {
|
||||||
return p.unexpected(got: 'eof')
|
return p.unexpected(got: 'eof')
|
||||||
}
|
}
|
||||||
if p.peek_tok.kind == .key_for {
|
.key_for {
|
||||||
comptime_for_stmt := p.comptime_for()
|
comptime_for_stmt := p.comptime_for()
|
||||||
return p.other_stmts(comptime_for_stmt)
|
return p.other_stmts(comptime_for_stmt)
|
||||||
} else if p.peek_tok.kind == .key_if {
|
}
|
||||||
|
.key_if {
|
||||||
if_expr := p.if_expr(true, false)
|
if_expr := p.if_expr(true, false)
|
||||||
cur_stmt := ast.ExprStmt{
|
cur_stmt := ast.ExprStmt{
|
||||||
expr: if_expr
|
expr: if_expr
|
||||||
|
@ -694,10 +715,35 @@ fn (mut p Parser) top_stmt() ast.Stmt {
|
||||||
} else {
|
} else {
|
||||||
return p.other_stmts(cur_stmt)
|
return p.other_stmts(cur_stmt)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.key_match {
|
||||||
|
mut pos := p.tok.pos()
|
||||||
|
expr := p.match_expr(true)
|
||||||
|
pos.update_last_line(p.prev_tok.line_nr)
|
||||||
|
return ast.ExprStmt{
|
||||||
|
expr: expr
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
// handles $dbg directly without registering token
|
||||||
|
if p.peek_tok.lit == 'dbg' {
|
||||||
|
return p.dbg_stmt()
|
||||||
} else {
|
} else {
|
||||||
|
mut pos := p.tok.pos()
|
||||||
|
expr := p.expr(0)
|
||||||
|
pos.update_last_line(p.prev_tok.line_nr)
|
||||||
|
return ast.ExprStmt{
|
||||||
|
expr: expr
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
return p.unexpected()
|
return p.unexpected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.hash {
|
.hash {
|
||||||
return p.hash()
|
return p.hash()
|
||||||
}
|
}
|
||||||
|
@ -2470,7 +2516,10 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
|
||||||
}
|
}
|
||||||
mut expr := ast.Expr{}
|
mut expr := ast.Expr{}
|
||||||
if !is_virtual_c_const {
|
if !is_virtual_c_const {
|
||||||
|
old_inside_assign_rhs := p.inside_assign_rhs
|
||||||
|
p.inside_assign_rhs = true
|
||||||
expr = p.expr(0)
|
expr = p.expr(0)
|
||||||
|
p.inside_assign_rhs = old_inside_assign_rhs
|
||||||
}
|
}
|
||||||
if is_block {
|
if is_block {
|
||||||
end_comments << p.eat_comments(same_line: true)
|
end_comments << p.eat_comments(same_line: true)
|
||||||
|
@ -2596,7 +2645,10 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
||||||
mut typ_pos := token.Pos{}
|
mut typ_pos := token.Pos{}
|
||||||
if has_expr {
|
if has_expr {
|
||||||
p.next() // =
|
p.next() // =
|
||||||
|
old_assign_rhs := p.inside_assign_rhs
|
||||||
|
p.inside_assign_rhs = true
|
||||||
expr = p.expr(0)
|
expr = p.expr(0)
|
||||||
|
p.inside_assign_rhs = old_assign_rhs
|
||||||
match mut expr {
|
match mut expr {
|
||||||
ast.CastExpr, ast.StructInit, ast.ArrayInit, ast.ChanInit {
|
ast.CastExpr, ast.StructInit, ast.ArrayInit, ast.ChanInit {
|
||||||
typ = expr.typ
|
typ = expr.typ
|
||||||
|
@ -2759,7 +2811,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||||
}
|
}
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
})
|
})
|
||||||
if typ in [ast.string_type_idx, ast.rune_type_idx, ast.array_type_idx, ast.map_type_idx] {
|
if typ in [ast.string_type_idx, ast.rune_type_idx, ast.array_type_idx, ast.map_type_idx]
|
||||||
|
&& !p.pref.is_fmt {
|
||||||
p.error_with_pos('cannot register sum type `${name}`, another type with this name exists',
|
p.error_with_pos('cannot register sum type `${name}`, another type with this name exists',
|
||||||
name_pos)
|
name_pos)
|
||||||
return ast.SumTypeDecl{}
|
return ast.SumTypeDecl{}
|
||||||
|
@ -2806,7 +2859,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
})
|
})
|
||||||
type_end_pos := p.prev_tok.pos()
|
type_end_pos := p.prev_tok.pos()
|
||||||
if idx in [ast.string_type_idx, ast.rune_type_idx, ast.array_type_idx, ast.map_type_idx] {
|
if idx in [ast.string_type_idx, ast.rune_type_idx, ast.array_type_idx, ast.map_type_idx]
|
||||||
|
&& !p.pref.is_fmt {
|
||||||
p.error_with_pos('cannot register alias `${name}`, another type with this name exists',
|
p.error_with_pos('cannot register alias `${name}`, another type with this name exists',
|
||||||
name_pos)
|
name_pos)
|
||||||
return ast.AliasTypeDecl{}
|
return ast.AliasTypeDecl{}
|
||||||
|
@ -3017,3 +3071,23 @@ fn (mut p Parser) add_defer_var(ident ast.Ident) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip `{...}`
|
||||||
|
fn (mut p Parser) skip_scope() {
|
||||||
|
mut br_cnt := 0
|
||||||
|
for {
|
||||||
|
match p.tok.kind {
|
||||||
|
.lcbr { br_cnt++ }
|
||||||
|
.rcbr { br_cnt-- }
|
||||||
|
.eof { break }
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
if br_cnt == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
if p.tok.kind == .rcbr {
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -338,7 +338,10 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
|
||||||
if p.tok.kind == .assign {
|
if p.tok.kind == .assign {
|
||||||
// Default value
|
// Default value
|
||||||
p.next()
|
p.next()
|
||||||
|
old_assign_rhs := p.inside_assign_rhs
|
||||||
|
p.inside_assign_rhs = true
|
||||||
default_expr = p.expr(0)
|
default_expr = p.expr(0)
|
||||||
|
p.inside_assign_rhs = old_assign_rhs
|
||||||
match mut default_expr {
|
match mut default_expr {
|
||||||
ast.EnumVal { default_expr.typ = typ }
|
ast.EnumVal { default_expr.typ = typ }
|
||||||
// TODO: implement all types??
|
// TODO: implement all types??
|
||||||
|
@ -457,7 +460,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// allow duplicate c struct declarations
|
// allow duplicate c struct declarations
|
||||||
if ret == -1 && language != .c {
|
if ret == -1 && language != .c && !p.pref.is_fmt {
|
||||||
p.error_with_pos('cannot register struct `${name}`, another type with this name exists',
|
p.error_with_pos('cannot register struct `${name}`, another type with this name exists',
|
||||||
name_pos)
|
name_pos)
|
||||||
return ast.StructDecl{}
|
return ast.StructDecl{}
|
||||||
|
@ -671,7 +674,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
}
|
}
|
||||||
language: language
|
language: language
|
||||||
)
|
)
|
||||||
if reg_idx == -1 {
|
if reg_idx == -1 && !p.pref.is_fmt {
|
||||||
p.error_with_pos('cannot register interface `${interface_name}`, another type with this name exists',
|
p.error_with_pos('cannot register interface `${interface_name}`, another type with this name exists',
|
||||||
name_pos)
|
name_pos)
|
||||||
return ast.InterfaceDecl{}
|
return ast.InterfaceDecl{}
|
||||||
|
|
94
vlib/v/tests/comptime/comptime_if_top_1_test.v
Normal file
94
vlib/v/tests/comptime/comptime_if_top_1_test.v
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// vtest vflags: -d new_1 -d new_a_1 -d new_b_1 -d new_c_1 -d new_d_1 -d new_e_1
|
||||||
|
module main
|
||||||
|
|
||||||
|
// this is comment, should skip
|
||||||
|
|
||||||
|
$if new_1 ? {
|
||||||
|
// this is comment, should skip
|
||||||
|
import os
|
||||||
|
// this is comment, should skip
|
||||||
|
} $else $if new_2 ? {
|
||||||
|
// this is comment, should skip
|
||||||
|
import math
|
||||||
|
// this is comment, should skip
|
||||||
|
} $else {
|
||||||
|
// this is comment, should skip
|
||||||
|
import time
|
||||||
|
// this is comment, should skip
|
||||||
|
}
|
||||||
|
// this is comment, should skip
|
||||||
|
|
||||||
|
const t = $if amd64 { 1 } $else { 2 }
|
||||||
|
|
||||||
|
$if new_a_1 ? {
|
||||||
|
pub type Digits = u64
|
||||||
|
} $else $if new_a_2 ? {
|
||||||
|
pub type Digits = u32
|
||||||
|
} $else {
|
||||||
|
pub type Digits = u8
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_b_1 ? {
|
||||||
|
pub const const1 = '123'
|
||||||
|
} $else $if new_b_2 ? {
|
||||||
|
pub const const1 = 123
|
||||||
|
} $else {
|
||||||
|
pub const const1 = 1.1
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_c_1 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_a
|
||||||
|
enum1_b
|
||||||
|
}
|
||||||
|
} $else $if new_c_2 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_c
|
||||||
|
enum1_d
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_e
|
||||||
|
enum1_f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_d_1 ? {
|
||||||
|
pub struct Struct1 {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
} $else $if new_d_2 ? {
|
||||||
|
pub struct Struct1 {
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub struct Struct1 {
|
||||||
|
c int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_e_1 ? {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_1'
|
||||||
|
}
|
||||||
|
} $else $if new_e_2 ? {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_2'
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
assert os.user_os().len > 0
|
||||||
|
assert t in [1, 2]
|
||||||
|
assert sizeof(Digits) == 8 // Digits == u64
|
||||||
|
assert const1 == '123'
|
||||||
|
_ := Enum1.enum1_a // should compile
|
||||||
|
_ := Struct1{
|
||||||
|
a: 123
|
||||||
|
} // should compile
|
||||||
|
assert ret() == 'new_e_1'
|
||||||
|
}
|
94
vlib/v/tests/comptime/comptime_if_top_2_test.v
Normal file
94
vlib/v/tests/comptime/comptime_if_top_2_test.v
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// vtest vflags: -d new_2 -d new_a_2 -d new_b_2 -d new_c_2 -d new_d_2 -d new_e_2
|
||||||
|
module main
|
||||||
|
|
||||||
|
// this is comment, should skip
|
||||||
|
|
||||||
|
$if new_1 ? {
|
||||||
|
// this is comment, should skip
|
||||||
|
import os
|
||||||
|
// this is comment, should skip
|
||||||
|
} $else $if new_2 ? {
|
||||||
|
// this is comment, should skip
|
||||||
|
import math
|
||||||
|
// this is comment, should skip
|
||||||
|
} $else {
|
||||||
|
// this is comment, should skip
|
||||||
|
import time
|
||||||
|
// this is comment, should skip
|
||||||
|
}
|
||||||
|
// this is comment, should skip
|
||||||
|
|
||||||
|
const t = $if amd64 { 1 } $else { 2 }
|
||||||
|
|
||||||
|
$if new_a_1 ? {
|
||||||
|
pub type Digits = u64
|
||||||
|
} $else $if new_a_2 ? {
|
||||||
|
pub type Digits = u32
|
||||||
|
} $else {
|
||||||
|
pub type Digits = u8
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_b_1 ? {
|
||||||
|
pub const const1 = '123'
|
||||||
|
} $else $if new_b_2 ? {
|
||||||
|
pub const const1 = 123
|
||||||
|
} $else {
|
||||||
|
pub const const1 = 1.1
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_c_1 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_a
|
||||||
|
enum1_b
|
||||||
|
}
|
||||||
|
} $else $if new_c_2 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_c
|
||||||
|
enum1_d
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_e
|
||||||
|
enum1_f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_d_1 ? {
|
||||||
|
pub struct Struct1 {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
} $else $if new_d_2 ? {
|
||||||
|
pub struct Struct1 {
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub struct Struct1 {
|
||||||
|
c int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_e_1 ? {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_1'
|
||||||
|
}
|
||||||
|
} $else $if new_e_2 ? {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_2'
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
assert math.max(1, 2) == 2
|
||||||
|
assert t in [1, 2]
|
||||||
|
assert sizeof(Digits) == 4 // Digits == u32
|
||||||
|
assert const1 == 123
|
||||||
|
_ := Enum1.enum1_d // should compile
|
||||||
|
_ := Struct1{
|
||||||
|
b: 123
|
||||||
|
} // should compile
|
||||||
|
assert ret() == 'new_e_2'
|
||||||
|
}
|
94
vlib/v/tests/comptime/comptime_if_top_3_test.v
Normal file
94
vlib/v/tests/comptime/comptime_if_top_3_test.v
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// vtest vflags: -d new_3 -d new_a_3 -d new_b_3 -d new_c_3 -d new_d_3 -d new_e_3
|
||||||
|
module main
|
||||||
|
|
||||||
|
// this is comment, should skip
|
||||||
|
|
||||||
|
$if new_1 ? {
|
||||||
|
// this is comment, should skip
|
||||||
|
import os
|
||||||
|
// this is comment, should skip
|
||||||
|
} $else $if new_2 ? {
|
||||||
|
// this is comment, should skip
|
||||||
|
import math
|
||||||
|
// this is comment, should skip
|
||||||
|
} $else {
|
||||||
|
// this is comment, should skip
|
||||||
|
import time
|
||||||
|
// this is comment, should skip
|
||||||
|
}
|
||||||
|
// this is comment, should skip
|
||||||
|
|
||||||
|
const t = $if amd64 { 1 } $else { 2 }
|
||||||
|
|
||||||
|
$if new_a_1 ? {
|
||||||
|
pub type Digits = u64
|
||||||
|
} $else $if new_a_2 ? {
|
||||||
|
pub type Digits = u32
|
||||||
|
} $else {
|
||||||
|
pub type Digits = u8
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_b_1 ? {
|
||||||
|
pub const const1 = '123'
|
||||||
|
} $else $if new_b_2 ? {
|
||||||
|
pub const const1 = 123
|
||||||
|
} $else {
|
||||||
|
pub const const1 = 1.1
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_c_1 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_a
|
||||||
|
enum1_b
|
||||||
|
}
|
||||||
|
} $else $if new_c_2 ? {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_c
|
||||||
|
enum1_d
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub enum Enum1 {
|
||||||
|
enum1_e
|
||||||
|
enum1_f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_d_1 ? {
|
||||||
|
pub struct Struct1 {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
} $else $if new_d_2 ? {
|
||||||
|
pub struct Struct1 {
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub struct Struct1 {
|
||||||
|
c int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if new_e_1 ? {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_1'
|
||||||
|
}
|
||||||
|
} $else $if new_e_2 ? {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_2'
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
pub fn ret() string {
|
||||||
|
return 'new_e_3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
assert time.days_in_year == 365
|
||||||
|
assert t in [1, 2]
|
||||||
|
assert sizeof(Digits) == 1 // Digits == u8
|
||||||
|
assert const1 == 1.1
|
||||||
|
_ := Enum1.enum1_e // should compile
|
||||||
|
_ := Struct1{
|
||||||
|
c: 123
|
||||||
|
} // should compile
|
||||||
|
assert ret() == 'new_e_3'
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue